diff --git a/README.md b/README.md index 974c9f6..68ce041 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,19 @@
  • 下载本项目最新的源码或 Releases 发布的源码至本地
  • 运行 main.py 即可使用
  • +

    🕹 用户脚本

    +

    如果您的浏览器安装了 Tampermonkey 浏览器扩展程序,可以添加 用户脚本,无需下载即可体验!

    +

    使用 XHS-Downloader 用户脚本批量获取作品链接,搭配 XHS-Downloader 程序可以实现批量下载无水印作品文件!

    +

    脚本功能

    + +

    脚本截图

    +

    💻 二次开发

    如果有其他需求,可以根据 main.py 的注释提示进行代码调用或修改!

    @@ -193,9 +206,6 @@ async with XHS(work_path=work_path,
     
     
    -

    🕹 用户脚本

    -

    如果您的浏览器安装了 Tampermonkey 浏览器扩展程序,可以 点击获取 用户脚本,无需下载即可体验!

    -

    可以使用 XHS-Downloader 用户脚本批量获取账号作品链接,搭配 XHS-Downloader 程序实现批量下载账号作品文件!

    ♥️ 支持项目

    如果 XHS-Downloader 对您有帮助,请考虑为它点个 Star ⭐,感谢您的支持!

    diff --git a/source/TUI/__init__.py b/source/TUI/__init__.py index e91bd0f..7aed1a2 100644 --- a/source/TUI/__init__.py +++ b/source/TUI/__init__.py @@ -1,3 +1,3 @@ -from .index import XHSDownloader +from .app import XHSDownloader __all__ = ['XHSDownloader'] diff --git a/source/TUI/app.py b/source/TUI/app.py new file mode 100644 index 0000000..d3d28ff --- /dev/null +++ b/source/TUI/app.py @@ -0,0 +1,37 @@ +from textual.app import App + +from source.application import XHS +from source.module import ( + ROOT, +) +from source.module import Settings +from source.translator import Chinese +from source.translator import LANGUAGE +from .index import Index +from .setting import Setting + +__all__ = ["XHSDownloader"] + + +class XHSDownloader(App): + def __init__(self): + super().__init__() + self.settings = Settings(ROOT) + self.parameter = self.settings.run() + self.prompt = LANGUAGE.get(self.parameter["language"], Chinese) + self.APP = XHS(**self.parameter, language_object=self.prompt) + + async def __aenter__(self): + await self.APP.__aenter__() + return self + + async def __aexit__(self, exc_type, exc_value, traceback): + await self.APP.__aexit__(exc_type, exc_value, traceback) + + async def on_mount(self) -> None: + self.install_screen(Setting(), name="setting") + self.install_screen(Index(self.APP, self.prompt), name="index") + await self.push_screen("index") + + async def action_settings(self): + await self.push_screen("setting") diff --git a/source/TUI/index.py b/source/TUI/index.py index 3a76075..6424676 100644 --- a/source/TUI/index.py +++ b/source/TUI/index.py @@ -1,13 +1,15 @@ from webbrowser import open +# from asyncio import sleep from pyperclip import paste from rich.text import Text -from textual.app import App +from textual import on from textual.app import ComposeResult from textual.binding import Binding from textual.containers import Center from textual.containers import HorizontalScroll from textual.containers import ScrollableContainer +from textual.screen import Screen from textual.widgets import Button from textual.widgets import Footer from textual.widgets import Header @@ -17,12 +19,11 @@ from textual.widgets import ProgressBar from textual.widgets import RichLog from source.application import XHS -from source.module import Settings +from source.module import ROOT from source.module import ( VERSION_MAJOR, VERSION_MINOR, VERSION_BETA, - ROOT, PROMPT, MASTER, ERROR, @@ -34,11 +35,9 @@ from source.module import ( GENERAL, USERSCRIPT, ) -from source.translator import Chinese -from source.translator import LANGUAGE -from .setting import Setting +from source.translator import (English, Chinese) -__all__ = ["XHSDownloader"] +__all__ = ["Index"] def show_state(function): @@ -53,7 +52,7 @@ def show_state(function): return inner -class XHSDownloader(App): +class Index(Screen): CSS_PATH = ROOT.joinpath( "static/css/index.tcss") BINDINGS = [ @@ -61,28 +60,18 @@ class XHSDownloader(App): # ("d", "toggle_dark", "切换主题"), Binding(key="u", action="check_update", description="检查更新"), Binding(key="m", action="user_script", description="获取脚本"), - # Binding(key="l", action="choose_language", description="切换语言"), - # Binding(key="s", action="settings", description="程序设置"), + Binding(key="s", action="settings", description="程序设置"), ] - def __init__(self): + def __init__(self, app: XHS, language: Chinese | English): super().__init__() - settings = Settings(ROOT).run() - self.prompt = LANGUAGE.get(settings["language"], Chinese) - self.APP = XHS(**settings, language_object=self.prompt) + self.app_ = app + self.prompt = language self.url = None self.tip = None self.bar = None - self.setting = None self.disclaimer = True - async def __aenter__(self): - await self.APP.__aenter__() - return self - - async def __aexit__(self, exc_type, exc_value, traceback): - await self.APP.__aexit__(exc_type, exc_value, traceback) - def compose(self) -> ComposeResult: yield Header() yield ScrollableContainer(Label(Text(f"{self.prompt.open_source_protocol}{LICENCE}", style=MASTER)), @@ -96,7 +85,6 @@ class XHSDownloader(App): HorizontalScroll(Button(self.prompt.download_button, id="deal"), Button(self.prompt.paste_button, id="paste"), Button(self.prompt.reset_button, id="reset"), ), - id="index", ) with Center(): yield ProgressBar(total=None, show_percentage=False, show_eta=False) @@ -106,8 +94,6 @@ class XHSDownloader(App): def on_mount(self) -> None: self.title = f"XHS-Downloader V{VERSION_MAJOR}.{ VERSION_MINOR}{" Beta" if VERSION_BETA else ""}" - - def on_ready(self) -> None: self.url = self.query_one(Input) self.tip = self.query_one(RichLog) self.bar = self.query_one(ProgressBar) @@ -118,20 +104,26 @@ class XHSDownloader(App): self.tip.clear() self.disclaimer = False - async def on_button_pressed(self, event: Button.Pressed) -> None: - if event.button.id == "deal": - await self.deal() - elif event.button.id == "reset": - self.query_one(Input).value = "" - elif event.button.id == "paste": - self.query_one(Input).value = paste() + @on(Button.Pressed, "#deal") + async def deal_button(self): + await self.deal() + + @on(Button.Pressed, "#reset") + def reset_button(self): + self.query_one(Input).value = "" + + @on(Button.Pressed, "#paste") + def paste_button(self): + self.query_one(Input).value = paste() @show_state async def deal(self): + # TODO: 处理过程中,进度条异常卡顿,待排查! + # await sleep(2) if not self.url.value: self.tip.write(Text(self.prompt.invalid_link, style=WARNING)) return - if any(await self.APP.extract(self.url.value, True, log=self.tip)): + if any(await self.app_.extract(self.url.value, True, log=self.tip)): self.url.value = "" else: self.tip.write(Text(self.prompt.download_failure, style=ERROR)) @@ -143,7 +135,7 @@ class XHSDownloader(App): self.prompt.check_update_notification, style=WARNING)) try: - url = await self.APP.html.request_url(RELEASES, False, self.tip) + url = await self.app_.html.request_url(RELEASES, False, self.tip) latest_major, latest_minor = map( int, url.split("/")[-1].split(".", 1)) if latest_major > VERSION_MAJOR or latest_minor > VERSION_MINOR: @@ -176,14 +168,3 @@ class XHSDownloader(App): @staticmethod def action_user_script(): open(USERSCRIPT) - - def action_choose_language(self): - pass - - def action_settings(self): - if self.setting: - self.setting.remove() - self.setting = None - else: - self.setting = Setting() - self.query_one("#index").mount(self.setting) diff --git a/source/TUI/server.py b/source/TUI/server.py new file mode 100644 index 0000000..e69de29 diff --git a/source/TUI/setting.py b/source/TUI/setting.py index 83e8b7d..ffbc064 100644 --- a/source/TUI/setting.py +++ b/source/TUI/setting.py @@ -1,16 +1,23 @@ from textual.app import ComposeResult +from textual.binding import Binding +from textual.screen import Screen +from textual.widgets import Footer +from textual.widgets import Header from textual.widgets import Label -from textual.widgets import Static from source.module import ROOT __all__ = ["Setting"] -class Setting(Static): +class Setting(Screen): CSS_PATH = ROOT.joinpath( "static/css/setting.tcss") + BINDINGS = [ + Binding(key="q", action="quit", description="退出程序"), + ] def compose(self) -> ComposeResult: - """Create child widgets for the app.""" + yield Header() yield Label("我是设置页") + yield Footer() diff --git a/source/application/Downloader.py b/source/application/Downloader.py index dfadfbb..01ac379 100644 --- a/source/application/Downloader.py +++ b/source/application/Downloader.py @@ -68,7 +68,7 @@ class Download: except ClientError as error: self.manager.delete(temp) # self.__create_progress(bar, None) - logging(log, error, ERROR) + logging(log, str(error), ERROR) logging(log, self.prompt.download_error(name), ERROR) return False diff --git a/source/application/Html.py b/source/application/Html.py index 2f77e70..e99829b 100644 --- a/source/application/Html.py +++ b/source/application/Html.py @@ -29,7 +29,7 @@ class Html: ) as response: return await response.text() if content else str(response.url) except ClientError as error: - logging(log, error, ERROR) + logging(log, str(error), ERROR) logging(log, self.prompt.request_error(url), ERROR) return "" diff --git a/static/用户脚本截图.png b/static/用户脚本截图.png new file mode 100644 index 0000000..3654c5e Binary files /dev/null and b/static/用户脚本截图.png differ