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
@@ -15,7 +15,7 @@ _SUPPORT_SITES = {
15
15
  "biquge": "笔趣阁 (biquge)",
16
16
  "biquyuedu": "精彩小说 (biquyuedu)",
17
17
  "dxmwx": "大熊猫文学网 (dxmwx)",
18
- "eightnovel": "无限轻小说 (8novel)",
18
+ "n8novel": "无限轻小说 (n8novel)",
19
19
  "esjzone": "ESJ Zone (esjzone)",
20
20
  "guidaye": "名著阅读 (guidaye)",
21
21
  "hetushu": "和图书 (hetushu)",
@@ -26,7 +26,7 @@ _SUPPORT_SITES = {
26
26
  "aaatxt": "3A电子书",
27
27
  "biquge": "笔趣阁",
28
28
  "dxmwx": "大熊猫文学网",
29
- "eightnovel": "无限轻小说",
29
+ "n8novel": "无限轻小说",
30
30
  "esjzone": "ESJ Zone",
31
31
  "hetushu": "和图书",
32
32
  "i25zw": "25中文网",
@@ -145,9 +145,9 @@ def _build_settings_dropdown(
145
145
  Create settings button + anchored menu with initial values from state.
146
146
 
147
147
  Returns a tuple of getter functions:
148
- - get_sites(): list of site keys, or None if none selected
149
- - get_psl(): per-site limit (int)
150
- - get_timeout(): timeout (float)
148
+ * get_sites(): list of site keys, or None if none selected
149
+ * get_psl(): per-site limit (int)
150
+ * get_timeout(): timeout (float)
151
151
  """
152
152
  site_cbs: dict[str, Any] = {}
153
153
 
@@ -205,6 +205,8 @@ class TaskManager:
205
205
 
206
206
  task.status = "completed"
207
207
 
208
+ exporter.close()
209
+
208
210
  except Exception as e:
209
211
  task.status = "failed"
210
212
  task.error = str(e)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: novel-downloader
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: A command-line tool for downloading Chinese web novels from Qidian and similar platforms.
5
5
  Author-email: Saudade Z <saudadez217@gmail.com>
6
6
  License: MIT License
@@ -47,6 +47,7 @@ Requires-Dist: aiohttp
47
47
  Requires-Dist: lxml
48
48
  Requires-Dist: platformdirs
49
49
  Provides-Extra: font-recovery
50
+ Requires-Dist: brotli; extra == "font-recovery"
50
51
  Requires-Dist: numpy; extra == "font-recovery"
51
52
  Requires-Dist: fonttools; extra == "font-recovery"
52
53
  Requires-Dist: pillow; extra == "font-recovery"
@@ -122,6 +123,7 @@ novel-cli download 123456
122
123
 
123
124
  * 支持站点见: [支持站点列表](https://github.com/saudadez21/novel-downloader/blob/main/docs/4-supported-sites.md)
124
125
  * 更多示例见: [CLI 使用示例](https://github.com/saudadez21/novel-downloader/blob/main/docs/5-cli-usage-examples.md)
126
+ * 运行中可使用 `CTRL+C` 取消任务
125
127
 
126
128
  ### 3. 图形界面 (GUI / Web)
127
129
 
@@ -133,6 +135,8 @@ novel-web
133
135
  # novel-web --listen public
134
136
  ```
135
137
 
138
+ * 运行中可使用 `CTRL+C` 停止服务
139
+
136
140
  ---
137
141
 
138
142
  ## 从源码安装 (开发版)
@@ -0,0 +1,203 @@
1
+ novel_downloader/__init__.py,sha256=WykQ4IZGl_tkfxTDIG30i3MPMwO60d_GPd06zSvR99g,218
2
+ novel_downloader/cli/__init__.py,sha256=okUd_09fBWx8lz3zx3329dIK0xNRlNQJkUzDXYoSE1U,167
3
+ novel_downloader/cli/clean.py,sha256=VaiJox75-ZuXvSDFMaiAUawEbdtuEUsnsVWZGKuirJ4,2395
4
+ novel_downloader/cli/config.py,sha256=W4-f59dK5jdlg_9XDwGIyzd6VtpyNpB9U4qcxfso8Xg,3598
5
+ novel_downloader/cli/download.py,sha256=v-__VwnrS1S8j8x7YqS6OB5b30gr_wde0Qzx6PKDjhI,7633
6
+ novel_downloader/cli/export.py,sha256=a14ng11RVboJ0aBzhQ54wS5M_rVN-B-b6XbeZwPV12o,2640
7
+ novel_downloader/cli/main.py,sha256=GKtxeumw_VvWManp52Am538jL2t7xz7yVrGIaxrvSVk,1009
8
+ novel_downloader/cli/search.py,sha256=_Ci4fa1ECiYmBZI2OZBxzwddYGIvdUyIp4AOIJiL1Ds,3641
9
+ novel_downloader/cli/ui.py,sha256=vL0FF0vqYE51cKkQUTl_6mmDpiIEhQ4RrCPYwywuJtA,4787
10
+ novel_downloader/config/__init__.py,sha256=gwaDMlcBX7Lw8Hi8dY2HxNEt9ysMhIFNhkziyjramWo,405
11
+ novel_downloader/config/adapter.py,sha256=olYPMwUxd2w5Su6h-txA42WRxLuk--QJ2g14AxPu7Kc,14380
12
+ novel_downloader/config/file_io.py,sha256=ncKk7rj07UnYYVEPR_RHS2D5igMSv8xaHySNvJQWhB8,6495
13
+ novel_downloader/core/__init__.py,sha256=oCmWj9t7CEyNfew5O25YeaMPeMvXt082jprKAPMffKk,1166
14
+ novel_downloader/core/archived/deqixs/fetcher.py,sha256=rXJf72PGpwGmRWCTDBmCPJPxVh6vaejVrUcvvr6mBhU,2557
15
+ novel_downloader/core/archived/deqixs/parser.py,sha256=udM6MYdunPVYwUNjEoBDjffHR_SsXPvv_EqsCMJJVrE,4169
16
+ novel_downloader/core/archived/deqixs/searcher.py,sha256=ezXCQ0pM8AqmTXmkzLrOSebTvHg_GouIywIE23c5hwY,2920
17
+ novel_downloader/core/archived/qidian/searcher.py,sha256=Q0-MdYfO-NrFW7rhF92lXk8EX1Gdcmp_gYzhcM06cLU,2460
18
+ novel_downloader/core/archived/wanbengo/searcher.py,sha256=RAXHENGgqGzWRop3N4_PPlRB7JdUZotQqKaA2RRrzZM,3056
19
+ novel_downloader/core/archived/xshbook/searcher.py,sha256=pfyVPl7DP_cq0mjIIyOkQPKZL-piOTO5agSSPeY4Qi4,2915
20
+ novel_downloader/core/downloaders/__init__.py,sha256=n8MQEIpD3UWDMNY6-u4tCsOWSg2TjIqgj-5AfwLI6h4,491
21
+ novel_downloader/core/downloaders/base.py,sha256=t3PzP58YLJRA6ug8LfYhxv58qHB8n5nl2EC0ureVKtU,10531
22
+ novel_downloader/core/downloaders/common.py,sha256=B-5kTuKiojPCDmx_SLUPoukdAN7r-krurxb82dqoDOY,9133
23
+ novel_downloader/core/downloaders/qianbi.py,sha256=yOK2NJNSfGsvgXnu4ktuwQeX35vkrD3LVjyVYNKU34s,11820
24
+ novel_downloader/core/downloaders/qidian.py,sha256=dK1UTaQml68koWUSjdfXD60rEhgAggQNXV1wO8i_A8U,11019
25
+ novel_downloader/core/downloaders/qqbook.py,sha256=SP-xfxtjuuqEC78xYDLWs-0_stQHpJt3uWfJDH83Jh8,10308
26
+ novel_downloader/core/downloaders/registry.py,sha256=DWCC_zQ5_Z2qAXAq4w_rOi4j83aPC_8Nlr0APqmeOxo,1902
27
+ novel_downloader/core/downloaders/signals.py,sha256=fgiSH8iRqkNqyI7pZX-hfJEOMY1KbXB1lT49eSJyHqQ,1093
28
+ novel_downloader/core/exporters/__init__.py,sha256=sPgSODCrI4edijIkcyltmgWphUv2v19eERBA3fHs8H8,490
29
+ novel_downloader/core/exporters/base.py,sha256=W6LYrJvbg9JMNQqtev1OZDuSZTSY0tMvRy20LyFTXjw,8315
30
+ novel_downloader/core/exporters/common.py,sha256=skuHohMRpqtwRxPewdXSzSxSrc_bLzmGLR-lVll3As4,21422
31
+ novel_downloader/core/exporters/linovelib.py,sha256=hTlRANVw3pQ3xnGWKQ_e5MZg6173fWHUEUEMhIP2cv4,1226
32
+ novel_downloader/core/exporters/qidian.py,sha256=w0mp0BvvchToESK-zLTcR8UWT2KQgysb0enR9y2P5rA,1824
33
+ novel_downloader/core/exporters/qqbook.py,sha256=742nlK3hfWqsEQmUiC9GPyufSakcgWS-ywTF4ycNHgk,731
34
+ novel_downloader/core/exporters/registry.py,sha256=rPWjq6TabFfWc7AtrqJ3ZY0N4ZuyAxMXXCOyJV4WcwU,1567
35
+ novel_downloader/core/fetchers/__init__.py,sha256=ppRZ1tNOTLkxwFlUm-b1rENySV2oTqQMeZZOPnGYsRw,2028
36
+ novel_downloader/core/fetchers/aaatxt.py,sha256=yRavuz6PrD28JAWLeZRFbFQ646vvLaSGh_6y7N4UETA,1768
37
+ novel_downloader/core/fetchers/b520.py,sha256=eNkZ3MMmjaygjdMX4-P_N9FoB4GkZPiAESaOds5L_gY,1800
38
+ novel_downloader/core/fetchers/base.py,sha256=BKrwUeTSqBpnP7qJpSFkIBQte9z7Lbn9l5vKWEcXjkM,12770
39
+ novel_downloader/core/fetchers/biquyuedu.py,sha256=kTfkX5cT8wXOpRjs3vxhjauzxe5ddS6nEBk5ncZv4ic,1824
40
+ novel_downloader/core/fetchers/dxmwx.py,sha256=WwQUlDjpYGQq_oQAgtG8pGDvAKre4msQw0pq2HntFfA,3023
41
+ novel_downloader/core/fetchers/esjzone.py,sha256=A1YpLGfmCMnhXCL73QZUZio59u_ZlZ5p0kP1hoB9r2M,6807
42
+ novel_downloader/core/fetchers/guidaye.py,sha256=YbaSWiD2CRxu3ZSjKdywjOxu63lreUnOLFVmvTNqiSs,1886
43
+ novel_downloader/core/fetchers/hetushu.py,sha256=VzbQtoAAi1iEFxo6Lgx5u_Wj7_H4c5wzjAm7mP7Sa04,2146
44
+ novel_downloader/core/fetchers/i25zw.py,sha256=AGT-t7tkP_y3F2bX6H0gF-4_N4lJflchbTe3_H9X-6Y,2622
45
+ novel_downloader/core/fetchers/ixdzs8.py,sha256=s3bguwtnlJXfkOell7Q5fcX-CqlrHtujStt2r_pRKAU,3066
46
+ novel_downloader/core/fetchers/jpxs123.py,sha256=SCBHE2uve9prpZd7h5_Z0Awuf6Sb9lMVHVm2No4oZbA,2656
47
+ novel_downloader/core/fetchers/lewenn.py,sha256=2NGvn8HVUQGIRn3vYQn2REJcXHs7yQrcyQ2c3EYZoQk,1808
48
+ novel_downloader/core/fetchers/linovelib.py,sha256=eh2ODbRDRI7FEo4E0uP8u5Ec-wRpWF74AyegZKwVuPw,5564
49
+ novel_downloader/core/fetchers/n8novel.py,sha256=0w1wc65bRfkC7c5XatAoeKbEMfbVT4pOsija0iecJKs,3481
50
+ novel_downloader/core/fetchers/piaotia.py,sha256=idSdaLfXwcQrWxWJeUeX31DhMsHrmk_dDtvzvpvHlOE,2756
51
+ novel_downloader/core/fetchers/qbtr.py,sha256=RXZVVHHS71w88Id20hftkeE9R3EXfG-tn7CdRG_ycHs,2630
52
+ novel_downloader/core/fetchers/qianbi.py,sha256=cby1Zx3PLomshIYNDlR-7Jxoay3V-_d-ZaKOxqNDaTQ,2637
53
+ novel_downloader/core/fetchers/qidian.py,sha256=sdNvnkk33X3tOBIEIlUiP47qYZBC2o4KGgsJN-jZ9Zw,9581
54
+ novel_downloader/core/fetchers/qqbook.py,sha256=p3goeLF-4YEoPkU3SdSxjE7xD58AxhK1SzpyuX6PkZU,5246
55
+ novel_downloader/core/fetchers/quanben5.py,sha256=pktaWblBE7pB-gWnh_s9DBM9RdDLpnl7xrqehdDmNaI,2146
56
+ novel_downloader/core/fetchers/rate_limiter.py,sha256=5h8pcVGsxcywph_DFqcMao5UnyAHseDAmP1_HZKNC3U,1552
57
+ novel_downloader/core/fetchers/registry.py,sha256=z9DDTUjc2r-Xiq3MqaPfV_3EmQBXr2TK_G8eARnblkA,1580
58
+ novel_downloader/core/fetchers/sfacg.py,sha256=xJILO3usvOVU41-XW6DqtMAdwZtNeiSDm24fQ9IkheM,4721
59
+ novel_downloader/core/fetchers/shencou.py,sha256=BDuR0zJ7AWrLcW7OwWOKxO3ySVY9x4tImWm87xqAFrs,2805
60
+ novel_downloader/core/fetchers/shuhaige.py,sha256=G5kR5xG4YY90GG59Ou9NtYEtdoNB0i8psKtH4ewbX80,1822
61
+ novel_downloader/core/fetchers/tongrenquan.py,sha256=OI9B6IhyccH2UnJ744WAwBoy_QyuQJVezfpzyCT0ktc,1898
62
+ novel_downloader/core/fetchers/ttkan.py,sha256=36ddzHAwLkKdytmCh4LjKAjnE1PzkmMuvJ4xAukHgQw,2414
63
+ novel_downloader/core/fetchers/wanbengo.py,sha256=MYpdVPqB2Dq2ZT9Glkx6un8wM9eBJiKJVTRLT3YiLAA,1812
64
+ novel_downloader/core/fetchers/xiaoshuowu.py,sha256=9_1xrlHpl7JGjC9-jIQZFOAoXYDCFHwaCx5NtTHWZ_4,2846
65
+ novel_downloader/core/fetchers/xiguashuwu.py,sha256=eZIHKZksLIL5yoer8yvhMawMug-sJvWxAuMFYtUspDs,5211
66
+ novel_downloader/core/fetchers/xs63b.py,sha256=8hoJVjsTBduPiHWQc48wxgBUIw8fqHPWWKvnwWvPX9w,4788
67
+ novel_downloader/core/fetchers/xshbook.py,sha256=BPvmnldQ6ox_7ckJBXUtY0YHikybKH0C6_dgBz_II24,1889
68
+ novel_downloader/core/fetchers/yamibo.py,sha256=mU0bnMDx1WLEEICg-tC4cubO0FXLctuOBwp16xYXf9g,6765
69
+ novel_downloader/core/fetchers/yibige.py,sha256=kAv3GTiQH6s_uHAtWor_UtT47QwSE1M8ZNdc-RhLt7Q,3172
70
+ novel_downloader/core/interfaces/__init__.py,sha256=YwDOPw_UCjuAE5u_LpUYxXjOH4X2kNMXrmUoBa5jp2Q,490
71
+ novel_downloader/core/interfaces/downloader.py,sha256=nGY2LYCCBzrKhs612L5tevGG8kJp_XfCyKvqjXEIeoI,1763
72
+ novel_downloader/core/interfaces/exporter.py,sha256=j160HjMQSobgIMlH2ULm1m1b2APgnYqSRIKX9Q4bFfo,1836
73
+ novel_downloader/core/interfaces/fetcher.py,sha256=qEgGm1fAiWYiziT81ZVJYaZxDoWDqV5W1nTcMN3Z2-4,3025
74
+ novel_downloader/core/interfaces/parser.py,sha256=B_HsE_PshnUjz-QibBpuNht6whN9gboW-k1BAsnMe6M,1317
75
+ novel_downloader/core/interfaces/searcher.py,sha256=1orneqFtwcqM5sFBKmhpWFbHk5bV7oEp0mN_77lgy6E,587
76
+ novel_downloader/core/parsers/__init__.py,sha256=4MzNhYriNPupNRO_bzEy6YAVAhqNTVKmj29n9ru1Eko,1971
77
+ novel_downloader/core/parsers/aaatxt.py,sha256=1NCrhbbpd5FUi0ybMX2LYf6Sss4pY3eDXTXk7MEkrkk,3633
78
+ novel_downloader/core/parsers/b520.py,sha256=hCQxd02Bz6-_yqAiNVpIYlA6YJ7Au0Q4EdH_6RdCK3U,3245
79
+ novel_downloader/core/parsers/base.py,sha256=g701qVIcqX8ZZ_SZXDY4rLrklzeJVVVTiYBSJCSW1WI,3737
80
+ novel_downloader/core/parsers/biquyuedu.py,sha256=IpZfL2AC0oUq5Gx8iqwTH8sItxtzpxvDRKaMmtYf_xU,3867
81
+ novel_downloader/core/parsers/dxmwx.py,sha256=uj3tj36d8lnXbgFvmpHzrvv9oDYuMXWZCb0d8I32GfA,5006
82
+ novel_downloader/core/parsers/esjzone.py,sha256=WeBwFn8waUtiZ3rzGJaiuB21ga7mnMnuBCA-0XnXOQI,7958
83
+ novel_downloader/core/parsers/guidaye.py,sha256=o1d987B5hkCEIVHYhszSavwKJFAErZVwpDaUPkSNUh4,3879
84
+ novel_downloader/core/parsers/hetushu.py,sha256=WUG4E9lvDJsa_l1xezYt0epPPJ4V9y_C4wwqWB8sxJs,4047
85
+ novel_downloader/core/parsers/i25zw.py,sha256=qILX6HQifu0hLJDNFc7XCqUNSQpfALhVgPC9jEGQt4g,4221
86
+ novel_downloader/core/parsers/ixdzs8.py,sha256=IyT9xoiyzghRuHg9-VASdEkmj-OMrrOBDWhjRNNmrVg,5690
87
+ novel_downloader/core/parsers/jpxs123.py,sha256=YwZAayPe_N2HJvioKifb3TJmk_EMsaRnPlknCCxHmrA,4211
88
+ novel_downloader/core/parsers/lewenn.py,sha256=YNk1Jl8eHwFFAAn-NyB1t0cVTZgl-Gkyy1SjGnKYSAU,4225
89
+ novel_downloader/core/parsers/linovelib.py,sha256=7d4nw6XowcRLGA_BY9q_3tJ8o19JS6_qAIl2vJoVelg,7083
90
+ novel_downloader/core/parsers/n8novel.py,sha256=AOAaOk1RKJe0gnUggSiVrIwgWD8bNs6cEaiFfb92_MY,7279
91
+ novel_downloader/core/parsers/piaotia.py,sha256=VGj10yVGzNK_TwUmo-5tVbCgbQA2FlJDv67m-KMxfIo,6086
92
+ novel_downloader/core/parsers/qbtr.py,sha256=0sae3Ms68Z7XaHav7_5Eid8sqlW1VBn0zZsy1WmVu64,4241
93
+ novel_downloader/core/parsers/qianbi.py,sha256=ULRLFE-bwnHU8Eifa7egD-cNk_-ea4vyFSCZwGAVTWM,4811
94
+ novel_downloader/core/parsers/qidian.py,sha256=tq-foRGo2H4C64cWYpD8nrPIzlOmg-JgkvIqVZ9Nn5I,25537
95
+ novel_downloader/core/parsers/qqbook.py,sha256=9QMSrsSRQUzQYCsZuDP9Rva5hw7QeRU1DvRzf5CW64w,24487
96
+ novel_downloader/core/parsers/quanben5.py,sha256=wr8QgIYk8FBcJBwm_wjXDdG0yMnodHHzBqnaPn1JETE,3075
97
+ novel_downloader/core/parsers/registry.py,sha256=2L6yRew4hxN04UUB4xm4E4v8R5RUldawF-Xkg8nXBPI,1534
98
+ novel_downloader/core/parsers/sfacg.py,sha256=7FuiLgN2SuDTkVmClQe4I8oU35RuLlPEEAHLSLEWqwk,5598
99
+ novel_downloader/core/parsers/shencou.py,sha256=pdkBCU7n6NmNs64cD6jfbDtEHNSuGqLOiQaIYhLeNr8,6775
100
+ novel_downloader/core/parsers/shuhaige.py,sha256=rlHXcpKil8anKMi6OVvoPAqGuQdA15hMLlCuSr6C5tM,3128
101
+ novel_downloader/core/parsers/tongrenquan.py,sha256=y3ok9g-BzA2YVM4KqoNPPpclE0wdNL5mVY3GRQ9FshM,3399
102
+ novel_downloader/core/parsers/ttkan.py,sha256=_8nc6diogbb9uGHm_lXYJT-RHR9p76o7ARn4NPom2-E,3564
103
+ novel_downloader/core/parsers/wanbengo.py,sha256=boEnK1gLLpqmf5EUFY9gVEhBxqxYrVka9ou_mDGZ4co,6407
104
+ novel_downloader/core/parsers/xiaoshuowu.py,sha256=k8j0TY5t7s0n1f-FWuRTZ-eN3A8p-_xnKy7-kp2deK4,5328
105
+ novel_downloader/core/parsers/xiguashuwu.py,sha256=V3bgvntbDBYm_l9UQUyytfSQ023Qb4Eov1edH52zD84,14225
106
+ novel_downloader/core/parsers/xs63b.py,sha256=A02abnMtsnWTomx-Hcfr97HFnNO38X9mmqKxHKrS610,5312
107
+ novel_downloader/core/parsers/xshbook.py,sha256=WwIGXEBAY8h-MLeApB1oVko_g3HF1Uj0X-Hko3TTrJ8,3995
108
+ novel_downloader/core/parsers/yamibo.py,sha256=B2ijBHCS0JW0I387LH8gDjevwakOE0RRKaKRsV4zo7A,5018
109
+ novel_downloader/core/parsers/yibige.py,sha256=K_nQ1SwVKLndgzlRvoTd2wd0tWXKb-T02c0sE6-bS5M,4846
110
+ novel_downloader/core/searchers/__init__.py,sha256=jU5kOLbzj10EYdNtnKQuKbZweGrtdXgBHNli6GvJhDM,1370
111
+ novel_downloader/core/searchers/aaatxt.py,sha256=KHaX1dpDBaAJz-_7UlaTtnMbFlTplWHaFyOfCkn4gX4,3717
112
+ novel_downloader/core/searchers/b520.py,sha256=n6X2f0FRoxGDSsvOIMwbs0yZ6U7V6LnkGajGwkPzztQ,2614
113
+ novel_downloader/core/searchers/base.py,sha256=KKX1-s5qUBX09LKV5wZP0v4SFDmawCSAL_1HhQU868U,5111
114
+ novel_downloader/core/searchers/dxmwx.py,sha256=ZaeFSU2T3Yl9x6hquila7cF4wYdwm9d82cTjFT9byCQ,3225
115
+ novel_downloader/core/searchers/esjzone.py,sha256=zw7bQalTfYjp9an0Ghk0ZDsWEOOh-fNsR4Lsoi4u7xA,3199
116
+ novel_downloader/core/searchers/hetushu.py,sha256=qhX6-QdvzPCXHh7hO6tHXFd3dpbcff_1PL7YvqgOQho,2829
117
+ novel_downloader/core/searchers/i25zw.py,sha256=1h3IZxjFO8XirDYN7x7fc96XjuspuTdkAUNHf1xVeBM,2827
118
+ novel_downloader/core/searchers/ixdzs8.py,sha256=Q-tZk5czA-wTSDQ4jnJEITfWWnsMXre5nPTjwJxGl6s,3454
119
+ novel_downloader/core/searchers/jpxs123.py,sha256=BeEa7wkE0KGwZ3HPIKSh7I8wpF_V8Z2L87eWjzphzwk,3345
120
+ novel_downloader/core/searchers/n8novel.py,sha256=pvAGlXj8JDLnMdpWsCd56Oh5FwjZB1ksSaqQgeXztok,2517
121
+ novel_downloader/core/searchers/piaotia.py,sha256=dGueBh819EvxgL-cyBITud3DGXJhebhZkExVxcPcH6E,3510
122
+ novel_downloader/core/searchers/qbtr.py,sha256=yokdCqlhlfJYy6HDhMZS4nGNzHGYwTy36glXq_AlSDw,3231
123
+ novel_downloader/core/searchers/qianbi.py,sha256=UK7znw9RZkhpsDTy3_wavi3aBLnaLVUGd9E_Epq5c20,5404
124
+ novel_downloader/core/searchers/quanben5.py,sha256=xDKtDsZ8e4bhmA9rIG-cdIkbtnaUUxSxJRqZrad1u3g,4265
125
+ novel_downloader/core/searchers/registry.py,sha256=VFtvtbAqLBSYO7CvXrVya-85t-jOUmyth30wls-6noY,2441
126
+ novel_downloader/core/searchers/shuhaige.py,sha256=8XW39aIdyHzWwG8r_hsr7YhOEGQLLTIXObe2HlAW8D4,3841
127
+ novel_downloader/core/searchers/tongrenquan.py,sha256=NE0BN4gutipfBPMm5TJP3YyI29ce6ERpmC1mqfQNgdc,3471
128
+ novel_downloader/core/searchers/ttkan.py,sha256=Y-qjePD7zQx8RUgASTuz4yu5fzT5MOJg7Qh9_SaP1z0,2851
129
+ novel_downloader/core/searchers/xiaoshuowu.py,sha256=gAS3OpoMwfksEtlXPL5XPrfD7KVprl8YA7HGn3gGANg,4132
130
+ novel_downloader/core/searchers/xiguashuwu.py,sha256=YWxOQpXUhMMsgxt7zc51rtdbe6mn9yv5Vzeg63OCJlQ,2952
131
+ novel_downloader/core/searchers/xs63b.py,sha256=T4QUQphYFvnbnENxFbYVNtZMi2QhXypxOJU-FjjVYwU,3443
132
+ novel_downloader/locales/en.json,sha256=w3TA-AtsQE2C1EVf5tNiOQRnaaXEaXX88-0Bb3xWdU8,3942
133
+ novel_downloader/locales/zh.json,sha256=XRku9SHycZ8zP0YYBwchBAg4yYjCWpgCLDItW8cmUcI,3779
134
+ novel_downloader/models/__init__.py,sha256=nKjRzf2rniAKSptHdngY9uZn6H0CuXIrCrTHsKVKS1A,730
135
+ novel_downloader/models/book.py,sha256=Xt59n7NRLoqb2Xh5W-VY0ogVXE_XdhXtyYCrtaDOHBE,909
136
+ novel_downloader/models/config.py,sha256=oF2NkXwInYOCpnb2cG1LpbBKPared3g5Ap-l952HGcI,2547
137
+ novel_downloader/models/login.py,sha256=VpTKfistRmlEJ67bzRpnAeQFBqs8R7VeGXZ74BZvTF0,355
138
+ novel_downloader/models/search.py,sha256=NSAXbQJvUY1Zdp1HfAt6JJ-mTFw2aX4-Je-JLeMG8ZY,351
139
+ novel_downloader/resources/config/settings.toml,sha256=RaG-VIa9K6e60vMaM7G9EjaAU8NXxQzLoYlCNtBbbsg,3702
140
+ novel_downloader/resources/css_styles/intro.css,sha256=Nqzp-A5we92d90CCiGL8h2FeuMnCz-G0TLevMF_Pl2U,1271
141
+ novel_downloader/resources/css_styles/main.css,sha256=1nsDTr698eY3furWDHuQMDKP1Vqd2h5x40eJMZpktNE,559
142
+ novel_downloader/resources/images/volume_border.png,sha256=2dEVimnTHKOfLMhi7bhkh_5joWNnrqg8duomLSNOZx4,28613
143
+ novel_downloader/resources/js_scripts/expr_to_json.js,sha256=ZyJ1l_2hB8-QMepDbE0KNJQhtr_yg959f7rtAjfZy7s,340
144
+ novel_downloader/resources/js_scripts/qidian_decrypt_node.js,sha256=mfBqyzSCC38UFjWrFbjX7SsBoIeok1Iv20Nxk6zIFV0,1914
145
+ novel_downloader/resources/js_scripts/qq_decrypt_node.js,sha256=QUuWrQhsdUtfhRc38Alg3mPRaHszXTsCIhXWwhOTApQ,2280
146
+ novel_downloader/resources/json/linovelib_font_map.json,sha256=F1IlEcvXGcagnZCu4Gw2vQ2NLnhy6cJOLhabukqnftw,67854
147
+ novel_downloader/resources/json/xiguashuwu.json,sha256=AT8KSFBWuiHj4Ggz3O1LqED0Tw22k0A4-V4OziHbqfo,16471
148
+ novel_downloader/utils/__init__.py,sha256=_l77NlxmGA3HHGSwK68o4_Nc7xRaVP8Bo8SUuImP5Uk,867
149
+ novel_downloader/utils/chapter_storage.py,sha256=7jpVdOguuylnjsJi_yQ-jCMIPljtJWsq_NqXMDDv0lQ,10315
150
+ novel_downloader/utils/constants.py,sha256=t4lUTT_VHryJ8AyUg9edCoXWmvLgzTjQoODiUImiLws,3413
151
+ novel_downloader/utils/cookies.py,sha256=Z_9mjJYfhv6xPVgsm7BzCpWeMTcPKoxAoUFWZYuEFWM,2117
152
+ novel_downloader/utils/i18n.py,sha256=86Wz4zT0_YTnmOSS6cliqO_uMgJJdfC-hNLyqZnXgvU,1050
153
+ novel_downloader/utils/logger.py,sha256=QuPyblYOIXEa4X0YBHLZgwbv1ZhkPNq159qyGmFKOno,3551
154
+ novel_downloader/utils/network.py,sha256=AIbM2kEfA9OjkMluFRKqGZIY2ZfNxVAoPnUHUkKkzgw,3625
155
+ novel_downloader/utils/state.py,sha256=QHfvS9CrO08fRZLNM0B_s0n5XIz7ap20NdAfesQI0Ek,1852
156
+ novel_downloader/utils/crypto_utils/__init__.py,sha256=MOl8pb73dRk8yQDuh2RZULnM3mn9VnJnOkh0SWcvaPs,136
157
+ novel_downloader/utils/crypto_utils/aes_util.py,sha256=PiDn1RPkTtki-9ZiTiE2rDgjhN7Ag79k2VDjjpTlkvc,2880
158
+ novel_downloader/utils/crypto_utils/aes_v1.py,sha256=_jW86_WyUTJfOzqYbZ6QvNPF-V8YRaqaOsyLjMsO610,34247
159
+ novel_downloader/utils/crypto_utils/aes_v2.py,sha256=OAsMnsztkJilqo8jM6nkrPMyujPqgGhohd-TcwW6fVA,48945
160
+ novel_downloader/utils/crypto_utils/rc4.py,sha256=SbC0oAdg2N7LWMnq9YbNh-zChI8SfpeBiijTPxFkYFc,1319
161
+ novel_downloader/utils/epub/__init__.py,sha256=77WorOLdsaxNoiuDPVxvQkiU49NW774bf3E7erPBv1I,725
162
+ novel_downloader/utils/epub/builder.py,sha256=2Vd7qD12vWqu05hVHrcgn5gfRzxGklY88nv8unuXF4M,11676
163
+ novel_downloader/utils/epub/constants.py,sha256=1P75NXAiKhoWqgAs_FDisT-U3ULnpk8wdvMnASCMg_o,2867
164
+ novel_downloader/utils/epub/documents.py,sha256=UijMa8yHpleZLUtRrwwTsOPZlqYlC5-qqXEuKh_StPI,9882
165
+ novel_downloader/utils/epub/models.py,sha256=CppM1qIC_G53L-lbouJO-pBBKLMTRfMvOM2PUOSPT78,2489
166
+ novel_downloader/utils/epub/utils.py,sha256=7eRYXUZFZ3NQU69UDwLK_yxiPQWpRhxBPhzKkQSTS0s,5090
167
+ novel_downloader/utils/file_utils/__init__.py,sha256=PIE96UKkI73wNr5v8kbP159BIbkEwsOQa9iEFr5RGUw,366
168
+ novel_downloader/utils/file_utils/io.py,sha256=bF1q38BdwjTkM8ylfQGczWAcAMHI0gBB5xNkYwTYqrk,2167
169
+ novel_downloader/utils/file_utils/normalize.py,sha256=j8d6kmiQyafa-E8NjTv33uUrnNDoxyJ18orXfS5J_Gw,1708
170
+ novel_downloader/utils/file_utils/sanitize.py,sha256=IuJA2JjcrxxOnJtehPLBpBNOuyNbj97TUZvw-vXB9PE,1713
171
+ novel_downloader/utils/fontocr/__init__.py,sha256=lWT8hVKeuYatEanyw6EjlgPidlyWSMkgCiRliEG_VtA,314
172
+ novel_downloader/utils/fontocr/core.py,sha256=pea9WkepQcD2tRgjX0xsvSABVCz7W9qJHy4s8QTY1Ag,7544
173
+ novel_downloader/utils/fontocr/loader.py,sha256=lgBjEC_c4JMxhTM1kbIth0F30rr9_zy-kOP_2EwhOAI,1422
174
+ novel_downloader/utils/node_decryptor/__init__.py,sha256=d5ISKEWv4i5ZF7rLtaOnnoLHrUENbVI9r9-FCCOYZTw,368
175
+ novel_downloader/utils/node_decryptor/decryptor.py,sha256=Nm9t_qL8N1xFplr0ntThVui2M4YlIxQKUJHOGSArIPU,11165
176
+ novel_downloader/utils/node_decryptor/decryptor_fetcher.py,sha256=U9nBp-DKutqQDjCMkxwR36w869-GiQErXkGN1XdiyZ4,4595
177
+ novel_downloader/utils/text_utils/__init__.py,sha256=cr0HCvgQFJE2ZEXqjkkmrOA7PnH50dKegrjdpIytUJs,601
178
+ novel_downloader/utils/text_utils/diff_display.py,sha256=5zvVtzsLbRxmUnn_dWUsXFaq6hch02OlOpqKYP8GB3g,2491
179
+ novel_downloader/utils/text_utils/numeric_conversion.py,sha256=RJ3L5GBxgNEQYJ7xFoihLVsjGcObBfpUAk_Gz5MxlkA,6627
180
+ novel_downloader/utils/text_utils/text_cleaner.py,sha256=9GbJChhZQGW06LApnHNzy6t5gS73AA9BTBigBn9qgcs,6410
181
+ novel_downloader/utils/text_utils/truncate_utils.py,sha256=xg5nlQvq6O1g3K-I64aTZvtnesN0P5QBGUVCPj09g8s,1284
182
+ novel_downloader/utils/time_utils/__init__.py,sha256=XbBeSbpNqiJy7Lsv-_udz29hPnIY53F0Drbuh730y44,331
183
+ novel_downloader/utils/time_utils/datetime_utils.py,sha256=ECidI5yvWVia8BWWLu7U0O0YYMIKgJwzWQmOuA_un3U,4499
184
+ novel_downloader/utils/time_utils/sleep_utils.py,sha256=uwQfnhFHqNOku8UwUJ7btD2N0NgDjY925QKDzT-9_sE,3000
185
+ novel_downloader/web/__init__.py,sha256=ga8qRQhYcGEiL0WKhSSyldLxkOEfrq-UU71T7MYv7EU,174
186
+ novel_downloader/web/main.py,sha256=ZzQcpJkAZb7tRlBkub6LGggNrbM4gtrI4nb-MyiUAlY,1783
187
+ novel_downloader/web/components/__init__.py,sha256=fxBI7rpAQvdZU3obR6_-bFqgmA7nzvRpW05Rw3b4jp8,193
188
+ novel_downloader/web/components/navigation.py,sha256=m-rjbNRlYjqXsu2dq5PdCzpqy7oW6_otra2ZufRsh1c,1156
189
+ novel_downloader/web/pages/__init__.py,sha256=KP_aH8y8dtCeRze8jDJ4tC3Ft7UTGhlW8ZKDdKPdwcM,383
190
+ novel_downloader/web/pages/download.py,sha256=cJ7txLvcXydLTciaSYUSul0jglulRAHMQ7UF25JsvtA,2598
191
+ novel_downloader/web/pages/progress.py,sha256=whWduqLvQ1PPZpDNVfvFCVaFgFhD87LT4CDb8JuqD_w,5207
192
+ novel_downloader/web/pages/search.py,sha256=sybpINlDt-zyRxyVulhbB8kKJuOxkOSZAV2chDxWcFI,10232
193
+ novel_downloader/web/services/__init__.py,sha256=kLW0uyqudnlHtSsMrrghmL6P1-VDrseggNdB3cR5jLA,316
194
+ novel_downloader/web/services/client_dialog.py,sha256=JwYV8bjxPxLQsuheC8rk_jaeODolz5X9Wo64MsXZoyc,5679
195
+ novel_downloader/web/services/cred_broker.py,sha256=_R2Szqg5qRBHrFujTlPxrrMpQsnfNozjLUxJ5HhD8_c,2939
196
+ novel_downloader/web/services/cred_models.py,sha256=8nXbVoAIz3QokctrCVm-8lSnKgCIFhMM6TuaNq6bFGU,846
197
+ novel_downloader/web/services/task_manager.py,sha256=tK2Vs5Wnx5Jp8Z8myq_-lPm1NwZ2QxLjaHa9p0Jc_K8,8654
198
+ novel_downloader-2.0.2.dist-info/licenses/LICENSE,sha256=XgmnH0mBf-qEiizoVAfJQAKzPB9y3rBa-ni7M0Aqv4A,1066
199
+ novel_downloader-2.0.2.dist-info/METADATA,sha256=eyqsSofixNRuVJ3DASJoP6KdGa56KkCbZAjErOf38M8,6589
200
+ novel_downloader-2.0.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
201
+ novel_downloader-2.0.2.dist-info/entry_points.txt,sha256=nIgnurS4J6_ce3oIBFV87I1pPwBofuRQvxkoRGn4yEU,112
202
+ novel_downloader-2.0.2.dist-info/top_level.txt,sha256=hP4jYWM2LTm1jxsW4hqEB8N0dsRvldO2QdhggJT917I,17
203
+ novel_downloader-2.0.2.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.common
4
- --------------------------------------
5
-
6
- Shared exporter implementation for producing standard TXT and EPUB outputs.
7
- """
8
-
9
- __all__ = ["CommonExporter"]
10
-
11
- from .main_exporter import CommonExporter
@@ -1,198 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.common.epub
4
- -------------------------------------------
5
-
6
- Contains the logic for exporting novel content as a single `.epub` file.
7
- """
8
-
9
- from __future__ import annotations
10
-
11
- from pathlib import Path
12
- from typing import TYPE_CHECKING
13
-
14
- from novel_downloader.core.exporters.epub_util import (
15
- build_epub_chapter,
16
- download_cover,
17
- finalize_export,
18
- inline_remote_images,
19
- prepare_builder,
20
- remove_all_images,
21
- )
22
- from novel_downloader.utils import (
23
- download,
24
- get_cleaner,
25
- )
26
- from novel_downloader.utils.constants import DEFAULT_IMAGE_SUFFIX
27
- from novel_downloader.utils.epub import (
28
- Chapter,
29
- Volume,
30
- )
31
-
32
- if TYPE_CHECKING:
33
- from .main_exporter import CommonExporter
34
-
35
-
36
- def common_export_as_epub(
37
- exporter: CommonExporter,
38
- book_id: str,
39
- ) -> Path | None:
40
- """
41
- Export a single novel (identified by `book_id`) to an EPUB file.
42
-
43
- This function will:
44
- 1. Load `book_info.json` for metadata.
45
- 2. Generate introductory HTML and optionally include the cover image.
46
- 3. Initialize the EPUB container.
47
- 4. Iterate through volumes and chapters in volume-batches, convert each to XHTML.
48
- 5. Assemble the spine, TOC, CSS and write out the final `.epub`.
49
-
50
- :param exporter: The exporter instance, carrying config and path info.
51
- :param book_id: Identifier of the novel (used as subdirectory name).
52
- """
53
- TAG = "[exporter]"
54
- config = exporter._config
55
-
56
- raw_base = exporter._raw_data_dir / book_id
57
- img_dir = raw_base / "images"
58
- out_dir = exporter.output_dir
59
-
60
- img_dir.mkdir(parents=True, exist_ok=True)
61
- out_dir.mkdir(parents=True, exist_ok=True)
62
-
63
- cleaner = get_cleaner(
64
- enabled=config.clean_text,
65
- config=config.cleaner_cfg,
66
- )
67
-
68
- # --- Load book_info.json ---
69
- book_info = exporter._load_book_info(book_id)
70
- if not book_info:
71
- return None
72
-
73
- book_name = book_info.get("book_name", book_id)
74
- book_author = book_info.get("author", "")
75
-
76
- exporter.logger.info(
77
- "%s Starting EPUB generation: %s (ID: %s)", TAG, book_name, book_id
78
- )
79
-
80
- cover_path = download_cover(
81
- book_info.get("cover_url", ""),
82
- raw_base,
83
- config.include_cover,
84
- exporter.logger,
85
- TAG,
86
- )
87
-
88
- # --- Initialize EPUB ---
89
- book, main_css = prepare_builder(
90
- site_name=exporter.site,
91
- book_id=book_id,
92
- title=book_name,
93
- author=book_author,
94
- description=book_info.get("summary", ""),
95
- subject=book_info.get("tags", []),
96
- serial_status=book_info.get("serial_status", ""),
97
- word_count=book_info.get("word_count", ""),
98
- cover_path=cover_path,
99
- )
100
-
101
- # --- Compile chapters ---
102
- volumes = book_info.get("volumes", [])
103
- if not volumes:
104
- exporter.logger.warning("%s No volumes found in metadata.", TAG)
105
-
106
- for vol_index, vol in enumerate(volumes, start=1):
107
- raw_name = vol.get("volume_name", "")
108
- raw_name = cleaner.clean_title(raw_name.replace(book_name, ""))
109
- vol_name = raw_name or f"Volume {vol_index}"
110
- exporter.logger.info("%s Processing volume %d: %s", TAG, vol_index, vol_name)
111
-
112
- # Batch-fetch chapters for this volume
113
- chap_ids = [
114
- chap["chapterId"]
115
- for chap in vol.get("chapters", [])
116
- if chap.get("chapterId")
117
- ]
118
- chap_map = exporter._get_chapters(book_id, chap_ids)
119
-
120
- vol_cover: Path | None = None
121
- vol_cover_url = vol.get("volume_cover", "")
122
- if vol_cover_url:
123
- vol_cover = download(
124
- vol_cover_url,
125
- img_dir,
126
- on_exist="skip",
127
- default_suffix=DEFAULT_IMAGE_SUFFIX,
128
- )
129
-
130
- curr_vol = Volume(
131
- id=f"vol_{vol_index}",
132
- title=vol_name,
133
- intro=cleaner.clean_content(vol.get("volume_intro", "")),
134
- cover=vol_cover,
135
- )
136
-
137
- for chap_meta in vol.get("chapters", []):
138
- chap_id = chap_meta.get("chapterId")
139
- if not chap_id:
140
- exporter.logger.warning(
141
- "%s Missing chapterId, skipping: %s",
142
- TAG,
143
- chap_meta,
144
- )
145
- continue
146
-
147
- chap_title = chap_meta.get("title", "")
148
- data = chap_map.get(chap_id)
149
- if not data:
150
- exporter.logger.info(
151
- "%s Missing chapter: %s (%s), skipping.",
152
- TAG,
153
- chap_title,
154
- chap_id,
155
- )
156
- continue
157
-
158
- title = cleaner.clean_title(data.get("title", chap_title)) or chap_id
159
- content = cleaner.clean_content(data.get("content", ""))
160
- extra = data.get("extra", {})
161
- author_note = cleaner.clean_content(extra.get("author_say", ""))
162
- content = (
163
- inline_remote_images(book, content, img_dir)
164
- if config.include_picture
165
- else remove_all_images(content)
166
- )
167
- extras = {"作者说": author_note} if author_note else {}
168
-
169
- chap_html = build_epub_chapter(
170
- title=title,
171
- paragraphs=content,
172
- extras=extras,
173
- )
174
- curr_vol.chapters.append(
175
- Chapter(
176
- id=f"c_{chap_id}",
177
- filename=f"c{chap_id}.xhtml",
178
- title=title,
179
- content=chap_html,
180
- css=[main_css],
181
- )
182
- )
183
-
184
- book.add_volume(curr_vol)
185
-
186
- # --- 5. Finalize EPUB ---
187
- out_name = exporter.get_filename(
188
- title=book_name,
189
- author=book_info.get("author"),
190
- ext="epub",
191
- )
192
- return finalize_export(
193
- book=book,
194
- out_dir=out_dir,
195
- filename=out_name,
196
- logger=exporter.logger,
197
- tag=TAG,
198
- )
@@ -1,64 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.common.main_exporter
4
- ----------------------------------------------------
5
-
6
- Common exporter implementation for saving novels as TXT and EPUB files.
7
- """
8
-
9
- from pathlib import Path
10
-
11
- from novel_downloader.core.exporters.base import BaseExporter
12
-
13
- from .epub import common_export_as_epub
14
- from .txt import common_export_as_txt
15
-
16
-
17
- class CommonExporter(BaseExporter):
18
- """
19
- CommonExporter is a exporter that processes and exports novels.
20
-
21
- It extends the BaseExporter interface and provides
22
- logic for exporting full novels as plain text (.txt) files
23
- and EPUB (.epub) files.
24
- """
25
-
26
- def export_as_txt(self, book_id: str) -> Path | None:
27
- """
28
- Compile and export a complete novel as a single .txt file.
29
-
30
- Processing steps:
31
- 1. Load book metadata from `book_info.json`, including title,
32
- author, summary, and chapter structure.
33
- 2. Iterate through all volumes and chapters, appending each
34
- volume/chapter title and content.
35
- 3. Combine metadata and content into a final formatted text.
36
- 4. Save the final result to the output directory using the
37
- configured filename template.
38
-
39
- :param book_id: The book identifier (used to locate raw data)
40
- """
41
- book_id = self._normalize_book_id(book_id)
42
- self._init_chapter_storages(book_id)
43
- return common_export_as_txt(self, book_id)
44
-
45
- def export_as_epub(self, book_id: str) -> Path | None:
46
- """
47
- Persist the assembled book as a EPUB (.epub) file.
48
-
49
- :param book_id: The book identifier.
50
- :raises NotImplementedError: If the method is not overridden.
51
- """
52
- book_id = self._normalize_book_id(book_id)
53
- self._init_chapter_storages(book_id)
54
- return common_export_as_epub(self, book_id)
55
-
56
- @staticmethod
57
- def _normalize_book_id(book_id: str) -> str:
58
- """
59
- Normalize a book identifier.
60
-
61
- Subclasses may override this method to transform the book ID
62
- into their preferred format.
63
- """
64
- return book_id.replace("/", "-")