novel-downloader 2.0.0__py3-none-any.whl → 2.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. novel_downloader/__init__.py +1 -1
  2. novel_downloader/cli/download.py +14 -11
  3. novel_downloader/cli/export.py +19 -19
  4. novel_downloader/cli/ui.py +35 -8
  5. novel_downloader/config/adapter.py +216 -153
  6. novel_downloader/core/__init__.py +5 -6
  7. novel_downloader/core/archived/deqixs/fetcher.py +1 -28
  8. novel_downloader/core/downloaders/__init__.py +2 -0
  9. novel_downloader/core/downloaders/base.py +34 -85
  10. novel_downloader/core/downloaders/common.py +147 -171
  11. novel_downloader/core/downloaders/qianbi.py +30 -64
  12. novel_downloader/core/downloaders/qidian.py +157 -184
  13. novel_downloader/core/downloaders/qqbook.py +292 -0
  14. novel_downloader/core/downloaders/registry.py +2 -2
  15. novel_downloader/core/exporters/__init__.py +2 -0
  16. novel_downloader/core/exporters/base.py +37 -59
  17. novel_downloader/core/exporters/common.py +620 -0
  18. novel_downloader/core/exporters/linovelib.py +47 -0
  19. novel_downloader/core/exporters/qidian.py +41 -12
  20. novel_downloader/core/exporters/qqbook.py +28 -0
  21. novel_downloader/core/exporters/registry.py +2 -2
  22. novel_downloader/core/fetchers/__init__.py +4 -2
  23. novel_downloader/core/fetchers/aaatxt.py +2 -22
  24. novel_downloader/core/fetchers/b520.py +3 -23
  25. novel_downloader/core/fetchers/base.py +80 -105
  26. novel_downloader/core/fetchers/biquyuedu.py +2 -22
  27. novel_downloader/core/fetchers/dxmwx.py +10 -22
  28. novel_downloader/core/fetchers/esjzone.py +6 -29
  29. novel_downloader/core/fetchers/guidaye.py +2 -22
  30. novel_downloader/core/fetchers/hetushu.py +9 -29
  31. novel_downloader/core/fetchers/i25zw.py +2 -16
  32. novel_downloader/core/fetchers/ixdzs8.py +2 -16
  33. novel_downloader/core/fetchers/jpxs123.py +2 -16
  34. novel_downloader/core/fetchers/lewenn.py +2 -22
  35. novel_downloader/core/fetchers/linovelib.py +4 -20
  36. novel_downloader/core/fetchers/{eightnovel.py → n8novel.py} +12 -40
  37. novel_downloader/core/fetchers/piaotia.py +2 -16
  38. novel_downloader/core/fetchers/qbtr.py +2 -16
  39. novel_downloader/core/fetchers/qianbi.py +1 -20
  40. novel_downloader/core/fetchers/qidian.py +27 -68
  41. novel_downloader/core/fetchers/qqbook.py +177 -0
  42. novel_downloader/core/fetchers/quanben5.py +9 -29
  43. novel_downloader/core/fetchers/rate_limiter.py +22 -53
  44. novel_downloader/core/fetchers/sfacg.py +3 -16
  45. novel_downloader/core/fetchers/shencou.py +2 -16
  46. novel_downloader/core/fetchers/shuhaige.py +2 -22
  47. novel_downloader/core/fetchers/tongrenquan.py +2 -22
  48. novel_downloader/core/fetchers/ttkan.py +3 -14
  49. novel_downloader/core/fetchers/wanbengo.py +2 -22
  50. novel_downloader/core/fetchers/xiaoshuowu.py +2 -16
  51. novel_downloader/core/fetchers/xiguashuwu.py +4 -20
  52. novel_downloader/core/fetchers/xs63b.py +3 -15
  53. novel_downloader/core/fetchers/xshbook.py +2 -22
  54. novel_downloader/core/fetchers/yamibo.py +4 -28
  55. novel_downloader/core/fetchers/yibige.py +13 -26
  56. novel_downloader/core/interfaces/exporter.py +19 -7
  57. novel_downloader/core/interfaces/fetcher.py +23 -49
  58. novel_downloader/core/interfaces/parser.py +2 -2
  59. novel_downloader/core/parsers/__init__.py +4 -2
  60. novel_downloader/core/parsers/b520.py +2 -2
  61. novel_downloader/core/parsers/base.py +5 -39
  62. novel_downloader/core/parsers/esjzone.py +3 -3
  63. novel_downloader/core/parsers/{eightnovel.py → n8novel.py} +7 -7
  64. novel_downloader/core/parsers/qidian.py +717 -0
  65. novel_downloader/core/parsers/qqbook.py +709 -0
  66. novel_downloader/core/parsers/xiguashuwu.py +8 -15
  67. novel_downloader/core/searchers/__init__.py +2 -2
  68. novel_downloader/core/searchers/b520.py +1 -1
  69. novel_downloader/core/searchers/base.py +2 -2
  70. novel_downloader/core/searchers/{eightnovel.py → n8novel.py} +5 -5
  71. novel_downloader/locales/en.json +3 -3
  72. novel_downloader/locales/zh.json +3 -3
  73. novel_downloader/models/__init__.py +2 -0
  74. novel_downloader/models/book.py +1 -0
  75. novel_downloader/models/config.py +12 -0
  76. novel_downloader/resources/config/settings.toml +23 -5
  77. novel_downloader/resources/js_scripts/expr_to_json.js +14 -0
  78. novel_downloader/resources/js_scripts/qidian_decrypt_node.js +21 -16
  79. novel_downloader/resources/js_scripts/qq_decrypt_node.js +92 -0
  80. novel_downloader/utils/__init__.py +0 -2
  81. novel_downloader/utils/chapter_storage.py +2 -3
  82. novel_downloader/utils/constants.py +7 -3
  83. novel_downloader/utils/cookies.py +32 -17
  84. novel_downloader/utils/crypto_utils/__init__.py +0 -6
  85. novel_downloader/utils/crypto_utils/aes_util.py +1 -1
  86. novel_downloader/utils/crypto_utils/rc4.py +40 -50
  87. novel_downloader/utils/epub/__init__.py +2 -3
  88. novel_downloader/utils/epub/builder.py +6 -6
  89. novel_downloader/utils/epub/constants.py +1 -6
  90. novel_downloader/utils/epub/documents.py +7 -7
  91. novel_downloader/utils/epub/models.py +8 -8
  92. novel_downloader/utils/epub/utils.py +10 -10
  93. novel_downloader/utils/file_utils/io.py +48 -73
  94. novel_downloader/utils/file_utils/normalize.py +1 -7
  95. novel_downloader/utils/file_utils/sanitize.py +4 -11
  96. novel_downloader/utils/fontocr/__init__.py +13 -0
  97. novel_downloader/utils/{fontocr.py → fontocr/core.py} +72 -61
  98. novel_downloader/utils/fontocr/loader.py +52 -0
  99. novel_downloader/utils/logger.py +80 -56
  100. novel_downloader/utils/network.py +16 -40
  101. novel_downloader/utils/node_decryptor/__init__.py +13 -0
  102. novel_downloader/utils/node_decryptor/decryptor.py +342 -0
  103. novel_downloader/{core/parsers/qidian/utils → utils/node_decryptor}/decryptor_fetcher.py +5 -6
  104. novel_downloader/utils/text_utils/text_cleaner.py +39 -30
  105. novel_downloader/utils/text_utils/truncate_utils.py +3 -14
  106. novel_downloader/utils/time_utils/sleep_utils.py +53 -43
  107. novel_downloader/web/main.py +1 -1
  108. novel_downloader/web/pages/download.py +1 -1
  109. novel_downloader/web/pages/search.py +4 -4
  110. novel_downloader/web/services/task_manager.py +2 -0
  111. {novel_downloader-2.0.0.dist-info → novel_downloader-2.0.2.dist-info}/METADATA +5 -1
  112. novel_downloader-2.0.2.dist-info/RECORD +203 -0
  113. novel_downloader/core/exporters/common/__init__.py +0 -11
  114. novel_downloader/core/exporters/common/epub.py +0 -198
  115. novel_downloader/core/exporters/common/main_exporter.py +0 -64
  116. novel_downloader/core/exporters/common/txt.py +0 -146
  117. novel_downloader/core/exporters/epub_util.py +0 -215
  118. novel_downloader/core/exporters/linovelib/__init__.py +0 -11
  119. novel_downloader/core/exporters/linovelib/epub.py +0 -349
  120. novel_downloader/core/exporters/linovelib/main_exporter.py +0 -66
  121. novel_downloader/core/exporters/linovelib/txt.py +0 -139
  122. novel_downloader/core/exporters/txt_util.py +0 -67
  123. novel_downloader/core/parsers/qidian/__init__.py +0 -10
  124. novel_downloader/core/parsers/qidian/book_info_parser.py +0 -89
  125. novel_downloader/core/parsers/qidian/chapter_encrypted.py +0 -470
  126. novel_downloader/core/parsers/qidian/chapter_normal.py +0 -126
  127. novel_downloader/core/parsers/qidian/chapter_router.py +0 -68
  128. novel_downloader/core/parsers/qidian/main_parser.py +0 -101
  129. novel_downloader/core/parsers/qidian/utils/__init__.py +0 -30
  130. novel_downloader/core/parsers/qidian/utils/fontmap_recover.py +0 -143
  131. novel_downloader/core/parsers/qidian/utils/helpers.py +0 -110
  132. novel_downloader/core/parsers/qidian/utils/node_decryptor.py +0 -175
  133. novel_downloader-2.0.0.dist-info/RECORD +0 -210
  134. {novel_downloader-2.0.0.dist-info → novel_downloader-2.0.2.dist-info}/WHEEL +0 -0
  135. {novel_downloader-2.0.0.dist-info → novel_downloader-2.0.2.dist-info}/entry_points.txt +0 -0
  136. {novel_downloader-2.0.0.dist-info → novel_downloader-2.0.2.dist-info}/licenses/LICENSE +0 -0
  137. {novel_downloader-2.0.0.dist-info → novel_downloader-2.0.2.dist-info}/top_level.txt +0 -0
@@ -20,7 +20,7 @@ from novel_downloader.models import (
20
20
 
21
21
 
22
22
  @register_parser(
23
- site_keys=["biquge", "bqg", "b520"],
23
+ site_keys=["biquge", "b520"],
24
24
  )
25
25
  class BiqugeParser(BaseParser):
26
26
  """
@@ -112,5 +112,5 @@ class BiqugeParser(BaseParser):
112
112
  "id": chapter_id,
113
113
  "title": title,
114
114
  "content": content,
115
- "extra": {"site": "biquge"},
115
+ "extra": {"site": "b520"},
116
116
  }
@@ -12,18 +12,14 @@ from collections.abc import Iterable
12
12
  from pathlib import Path
13
13
  from typing import Any
14
14
 
15
- from novel_downloader.core.interfaces import ParserProtocol
16
15
  from novel_downloader.models import BookInfoDict, ChapterDict, ParserConfig
17
16
 
18
17
 
19
- class BaseParser(ParserProtocol, abc.ABC):
18
+ class BaseParser(abc.ABC):
20
19
  """
21
20
  BaseParser defines the interface for extracting book metadata and chapter content
22
21
  from raw HTML.
23
22
 
24
- This base class manages internal book state (e.g. current book ID) and supports
25
- configuration-driven behavior such as content cleaning or formatting.
26
-
27
23
  Subclasses must implement actual parsing logic for specific sites.
28
24
  """
29
25
 
@@ -31,22 +27,20 @@ class BaseParser(ParserProtocol, abc.ABC):
31
27
 
32
28
  _SPACE_RE = re.compile(r"\s+")
33
29
 
34
- def __init__(
35
- self,
36
- config: ParserConfig,
37
- ):
30
+ def __init__(self, config: ParserConfig):
38
31
  """
39
32
  Initialize the parser with a configuration object.
40
33
 
41
34
  :param config: ParserConfig object controlling parsing behavior.
42
35
  """
43
- self._config = config
44
36
  self._book_id: str | None = None
45
37
 
38
+ self._fontocr_cfg = config.fontocr_cfg
39
+ self._save_font_debug = config.save_font_debug
46
40
  self._decode_font: bool = config.decode_font
41
+ self._batch_size = config.batch_size
47
42
  self._use_truncation = config.use_truncation
48
43
  self._base_cache_dir = Path(config.cache_dir)
49
- self._cache_dir = self._base_cache_dir
50
44
 
51
45
  self._ad_pattern = self._compile_ads_pattern()
52
46
 
@@ -80,34 +74,6 @@ class BaseParser(ParserProtocol, abc.ABC):
80
74
  """
81
75
  ...
82
76
 
83
- @property
84
- def book_id(self) -> str | None:
85
- """
86
- Current book ID in context.
87
-
88
- :return: The current book identifier.
89
- """
90
- return self._book_id
91
-
92
- @book_id.setter
93
- def book_id(self, value: str) -> None:
94
- """
95
- Set current book ID and update debug paths if needed.
96
-
97
- :param value: Book identifier.
98
- """
99
- self._book_id = value
100
- self._cache_dir = self._base_cache_dir / value
101
- self._on_book_id_set()
102
-
103
- def _on_book_id_set(self) -> None:
104
- """
105
- Hook called when a new book ID is set.
106
- Subclasses can override this to initialize
107
- book-related folders or states.
108
- """
109
- pass
110
-
111
77
  def _compile_ads_pattern(self) -> re.Pattern[str] | None:
112
78
  """
113
79
  Compile a regex pattern from the ADS list, or return None if no ADS.
@@ -128,9 +128,9 @@ class EsjzoneParser(BaseParser):
128
128
  or tag == "summary"
129
129
  ):
130
130
  # Handle possible volume title markers:
131
- # - <h2>: standard volume header
132
- # - <p class="non">: alternative volume header style
133
- # - <summary>: fallback for stray <summary> tags outside <details>
131
+ # * <h2>: standard volume header
132
+ # * <p class="non">: alternative volume header style
133
+ # * <summary>: fallback for stray <summary> tags outside <details>
134
134
  _start_volume(node.xpath("string()"))
135
135
 
136
136
  elif tag == "a":
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env python3
2
2
  """
3
- novel_downloader.core.parsers.eightnovel
4
- ----------------------------------------
3
+ novel_downloader.core.parsers.n8novel
4
+ -------------------------------------
5
5
 
6
6
  """
7
7
 
@@ -21,9 +21,9 @@ from novel_downloader.models import (
21
21
 
22
22
 
23
23
  @register_parser(
24
- site_keys=["eightnovel", "8novel"],
24
+ site_keys=["n8novel", "8novel"],
25
25
  )
26
- class EightnovelParser(BaseParser):
26
+ class N8novelParser(BaseParser):
27
27
  """
28
28
  Parser for 无限轻小说 book pages.
29
29
  """
@@ -177,7 +177,7 @@ class EightnovelParser(BaseParser):
177
177
  "id": chapter_id,
178
178
  "title": title,
179
179
  "content": content,
180
- "extra": {"site": "eightnovel"},
180
+ "extra": {"site": "n8novel"},
181
181
  }
182
182
 
183
183
  @staticmethod
@@ -195,8 +195,8 @@ class EightnovelParser(BaseParser):
195
195
  def _build_id_title_map(cls, html_str: str) -> dict[str, str]:
196
196
  """
197
197
  Extracts two comma-split lists from html_str:
198
- - A numeric list of IDs (one element longer)
199
- - A list of titles
198
+ * A numeric list of IDs (one element longer)
199
+ * A list of titles
200
200
  """
201
201
  id_list = None
202
202
  title_list = None