~cytrogen/kobo-manga

ref: 4e504823f4bf8d2b5f4279da3f4d4ebe98fc97ad kobo-manga/src/kobo_manga/scheduler/daemon.py -rw-r--r-- 3.0 KiB
4e504823 — HallowDem Initial commit: kobo-manga pipeline a day ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"""守护进程模式

定期检查订阅漫画的更新,下载新章节并可选推送到设备。
"""

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}")