From 52d28f42d2427b3c3aa87c8e334f11123ef31da6 Mon Sep 17 00:00:00 2001 From: cxykevin Date: Fri, 3 May 2024 09:08:46 +0800 Subject: [PATCH] =?UTF-8?q?origin=20commit(=E5=AE=8C=E6=88=90installer)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 107 ++++++++++++++ .vscode/launch.json | 15 ++ .vscode/settings.json | 4 + lang/zh_cn.toml | 21 +++ lib/downloader.py | 64 +++++++++ lib/get_disk.py | 112 +++++++++++++++ lib/install_pkg.py | 60 ++++++++ lib/open_ventoy.py | 11 ++ logger/config.py | 3 + logger/logger.py | 55 ++++++++ main.py | 3 + res/icon.pack | Bin 0 -> 75215 bytes res/installer_file.json | 10 ++ ui/installer.py | 299 ++++++++++++++++++++++++++++++++++++++++ ui/lang.py | 15 ++ ui/nav.py | 61 ++++++++ ui/win.py | 53 +++++++ 17 files changed, 893 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 lang/zh_cn.toml create mode 100644 lib/downloader.py create mode 100644 lib/get_disk.py create mode 100644 lib/install_pkg.py create mode 100644 lib/open_ventoy.py create mode 100644 logger/config.py create mode 100644 logger/logger.py create mode 100644 main.py create mode 100644 res/icon.pack create mode 100644 res/installer_file.json create mode 100644 ui/installer.py create mode 100644 ui/lang.py create mode 100644 ui/nav.py create mode 100644 ui/win.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..29bf417 --- /dev/null +++ b/.gitignore @@ -0,0 +1,107 @@ +# download files +debug_utils +software + +################# python config ################## +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version +.idea/ +# celery beat schedule file +celerybeat-schedule +workspace.xml +# SageMath parsed files +*.sage.py +.idea/workspace.xml +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6646939 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,15 @@ +{ + // 使用 IntelliSense 了解相关属性。 + // 悬停以查看现有属性的描述。 + // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "Python 调试", + "type": "debugpy", + "request": "launch", + "program": "main.py", + "console": "integratedTerminal" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..242c7c8 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "python.analysis.typeCheckingMode": "off", + "python.analysis.autoImportCompletions": true +} \ No newline at end of file diff --git a/lang/zh_cn.toml b/lang/zh_cn.toml new file mode 100644 index 0000000..aba61bd --- /dev/null +++ b/lang/zh_cn.toml @@ -0,0 +1,21 @@ +UnsupportedSystem = "当前操作系统不受支持" +PermissionDeniedLinux = "在 linux 操作系统系统下,请使用 root 权限进行安装" +PermissionDeniedWin = "权限不足,请以管理员身份运行此程序" +InstallWelcome = "欢迎安装 PEInjector" +InstallInfo = "PEinjector 是增强 WindowsPE 的一个工具和平台" +DownloadInstallTitle = "下载必要文件" +DownloadInstall = "在开始之前,我们需要下载一些依赖文件\n如果您的网络状况不佳,请手动下载 peinjector 和 ventoy 并解压到 software 文件夹" +StartInstall = "开始安装" +InstallVtoy = "安装 Ventoy" +InstallVtoyTitle = "安装 Ventoy" +InstallVtoyInfo = "请在打开的 ventoy 安装程序手动完成安装\n若安装完毕,请点击 “扫描” 按钮并选择您安装完毕的U盘\n若您找不到您的U盘,请尝试点击 “显示所有设备”\n如果你在使用 arm 架构的设备或软件无法打开,请手动运行以下程序:\n Windows: software\\ventoy\\altexe\\你的架构对应程序.exe\n Linux: software/ventoy/altexe/你的架构对应程序\n注:请确保磁盘已经挂载。本版本ventoy已精简,与原版兼容" +ScanVtoy = "扫描" +RestartVtoy = "重启安装程序" +ChooseVtoyDevice = "选择设备" +ShowAllDevices = "显示所有设备" +InstallIjTitle = "安装 PEinjector" +InstallIjInfo = "PEinjector主程序正在安装中,请稍等" +FinishInstall = "完成安装" +InstallFinishTitle = "安装已完成" +InstallFinishInfo = "PEinjector已经安装到您的设备\n点击下方按钮关闭程序并重新启动以管理 PEinjector" +InstallFinishBtn = "关闭" diff --git a/lib/downloader.py b/lib/downloader.py new file mode 100644 index 0000000..653607b --- /dev/null +++ b/lib/downloader.py @@ -0,0 +1,64 @@ +import time +import os +import shutil +import requests +import py7zr +from threading import Thread +from logger.logger import * + +CHUNKSIZE = 1024 + + +class Download_Theard(Thread): + def __init__(self, url, to, progress_callback, onfinish): + self.url = url + self.to = to + self.progress_callback = progress_callback + self.onfinish = onfinish + Thread.__init__(self, daemon=True) + + def run(self): + while 1: + try: + info("[downloader]download "+self.url) + self.progress_callback(0) + r = requests.get(self.url, stream=True) + if (r.status_code >= 300): + raise Exception + total = int(r.headers.get('content-length', 0)) + now_file = 0 + with open(self.to, 'wb') as fp: + for item in r.iter_content(CHUNKSIZE): + fp.write(item) + now_file += len(item) + self.progress_callback(now_file/total*0.9) + self.progress_callback(0.9) + info("[downloader]unzip "+self.url) + with py7zr.SevenZipFile(self.to, mode='r') as z: + z.extractall(path="software") + self.progress_callback(1) + self.onfinish() + return + except: + pass + + +def download_files(files, onfisish, anim_list): + threads = [] + finishnum = 0 + finishmax = len(files) + + def anim_check(*args): + onfisish() # run in main thread + return -1 + + def progfinish(): + nonlocal finishnum, finishmax + finishnum += 1 + if (finishnum == finishmax): + anim_list.anim.append(anim_check) + + for i in files: + threads.append(Download_Theard( + i["from"], i["to"], i["progbar"], progfinish)) + threads[-1].start() diff --git a/lib/get_disk.py b/lib/get_disk.py new file mode 100644 index 0000000..bc8dab0 --- /dev/null +++ b/lib/get_disk.py @@ -0,0 +1,112 @@ +import platform +import os +import subprocess +import sys + +from ui.lang import l +from logger.logger import * + +if platform.system() == 'Linux': + def find_hub_disk(): + info("[getdisk]get hub disk") + output = subprocess.check_output( + ['mount', '-v']).decode(sys.getdefaultencoding()) + for line in output.split('\n'): + if not line: + continue + mount_point_l = line.split(" ") + disk_id = mount_point_l[0] + mount_to = mount_point_l[2] + if len(disk_id) <= len("/dev/sd") or (disk_id[:len("/dev/sd")] != "/dev/sd" and (disk_id[:len("/dev/sd")] != "/dev/lo") and (disk_id[:len("/dev/sd")] != "/dev/nv")): + continue + if (mount_to == "/" or mount_to == "/boot"): + continue + if (os.path.exists(mount_to + "/PEinjector")): + return (0, mount_to, disk_id) + return (2, "") + + def find_vtoy_disk(): + vtoylist = [] + info("[getdisk]get vtoy disk") + output = subprocess.check_output( + ['mount', '-v']).decode(sys.getdefaultencoding()) + for line in output.split('\n'): + if not line: + continue + mount_point_l = line.split(" ") + disk_id = mount_point_l[0] + mount_to = mount_point_l[2] + if len(disk_id) <= len("/dev/sd") or (disk_id[:len("/dev/sd")] != "/dev/sd" and (disk_id[:len("/dev/sd")] != "/dev/lo") and (disk_id[:len("/dev/sd")] != "/dev/nv")): + continue + if (mount_to == "/" or mount_to == "/boot"): + continue + if os.path.exists(mount_to + "/ventoy"): + vtoylist.append((disk_id, mount_to)) + continue + output2 = subprocess.check_output( + ['blkid', '-o', 'value', '-s', 'LABEL', disk_id]).decode(sys.getdefaultencoding()) + output2 = output2.replace('\n', "") + if (output2 == ""): + continue + if (output2 == "Ventoy" or output2 == "ventoy"): + vtoylist.append((disk_id, mount_to)) + return vtoylist + + def find_all_disk(): + vtoylist = [] + info("[getdisk]get all disk") + output = subprocess.check_output( + ['mount', '-v']).decode(sys.getdefaultencoding()) + for line in output.split('\n'): + if not line: + continue + mount_point_l = line.split(" ") + disk_id = mount_point_l[0] + mount_to = mount_point_l[2] + if len(disk_id) <= len("/dev/sd") or (disk_id[:len("/dev/sd")] != "/dev/sd" and (disk_id[:len("/dev/sd")] != "/dev/lo") and (disk_id[:len("/dev/sd")] != "/dev/nv")): + continue + if (mount_to == "/" or mount_to == "/boot"): + continue + vtoylist.append((disk_id, mount_to)) + return vtoylist +elif platform.system() == 'Windows': + def find_hub_disk(): + info("[getdisk]get hub disk") + for i in "CDEFGHIJKABLMNOPQRSTUVWYZ": + this_disk = i+":" + if os.path.exists(this_disk + "/PEinjector"): + return (0, this_disk, this_disk) + return (2, "") + + def find_vtoy_disk(): + vtoylist = [] + info("[getdisk]get vtoy disk") + for i in "CDEFGHIJKABLMNOPQRSTUVWYZ": + this_disk = i+":" + if not os.path.exists(this_disk): + continue + if os.path.exists(this_disk + "/ventoy"): + vtoylist.append((this_disk, this_disk)) + with os.popen("wmic logicaldisk" + + f" where name=\"{this_disk}\" get volumename", 'r', 1) as file: + output2 = file.read() + output2 = (output2.replace("\n", "") + .replace("VolumeName", "") + .lstrip() + .rstrip()) + if (output2 == "Ventoy"): + vtoylist.append((this_disk, this_disk)) + return vtoylist + + def find_all_disk(): + vtoylist = [] + info("[getdisk]get all disk") + for i in "CDEFGHIJKABLMNOPQRSTUVWYZ": + this_disk = i+":" + if (os.path.exists(this_disk)): + vtoylist.append((this_disk, this_disk)) + return vtoylist +else: + def find_hub_disk(): + info("[getdisk]get hub disk") + return (1, l("UnsupportedSystem")) diff --git a/lib/install_pkg.py b/lib/install_pkg.py new file mode 100644 index 0000000..c785497 --- /dev/null +++ b/lib/install_pkg.py @@ -0,0 +1,60 @@ +import time +import os +import shutil +from threading import Thread +from logger.logger import * + + +class PKG_Theard(Thread): + def __init__(self, disks, barcallback, donecallback): + self.disks = disks + self.barcallback = barcallback + self.donecallback = donecallback + Thread.__init__(self, daemon=True) + + def run(self): + DISK = self.disks + info(f"[install]install to {DISK}") + self.barcallback(0) + if not os.path.exists(DISK+"/PEinjector"): + os.mkdir(DISK+"/PEinjector") + time.sleep(0.1) + self.barcallback(0.1) + info("[install]install main file") + if os.path.exists(DISK+"/PEinjector/PEinjector.7z"): + os.remove(DISK+"/PEinjector/PEinjector.7z") + time.sleep(0.1) + self.barcallback(0.2) + shutil.copyfile("software/peinjector/dist/PEinjector.7z", + DISK+"/PEinjector/PEinjector.7z") + time.sleep(0.1) + self.barcallback(0.4) + time.sleep(0.1) + info("[install]write info") + if not os.path.exists(DISK+"/PEinjector/disable.txt"): + with open(DISK+"/PEinjector/disable.txt", "w") as file: + pass + self.barcallback(0.5) + time.sleep(0.1) + shutil.copyfile("software/peinjector/version", + DISK+"/PEinjector/VERSION") + if not os.path.exists(DISK+"/PEinjector/install"): + os.mkdir(DISK+"/PEinjector/install") + self.barcallback(0.6) + if not os.path.exists(DISK+"/PEinjector/package"): + os.mkdir(DISK+"/PEinjector/package") + ns = 0 + for i in os.listdir("software/peinjector/package"): + if os.path.exists(DISK+"/PEinjector/package/"+i): + shutil.rmtree(DISK+"/PEinjector/package/"+i) + shutil.copytree("software/peinjector/package/" + + i, DISK+"/PEinjector/package/"+i) + ns += 1 + info( + f"[install]install pkg {ns}/{len(os.listdir('software/peinjector/package'))}") + self.barcallback( + 0.6+ns/len(os.listdir("software/peinjector/package"))*0.4) + time.sleep(0.1) + info("[install]install finish") + self.barcallback(1) + self.donecallback() diff --git a/lib/open_ventoy.py b/lib/open_ventoy.py new file mode 100644 index 0000000..8af4db2 --- /dev/null +++ b/lib/open_ventoy.py @@ -0,0 +1,11 @@ +import os +import platform + + +def run(): + if (platform.system() == 'Linux'): + os.system("chmod +x ./software/ventoy/VentoyGUI.x86_64") + os.system( + "cd software/ventoy;./VentoyGUI.x86_64 2> ../../logger/vtoylog.log&") + if (platform.system() == 'Windows'): + os.system("cd software\\ventoy && start Ventoy2Disk.exe") diff --git a/logger/config.py b/logger/config.py new file mode 100644 index 0000000..b3f19c3 --- /dev/null +++ b/logger/config.py @@ -0,0 +1,3 @@ +LOGPATH = "logger/log.log" +LOGLEVEL = "debug" +OUTPUT_COLORFUL = True diff --git a/logger/logger.py b/logger/logger.py new file mode 100644 index 0000000..6ed14ba --- /dev/null +++ b/logger/logger.py @@ -0,0 +1,55 @@ +# ------ cxykevin log moudle ------ +# This moudle is not a part of this project. +# This file is CopyNone. + + +import logging +from logger import config +import sys +levels = { + "debug": logging.DEBUG, + 'info': logging.INFO, + 'warning': logging.WARN, + 'err': logging.ERROR +} + + +def init() -> None: + logging.basicConfig(filename=config.LOGPATH, + format='[%(asctime)s][%(levelname)s] %(message)s', + level=levels[config.LOGLEVEL]) + + +def info(msg: str) -> None: + if (20 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[34mINFO\033[0m]" if config.OUTPUT_COLORFUL else "[INFO]") + msg + "\n") + logging.info(msg) + + +def warn(msg: str) -> None: + if (30 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[33mWARNING\033[0m]" if config.OUTPUT_COLORFUL else "[WARNING]") + msg + "\n") + logging.warn(msg) + + +def err(msg: str) -> None: + if (40 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[31mERROR\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + "\n") + logging.error(msg) + + +def break_err(msg: str) -> None: + if (40 >= levels[config.LOGLEVEL]): + sys.stdout.write( + ("[\033[31mERROR\033[0m]" if config.OUTPUT_COLORFUL else "[ERROR]") + msg + "\n") + logging.error(msg) + + +def print(*args, end="\n") -> None: + msg = ' '.join(map(str, args)) + if (10 >= levels[config.LOGLEVEL]): + sys.stdout.write(msg + end) + logging.debug(msg) diff --git a/main.py b/main.py new file mode 100644 index 0000000..99a10d6 --- /dev/null +++ b/main.py @@ -0,0 +1,3 @@ +from ui import win +if __name__ == "__main__": + win.main() diff --git a/res/icon.pack b/res/icon.pack new file mode 100644 index 0000000000000000000000000000000000000000..bd01ce11ca1e51dd54ee7b4b42ef62bcb0809bac GIT binary patch literal 75215 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 CClnX} literal 0 HcmV?d00001 diff --git a/res/installer_file.json b/res/installer_file.json new file mode 100644 index 0000000..80ed0a5 --- /dev/null +++ b/res/installer_file.json @@ -0,0 +1,10 @@ +[ + { + "name": "peinjector", + "source": "http://git.hmtsai.cn/cxykevin/PEinjector_Hub_Files/raw/branch/master/peinjector.7z" + }, + { + "name": "ventoy", + "source": "http://git.hmtsai.cn/cxykevin/PEinjector_Hub_Files/raw/branch/master/ventoy.7z" + } +] \ No newline at end of file diff --git a/ui/installer.py b/ui/installer.py new file mode 100644 index 0000000..ff378dd --- /dev/null +++ b/ui/installer.py @@ -0,0 +1,299 @@ +import json +import os +from turtle import bgcolor +from magictk import mtk, color_tmpl +from magictk import fontconfig +from ui.lang import l +from lib import open_ventoy +from lib import get_disk +from lib import install_pkg +from lib import downloader +from logger.logger import * + +now_frame = None +master: mtk.Frame = None + + +def show_first_page(): + global now_frame, master + first_page = mtk.Frame(master,) + mtk.Frame(first_page, w=10000).pack(fill="both", expand=True) + mtk.Label(first_page, text=l("InstallWelcome"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(first_page, text="\n"+l("InstallInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(first_page, height=30).pack() + buttonlist = mtk.Frame(first_page) + + def install_callback(*args): + change_page_download() + + mtk.ButtonFill(buttonlist, text=l("StartInstall"), + w=110, color_type="primary", func=install_callback).pack(side="left") + mtk.Frame(buttonlist, height=10).pack(side="left") + buttonlist.pack() + mtk.Frame(first_page, w=10000).pack(fill="both", expand=True) + first_page.pack(fill="both", expand=True) + now_frame = first_page + + +def change_page_download(): + global now_frame, master + now_frame.pack_forget() + instvtoy_page = mtk.Frame(master,) + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + mtk.Label(instvtoy_page, text="0/3 "+l("DownloadInstallTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(instvtoy_page, text="\n"+l("DownloadInstall"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(instvtoy_page, height=30).pack() + + prog_frame = mtk.Frame(instvtoy_page) + with open("res/installer_file.json", 'r') as file: + files = json.load(file) + download_l = [] + if not (os.path.exists("software")): + os.mkdir("software") + if not (os.path.exists("software"+os.sep+"cache")): + os.mkdir("software"+os.sep+"cache") + funclst = [] + for i in files: + def runf(): + sframe = mtk.Frame(prog_frame, height=10) + progps = mtk.Label( + sframe, background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"], text=" 0%", width=6, font=(fontconfig.getfont(), 10)) + progps.pack(side="left") + progbar = mtk.ProgressBar(sframe, w=300) + progbar.pack(side="left", anchor='w') + proglabel = mtk.Label( + sframe, background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"], text=" "+i["name"], width=18, font=(fontconfig.getfont(), 10)) + proglabel.pack(side="left") + sframe.pack(side="top") + + def progcallback(prog): + progbar.set_progress(prog) + progstr = str(int(prog*100)) + outstr = " "*(3-len(progstr))+progstr+"%" + + def setproganim(*args): + progps.configure(text=outstr) + return -1 + prog_frame.root.anim.append(setproganim) + + funclst.append(progcallback) + download_l.append({ + "from": i["source"], + "to": "software"+os.sep+"cache"+os.sep+i["name"]+".7z", + "progbar": funclst[-1] + }) + runf() + + def nextpage_callback(*args): + change_page_installvtoy() + open_ventoy.run() + + buttonlist = mtk.Frame(instvtoy_page, height=30) + btns = mtk.ButtonFill(buttonlist, text=l("InstallVtoy"), + w=120, color_type="primary", func=nextpage_callback) + + def callbacks(): + btns.pack(side="left") + + downloader.download_files(download_l, callbacks, prog_frame.root) + prog_frame.pack(fill='x', anchor="center") + mtk.Frame(instvtoy_page, height=30).pack() + + buttonlist.pack() + + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + instvtoy_page.pack(fill="both", expand=True) + now_frame = instvtoy_page + + +def change_page_installvtoy(): + global now_frame, master + now_frame.pack_forget() + instvtoy_page = mtk.Frame(master,) + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + mtk.Label(instvtoy_page, text="1/3 "+l("InstallVtoyTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(instvtoy_page, text="\n"+l("InstallVtoyInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(instvtoy_page, height=30).pack() + buttonlist = mtk.Frame(instvtoy_page) + scan_obj_list = mtk.Frame(instvtoy_page, height=30) + added_list = False + selects = mtk.Select(scan_obj_list, text=l( + "ChooseVtoyDevice"), items=[], w=380) + devmenu = [] + + def finishvtoy_callback(*args): + if (selects.get() == -1): + return + info(f"[installer]choose disk info:{str(devmenu[selects.get()])}") + global devinfo + devinfo = devmenu[selects.get()] + change_page_installing() + + def install_callback(*args): + nonlocal added_list, selects, devmenu + + def show_all_dev(*args): + nonlocal devmenu + devmenu = get_disk.find_all_disk() + selects.change_menu([f"{i[0]} [{i[1]}]" for i in devmenu]) + + if (added_list == False): + mtk.ButtonLight(scan_obj_list, func=show_all_dev, text=l("ShowAllDevices"), w=100, color_type="info").pack( + side="left") + selects.pack(side="left") + mtk.Button(scan_obj_list, func=finishvtoy_callback, iconname="circle-check", iconsize=16, w=32).pack( + side="left") + added_list = True + devmenu = get_disk.find_vtoy_disk() + selects.change_menu([f"{i[0]} [{i[1]}]" for i in devmenu]) + + def restart_callback(*args): + open_ventoy.run() + + mtk.ButtonFill(buttonlist, text=l("ScanVtoy"), + w=80, color_type="primary", func=install_callback).pack(side="left") + mtk.ButtonLight(buttonlist, text=l("RestartVtoy"), + w=120, color_type="primary", func=restart_callback).pack(side="left") + mtk.Frame(buttonlist, height=10).pack(side="left") + buttonlist.pack() + scan_obj_list.pack() + mtk.Frame(instvtoy_page, w=10000).pack(fill="both", expand=True) + instvtoy_page.pack(fill="both", expand=True) + now_frame = instvtoy_page + + +def change_page_installing(): + global now_frame, master, devinfo + devpath = devinfo[1] + now_frame.pack_forget() + installinjector_page = mtk.Frame(master,) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + mtk.Label(installinjector_page, text="2/3 "+l("InstallIjTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(installinjector_page, text="\n"+l("InstallIjInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(installinjector_page, height=30).pack() + + prog_frame = mtk.Frame(installinjector_page, height=10) + progbar = mtk.ProgressBar(prog_frame, w=300) + progbar.pack() + prog_frame.pack(fill='x') + + def barcallback(prog): + progbar.set_progress(prog) + + finishbutton_frame = mtk.Frame(installinjector_page, height=30) + + def finishbtncallback(*args): + change_page_finish() + finishbtn = mtk.ButtonFill(finishbutton_frame, text=l( + "FinishInstall"), w=120, color_type="success", func=finishbtncallback) + + closeid = False + + def anim_pick(*args): + nonlocal closeid + if (closeid == True): + closeid = False + finishbtn.pack() + return -1 + prog_frame.root.anim.append(anim_pick) + + def finishcallback(): + nonlocal closeid + closeid = True + + finishbutton_frame.pack(fill="both", expand=True) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + installinjector_page.pack(fill="both", expand=True) + theards = install_pkg.PKG_Theard(devpath, barcallback, finishcallback) + theards.start() + now_frame = installinjector_page + + +def change_page_installing(): + global now_frame, master, devinfo + devpath = devinfo[1] + now_frame.pack_forget() + installinjector_page = mtk.Frame(master,) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + mtk.Label(installinjector_page, text="2/3 "+l("InstallIjTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(installinjector_page, text="\n"+l("InstallIjInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + mtk.Frame(installinjector_page, height=30).pack() + + prog_frame = mtk.Frame(installinjector_page, height=10) + progbar = mtk.ProgressBar(prog_frame, w=300) + progbar.pack() + prog_frame.pack(fill='x') + + def barcallback(prog): + progbar.set_progress(prog) + + finishbutton_frame = mtk.Frame(installinjector_page, height=30) + + def finishbtncallback(*args): + change_page_finish() + finishbtn = mtk.ButtonFill(finishbutton_frame, text=l( + "FinishInstall"), w=120, color_type="success", func=finishbtncallback) + + closeid = False + + def anim_pick(*args): + nonlocal closeid + if (closeid == True): + closeid = False + finishbtn.pack() + return -1 + prog_frame.root.anim.append(anim_pick) + + def finishcallback(): + nonlocal closeid + closeid = True + + mtk.Frame(installinjector_page, height=30).pack() + finishbutton_frame.pack(fill="both", expand=True) + mtk.Frame(installinjector_page, w=10000).pack(fill="both", expand=True) + installinjector_page.pack(fill="both", expand=True) + theards = install_pkg.PKG_Theard(devpath, barcallback, finishcallback) + theards.start() + now_frame = installinjector_page + + +def change_page_finish(): + global now_frame, master + now_frame.pack_forget() + finish_page = mtk.Frame(master,) + mtk.Frame(finish_page, w=10000).pack(fill="both", expand=True) + mtk.Label(finish_page, text="3/3 "+l("InstallFinishTitle"), + anchor='center', font=(fontconfig.getfont(), 22), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["primary_text"]).pack(fill='x') + mtk.Label(finish_page, text="\n"+l("InstallFinishInfo"), + anchor='center', font=(fontconfig.getfont(), 12), background=color_tmpl.default_color["background"], foreground=color_tmpl.default_color["secondary_text"]).pack(fill='x') + + def closecallback(*args): + info("close from installer") + finish_page.root.quit() + + btnframe = mtk.Frame(finish_page, height=30) + mtk.ButtonFill(finish_page, text=l( + "InstallFinishBtn"), func=closecallback, color_type="danger").pack() + btnframe.pack() + mtk.Frame(finish_page, height=30).pack() + mtk.Frame(finish_page, w=10000).pack(fill="both", expand=True) + finish_page.pack(fill="both", expand=True) + now_frame = finish_page + + +def installer_ui(root: mtk.Frame): + global master + install_root_frame = mtk.Frame(root) + master = install_root_frame + show_first_page() + install_root_frame.pack(fill="both", expand=True) diff --git a/ui/lang.py b/ui/lang.py new file mode 100644 index 0000000..b844a84 --- /dev/null +++ b/ui/lang.py @@ -0,0 +1,15 @@ +from logger.logger import * +import tomllib + +l_obj = {} + + +def load_lang(lang: str): + info(f"[lang]load lang: {lang}") + global l_obj + with open("lang/"+lang+".toml", "rb") as file: + l_obj = tomllib.load(file) + + +def l(strs): + return l_obj.get(strs, f"__{strs}__") diff --git a/ui/nav.py b/ui/nav.py new file mode 100644 index 0000000..d752ab8 --- /dev/null +++ b/ui/nav.py @@ -0,0 +1,61 @@ +from magictk import mtk, color_tmpl +from logger.logger import * + + +choose_id = 0 + + +def nav_callback(obj): + ids = obj.ids + side = navlists[ids]["side"] + global choose_id + if (choose_id == ids): + return + choose_id = ids + if (side == "top"): + nav_frame_now.place_forget() + nav_frame_now.place(x=0, y=50*ids, width=3, height=50, anchor='nw') + else: + nav_frame_now.place_forget() + nav_frame_now.place(x=0, rely=1, width=3, height=50, anchor='sw') + + +def pack_nav(master: mtk.Frame, root: mtk.Frame, navlist: list): + global nav_frame_now, btn_list, navlists, nav_main, btn_frame_list + navlists = navlist + nav_frame = mtk.Frame(master) + nav_frame_show = mtk.Frame(nav_frame, w=3) + nav_frame_now = mtk.Frame( + nav_frame_show, w=3, bg=color_tmpl.default_color["primary"]) + nav_frame_now.place(x=0, y=0, width=3, height=50) + nav_frame_show.pack(side="left", fill='y') + mtk.Frame(nav_frame, w=1).pack( + side="left", expand=True, fill='y') + nav_frame_main = mtk.Frame(nav_frame, w=50) + + btn_list = [] + btn_frame_list = [] + ids = 0 + for i in navlist: + icon = i["icon"] + frame = i["frame"] + side = i["side"] + btn_list.append(mtk.ButtonLight( + master=nav_frame_main, color_type="plain", iconname=icon, iconsize=32, w=50, h=50, func=nav_callback)) + btn_list[-1].ids = ids + btn_list[-1].pack(side=side) + btn_frame_list.append(frame) + ids += 1 + + nav_frame_main.pack(side="left", fill='both') + mtk.Frame(nav_frame, w=2).pack( + side="left", expand=True, fill='y') + mtk.Frame(nav_frame, w=1, bg=color_tmpl.default_color["border_light"]).pack( + side="left", expand=True, fill='y') + nav_frame.pack(side="left", expand=True, fill='y') + + nav_main = mtk.Frame( + master, w=1000) + btn_frame_list[0](nav_main) + + nav_main.pack(side="right", fill='both') diff --git a/ui/win.py b/ui/win.py new file mode 100644 index 0000000..72ddb0b --- /dev/null +++ b/ui/win.py @@ -0,0 +1,53 @@ +from tkinter import messagebox +from magictk import mtk +from logger.logger import * +from ui import nav +from ui import installer +from lib import get_disk +from ui.lang import load_lang, l +import sys +import getpass +import platform +import ctypes + +init() + +load_lang("zh_cn") # TODO:读取设置 + +disk_res = get_disk.find_hub_disk() +errno = disk_res[0] +root_disk = disk_res[1] +if (errno == 1): + messagebox.showerror("Injector Hub Error", root_disk) + sys.exit(1) +elif (errno == 2): + info("[win]cannot find installed disk") + if (platform.system() == "Linux" and getpass.getuser() != "root"): + messagebox.showerror("Injector Hub Error", l("PermissionDeniedLinux")) + sys.exit(1) + if (platform.system() == "Windows" and ctypes.windll.shell32.IsUserAnAdmin() == False): + messagebox.showerror("Injector Hub Error", l("PermissionDeniedWin")) + nav_list = [ + {"icon": "lightning", "frame": installer.installer_ui, "side": "top"} + ] +else: + info(f"[win]found installed disk \"{root_disk}\"") + nav_list = [ + {"icon": "home-filled", "frame": None, "side": "top"}, + {"icon": "dvd", "frame": None, "side": "top"}, + {"icon": "plugin", "frame": None, "side": "top"}, + {"icon": "setting", "frame": None, "side": "bottom"} + ] + +info("[win]init window") +mtk.load_icon_pack("res/icon.pack") +main_win = mtk.Tk(title="Injector Hub", w=1000, h=800) + +main_frame = mtk.Frame(main_win, w=10000) +nav.pack_nav(main_win, main_frame, nav_list) +main_frame.pack(side="left", fill="both", expand=True) + + +def main(): + info("[win]mainloop") + main_win.mainloop()