~cytrogen/kobo-manga

ref: 4e504823f4bf8d2b5f4279da3f4d4ebe98fc97ad kobo-manga/src/kobo_manga/sources/__init__.py -rw-r--r-- 2.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
"""漫画源注册表(插件化)

源适配器为插件,需用户自行实现并放置于 sources/ 目录下。
插件模块应继承 BaseSource 并在模块顶层调用 register_source() 注册。
启动时自动扫描 sources/ 下所有 .py 文件(排除 base.py)并尝试加载。
"""

import importlib
import logging
from pathlib import Path

from kobo_manga.sources.base import BaseSource

logger = logging.getLogger(__name__)

_registry: dict[str, type[BaseSource]] = {}


def register_source(cls: type[BaseSource]) -> type[BaseSource]:
    """注册源适配器类。"""
    _registry[cls.name] = cls
    return cls


def get_source(name: str) -> BaseSource:
    """按名字实例化源。"""
    _ensure_registered()
    if name not in _registry:
        available = ", ".join(_registry.keys()) or "(无已安装的源插件)"
        raise ValueError(f"未知源 '{name}',可用: {available}")
    return _registry[name]()


def list_sources() -> list[str]:
    """返回所有已注册的源名称。"""
    _ensure_registered()
    return list(_registry.keys())


def infer_source_from_url(url: str) -> str | None:
    """从 URL 推断源名称。"""
    _ensure_registered()
    for name, cls in _registry.items():
        if hasattr(cls, "URL_PATTERNS"):
            for pattern in cls.URL_PATTERNS:
                if pattern in url:
                    return name
    return None


_registered = False


def _ensure_registered():
    """自动扫描 sources/ 目录下的插件模块并注册。"""
    global _registered
    if _registered:
        return
    _registered = True

    sources_dir = Path(__file__).parent
    skip = {"__init__.py", "base.py"}

    for py_file in sorted(sources_dir.glob("*.py")):
        if py_file.name in skip:
            continue
        module_name = f"kobo_manga.sources.{py_file.stem}"
        try:
            importlib.import_module(module_name)
        except Exception as e:
            logger.debug(f"跳过源插件 {py_file.name}: {e}")