"""守护进程模式 定期检查订阅漫画的更新,下载新章节并可选推送到设备。 """ import asyncio from datetime import datetime from pathlib import Path from kobo_manga.config import AppConfig from kobo_manga.db.database import Database from kobo_manga.db.queries import list_subscriptions from kobo_manga.pipeline import MangaPipeline from kobo_manga.transfer import get_transfer class UpdateScheduler: """订阅更新调度器。""" def __init__(self, config: AppConfig, db: Database): self.config = config self.db = db self.running = False async def run_once(self) -> dict: """执行一轮更新检查。 Returns: {checked, new_chapters, errors, kepubs} """ pipeline = MangaPipeline(self.config, self.db) subs = list_subscriptions(self.db) results: dict = { "checked": 0, "new_chapters": 0, "errors": 0, "kepubs": [], } for sub in subs: title = sub.get("title", sub["manga_id"]) print(f"\n 检查: {title}") try: kepubs = await pipeline.check_and_download_updates( sub["manga_id"], sub["source"] ) results["checked"] += 1 results["new_chapters"] += len(kepubs) results["kepubs"].extend(kepubs) # 自动推送 if kepubs and ( sub["auto_push"] or self.config.scheduler.auto_push ): self._push(kepubs) except Exception as e: results["errors"] += 1 print(f" [!] {title}: {e}") return results async def run_forever(self): """守护循环:定期执行 run_once。Ctrl+C 退出。""" self.running = True interval = self.config.scheduler.interval while self.running: now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") print(f"\n[{now}] 开始检查订阅更新...") results = await self.run_once() print( f"\n 检查 {results['checked']} 个订阅," f"{results['new_chapters']} 个新章节," f"{results['errors']} 个错误" ) if self.running: next_time = datetime.now().timestamp() + interval next_str = datetime.fromtimestamp(next_time).strftime( "%H:%M:%S" ) print(f" 下次检查: {next_str}") try: await asyncio.sleep(interval) except asyncio.CancelledError: break def _push(self, kepubs: list[Path]): """推送新章节到设备。""" try: transfer = get_transfer(self.config.transfer) dest_paths = transfer.transfer(kepubs) print(f" [OK] 推送 {len(dest_paths)} 个文件") except Exception as e: print(f" [!] 推送失败: {e}")