Skip to content

Commit f36de32

Browse files
committed
init: package related;
1 parent cefb277 commit f36de32

15 files changed

+420
-24
lines changed

README.md

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
<div align="center">
22
<h1 id="koishi">ComicViewer</h1>
3-
4-
![](https://img.shields.io/badge/Backend-Python3.12-green.svg?colorA=abcdef)
5-
![](https://img.shields.io/badge/Frontend-Vite+Vue3+elementPlus-blue.svg?colorA=abcdef)
6-
3+
<img src="https://img.shields.io/badge/Backend-Python3.12-green.svg?colorA=abcdef" alt="tag">
4+
<img src="https://img.shields.io/badge/Frontend-Vite+Vue3+elementPlus-blue.svg?colorA=abcdef" alt="tag">
75
</div>
86

97
超简单 fastapi + vue3 项目, pc本地下漫画(或任意图片目录)后用手机浏览器进行局域网阅读
108

119
## 预览
12-
![](https://images.cnblogs.com/cnblogs_com/jsoneri/2401311/o_240530080611_comic_viewer.png)
10+
![](https://github.com/jasoneri/comic_viewer/blob/master/doc/comic_viewer.jpg)
11+
12+
> 打包好的开箱即用版 → [点击前往下载页面](https://github.com/jasoneri/comic_viewer/releases),包名 `comic_viewer.7z`<br>
13+
> 内含另外的 `部署指南` ,无需看以下说明
1314
1415
## 准备
1516
### 版本
16-
> Python==3.12.3(实际3.8也行)<br>
17-
> node // newest
17+
+ Python==3.12.3(实际3.8也行)
18+
+ node // newest
1819
### backend
19-
> `backend/settings.yml`修改目录,把内容放进该目录内,示例如下
20+
`backend/conf.yml`修改目录,默认是`D:\Comic`, 把漫画放进该目录内,示例如下
2021
```shell
2122
yourComicPath
2223
└── GrandBlue碧蓝之海_第62话
@@ -30,8 +31,7 @@ python -m pip install -r requirements.txt
3031
```
3132

3233
### frontend
33-
> 默认端口为8080,配置在frontend/vite.config.js
34-
34+
默认端口为8080,配置在frontend/vite.config.js
3535
```shell
3636
cd frontend
3737
npm i
@@ -48,7 +48,6 @@ npm start
4848
手机进浏览器照样填地址即可,如预览所示
4949

5050
## 交流
51-
5251
群 437774506
5352

5453
## 免责声明

backend/app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import pathlib
22
import uvicorn
3+
import sys
4+
sys.path.append(str(pathlib.Path(__file__).parent.absolute()))
35
from api import create_app
46

57
app = create_app()

backend/requirements.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,25 @@
66
#
77
annotated-types==0.7.0 # via pydantic
88
anyio==4.4.0 # via starlette
9+
brotli==1.1.0 # via py7zr
910
click==8.1.7 # via uvicorn
1011
colorama==0.4.6 # via click
1112
fastapi==0.112.0 # via -r requirements-in.txt
1213
h11==0.14.0 # via uvicorn
1314
idna==3.7 # via anyio
15+
inflate64==1.0.0 # via py7zr
16+
multivolumefile==0.2.3 # via py7zr
17+
psutil==6.0.0 # via py7zr
18+
py7zr==0.22.0 # via -r requirements-in.txt
19+
pybcj==1.0.2 # via py7zr
20+
pycryptodomex==3.20.0 # via py7zr
1421
pydantic==2.8.2 # via -r requirements-in.txt, fastapi
1522
pydantic-core==2.20.1 # via pydantic
23+
pyppmd==1.1.0 # via py7zr
1624
pyyaml==6.0.2 # via -r requirements-in.txt
25+
pyzstd==0.16.1 # via py7zr
1726
sniffio==1.3.1 # via anyio
1827
starlette==0.37.2 # via -r requirements-in.txt, fastapi
28+
texttable==1.7.0 # via py7zr
1929
typing-extensions==4.12.2 # via fastapi, pydantic, pydantic-core
2030
uvicorn==0.30.5 # via -r requirements-in.txt

deploy/init.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
import os
4+
import pathlib
5+
import shutil
6+
import py7zr
7+
from colorama import init, Fore
8+
9+
init(autoreset=True)
10+
11+
12+
if __name__ == '__main__':
13+
"""初次使用时,将预设极限压缩过的node依赖包解压至frontend"""
14+
root = pathlib.Path(__file__).parent.parent.parent
15+
scripts_p = root.joinpath('scripts')
16+
pkg = "node_modules"
17+
pkg_zip = f"{pkg}.7z"
18+
npm_pkg = root.joinpath(f"runtime/{pkg_zip}")
19+
if npm_pkg.exists():
20+
print(Fore.YELLOW + "[ 首次使用,初始化环境中.. ]")
21+
npm_pkg_p = scripts_p.joinpath(f'frontend/{pkg}')
22+
npm_pkg_p.mkdir(exist_ok=True)
23+
new_npm_pkg = scripts_p.joinpath(f'frontend/{pkg_zip}')
24+
shutil.move(npm_pkg, new_npm_pkg)
25+
with py7zr.SevenZipFile(new_npm_pkg, 'r') as zip_f:
26+
zip_f.extractall(npm_pkg_p)
27+
os.remove(new_npm_pkg)
28+
print(Fore.CYAN + "[ 初始化完成 ]")

deploy/packer.py

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
"""code packer
4+
env-python: developer
5+
"""
6+
import os
7+
import shutil
8+
import pathlib
9+
import stat
10+
import datetime
11+
12+
import py7zr
13+
14+
from tqdm import tqdm
15+
from loguru import logger
16+
from github import Github, Auth
17+
18+
# import github.Requester # REMARK(2024-08-08): modified in package: HTTPSRequestsConnectionClass.session.proxies
19+
20+
21+
path = pathlib.Path(__file__).parent
22+
api_github = "https://api.github.com"
23+
github_token = "**create token by your github account**"
24+
proxies = None
25+
headers = {
26+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:128.0) Gecko/20100101 Firefox/128.0",
27+
"Accept": "*/*",
28+
"Accept-Language": "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2",
29+
"Accept-Encoding": "gzip, deflate, br, zstd",
30+
"Origin": "https://github.com",
31+
"Connection": "keep-alive",
32+
"Referer": "https://github.com/",
33+
"Priority": "u=0",
34+
"Pragma": "no-cache",
35+
"Cache-Control": "no-cache",
36+
"TE": "trailers"
37+
}
38+
preset = {
39+
"python": ["api-ms-win-core", "base_library.zip", ".tcl", "tclIndex", "MSVCP140.dll", "cacert.pem", "cp936.enc",
40+
"__init__", "python.exe", "pythonw.exe", "VCRUNTIME140_1.dll"],
41+
"matplotlib": ["matplotlibrc", ".load-order", "matplotlib.svg"], "request": ["msgcat-1.6.1.tm"],
42+
"plotly": ["plotly.json", "plotly.min.js", "package_data\\templates"], "pyecharts": ["pyecharts"],
43+
"pyqtwebengine": ["QtWebEngineProcess.exe", "icudtl.dat", "qtwebengine_devtools_resources.pak",
44+
"qtwebengine_resources", "qt.conf"], "streamlit": ["streamlit\\static"],
45+
"trame_vtk": ["static_viewer.html"], "python-docx": ["docx\\templates"], "python-pptx": ["pptx\\templates"],
46+
"scrapy": ["mime.types"]}
47+
release_desc = """开箱即用
48+
---
49+
解压双击运行 `comic_viewer.exe`
50+
51+
下载很慢 ?到压缩包的下载链接右键复制到 https://github.akams.cn/ 上进行下载加速
52+
53+
一般情况下,使用包内的更新程序 `comic_viewer-更新.exe` 即可<br>
54+
特殊情况,如运行环境需要变化时,需要在此页面下绿色安装包 (包更新未必是最新,更新日期参照标题)
55+
> 绿色包保证 `运行环境` 的更新,更新程序保证 `代码` 的更新,<br>
56+
> 所以会有包更新没跟上代码更新,优先以内置的`comic_viewer-更新.exe` 为主
57+
58+
---
59+
其他问题 [回到项目主页](https://github.com/jasoneri/comic_viewer) 下方找群进群询问"""
60+
61+
62+
class Proj:
63+
proj = "comic_viewer"
64+
name = "comic_viewer"
65+
66+
def __repr__(self):
67+
return self.proj
68+
69+
70+
proj = Proj()
71+
72+
73+
class Clean:
74+
"""aim at runtime like site-packages"""
75+
76+
@staticmethod
77+
def clean_packages():
78+
"""clean site-packages"""
79+
package_p = path.joinpath('site-packages')
80+
for p in tqdm(package_p.glob("[psw][ieh][pte]*")): # pip, set-tools, wheel, not need
81+
shutil.rmtree(str(p), ignore_errors=True)
82+
83+
@staticmethod
84+
def end_work(specified: iter = None):
85+
def delete(func, _path, execinfo):
86+
os.chmod(_path, stat.S_IWUSR)
87+
func(_path)
88+
89+
waiting = specified or ("scripts/.git", )
90+
for p in tqdm(waiting):
91+
_p = path.joinpath(p)
92+
if _p.exists():
93+
shutil.rmtree(_p, onerror=delete) if _p.is_dir() else os.remove(_p)
94+
95+
96+
class Packer:
97+
github_author = "jasoneri"
98+
executor = path.parent.joinpath(r'Bat_To_Exe_Converter\Bat_To_Exe_Converter.exe')
99+
zip_file = path.joinpath(f'{proj}.7z')
100+
preset_zip_file = path.joinpath(f'{proj}_preset.7z')
101+
102+
def __init__(self, default_specified: tuple):
103+
self.default_specified = default_specified
104+
105+
@classmethod
106+
def bat_to_exe(cls):
107+
def _do(bat_file, exe_file, icon, *args):
108+
args_str = " ".join(args)
109+
command = f"cd {path} && {cls.executor} /bat {bat_file} /exe {exe_file} /icon {icon} /x64 {args_str}"
110+
error_code = os.system(command)
111+
if error_code: # Unreliable, need raise error make next step run correctly
112+
raise OSError(f"[ fail - packup {bat_file}], error_code: {error_code}")
113+
else:
114+
logger.info(f"[ success {bat_file} ]")
115+
116+
_do(path.joinpath(rf"scripts/launcher/{proj}.bat"), path.joinpath(rf"{proj}.exe"),
117+
path.joinpath(rf"scripts/launcher/{proj}.ico"), "/invisible")
118+
_do(path.joinpath(rf"scripts/launcher/update.bat"), path.joinpath(rf"{proj}-更新.exe"),
119+
path.joinpath(rf"scripts/launcher/{proj}.ico"))
120+
121+
@staticmethod
122+
def markdown_to_html(file_path, out_name):
123+
import markdown
124+
with open(path.joinpath(file_path), 'r', encoding='utf-8') as f:
125+
md_content = f.read()
126+
html = markdown.markdown(md_content)
127+
html_style = f"""<!DOCTYPE html><html><head><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/github-markdown-css/5.2.0/github-markdown.min.css"></head><body><article class="markdown-body">
128+
{html}
129+
</article></body></html>"""
130+
with open(path.joinpath(out_name), 'w', encoding='utf-8') as f:
131+
f.write(html_style)
132+
133+
def packup(self, runtime_init=False):
134+
zip_file = self.zip_file
135+
specified = self.default_specified
136+
mode = "a"
137+
if runtime_init:
138+
# {proj}_preset.7z: only include runtime and site-packages. If env changed, re-packup it
139+
if self.preset_zip_file.exists():
140+
logger.debug(f"[ preset_zip_file exists ] run normal packup")
141+
logger.debug(f"[ if need init ] delete '{self.preset_zip_file}' manually later")
142+
return self.packup()
143+
zip_file = self.preset_zip_file
144+
specified = ('runtime', 'site-packages')
145+
mode = "w"
146+
else:
147+
shutil.copy(self.preset_zip_file, self.zip_file)
148+
with py7zr.SevenZipFile(zip_file, mode, filters=[{"id": py7zr.FILTER_LZMA2}]) as zip_f:
149+
for file in tqdm(tuple(specified)):
150+
if path.joinpath(file).exists():
151+
zip_f.writeall(file)
152+
if not self.zip_file.exists():
153+
self.packup()
154+
155+
@staticmethod
156+
def upload(zip_file):
157+
date_now = datetime.datetime.now().strftime("%Y%m%d")
158+
repo = proj.name
159+
if github_token.startswith("**create"):
160+
raise ValueError("[ you forget to replace your github token ] ")
161+
auth = Auth.Token(github_token)
162+
g = Github(auth=auth)
163+
user = g.get_user()
164+
release = user.get_repo(repo).get_latest_release()
165+
# delete asset
166+
"""github note:
167+
If you upload an asset with the same filename as another uploaded asset,
168+
you'll receive an error and must delete the old file before you can re-upload the new asset."""
169+
_asset = list(filter(lambda x: x.name == zip_file, release.assets))
170+
if _asset:
171+
_asset[0].delete_asset()
172+
# upload asset
173+
release.upload_asset(str(path.joinpath(zip_file)), name=zip_file)
174+
# update release
175+
text = release_desc
176+
release.update_release(name=f"{date_now} - v1.0.0", message=text)
177+
178+
179+
def clean():
180+
"""almost run few times in upfront"""
181+
Clean.clean_packages()
182+
Clean.end_work()
183+
184+
185+
if __name__ == '__main__':
186+
# clean() # step 0
187+
Packer.bat_to_exe() # step 1
188+
Packer.markdown_to_html('scripts/doc/deploy.md', '部署指南.html') # step 2
189+
packer = Packer(('scripts', f'{proj}.exe', f'{proj}-更新.exe'))
190+
packer.packup(runtime_init=True) # step 3
191+
packer.upload('comic_viewer.7z') # step 4
192+
Clean.end_work((f'{proj}.exe', f'{proj}-更新.exe', 'comic_viewer.7z')) # step 5
193+
# If error occur, exegesis previous step and run again

0 commit comments

Comments
 (0)