novel-downloader 1.4.1__py3-none-any.whl → 1.4.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 (29) hide show
  1. novel_downloader/__init__.py +1 -1
  2. novel_downloader/cli/download.py +69 -10
  3. novel_downloader/config/adapter.py +42 -9
  4. novel_downloader/core/downloaders/base.py +26 -22
  5. novel_downloader/core/downloaders/common.py +41 -5
  6. novel_downloader/core/downloaders/qidian.py +60 -32
  7. novel_downloader/core/exporters/common/epub.py +153 -68
  8. novel_downloader/core/exporters/epub_util.py +1358 -0
  9. novel_downloader/core/exporters/linovelib/epub.py +147 -190
  10. novel_downloader/core/fetchers/qidian/browser.py +62 -10
  11. novel_downloader/core/interfaces/downloader.py +13 -12
  12. novel_downloader/locales/en.json +2 -0
  13. novel_downloader/locales/zh.json +2 -0
  14. novel_downloader/models/__init__.py +2 -0
  15. novel_downloader/models/config.py +8 -0
  16. novel_downloader/tui/screens/home.py +5 -4
  17. novel_downloader/utils/constants.py +0 -29
  18. {novel_downloader-1.4.1.dist-info → novel_downloader-1.4.2.dist-info}/METADATA +4 -2
  19. {novel_downloader-1.4.1.dist-info → novel_downloader-1.4.2.dist-info}/RECORD +23 -28
  20. novel_downloader/core/exporters/epub_utils/__init__.py +0 -40
  21. novel_downloader/core/exporters/epub_utils/css_builder.py +0 -75
  22. novel_downloader/core/exporters/epub_utils/image_loader.py +0 -131
  23. novel_downloader/core/exporters/epub_utils/initializer.py +0 -100
  24. novel_downloader/core/exporters/epub_utils/text_to_html.py +0 -178
  25. novel_downloader/core/exporters/epub_utils/volume_intro.py +0 -60
  26. {novel_downloader-1.4.1.dist-info → novel_downloader-1.4.2.dist-info}/WHEEL +0 -0
  27. {novel_downloader-1.4.1.dist-info → novel_downloader-1.4.2.dist-info}/entry_points.txt +0 -0
  28. {novel_downloader-1.4.1.dist-info → novel_downloader-1.4.2.dist-info}/licenses/LICENSE +0 -0
  29. {novel_downloader-1.4.1.dist-info → novel_downloader-1.4.2.dist-info}/top_level.txt +0 -0
@@ -17,6 +17,7 @@ strongly typed Python objects for safer and cleaner access.
17
17
  """
18
18
 
19
19
  from dataclasses import dataclass
20
+ from typing import NotRequired, TypedDict
20
21
 
21
22
  from .types import (
22
23
  BrowserType,
@@ -98,3 +99,10 @@ class ExporterConfig:
98
99
  include_toc: bool = False
99
100
  include_picture: bool = False
100
101
  split_mode: SplitMode = "book"
102
+
103
+
104
+ class BookConfig(TypedDict):
105
+ book_id: str
106
+ start_id: NotRequired[str]
107
+ end_id: NotRequired[str]
108
+ ignore_ids: NotRequired[list[str]]
@@ -106,12 +106,12 @@ class HomeScreen(Screen): # type: ignore[misc]
106
106
  self,
107
107
  adapter: ConfigAdapter,
108
108
  site: str,
109
- valid_book_ids: set[str],
109
+ book_ids: set[str],
110
110
  ) -> None:
111
111
  btn = self.query_one("#download", Button)
112
112
  btn.disabled = True
113
113
  try:
114
- logging.info(f"下载请求: {site} | {valid_book_ids}")
114
+ logging.info(f"下载请求: {site} | {book_ids}")
115
115
  downloader_cfg = adapter.get_downloader_config()
116
116
  fetcher_cfg = adapter.get_fetcher_config()
117
117
  parser_cfg = adapter.get_parser_config()
@@ -139,10 +139,11 @@ class HomeScreen(Screen): # type: ignore[misc]
139
139
  config=downloader_cfg,
140
140
  )
141
141
 
142
- for book_id in valid_book_ids:
142
+ for book_id in book_ids:
143
143
  logging.info(t("download_downloading", book_id=book_id, site=site))
144
144
  await downloader.download(
145
- book_id, progress_hook=self._update_progress
145
+ {"book_id": book_id},
146
+ progress_hook=self._update_progress,
146
147
  )
147
148
 
148
149
  if downloader_cfg.login_required and fetcher.is_logged_in:
@@ -116,35 +116,6 @@ QD_DECRYPT_SCRIPT_PATH = files("novel_downloader.resources.js_scripts").joinpath
116
116
  # Text Files
117
117
  BLACKLIST_PATH = files("novel_downloader.resources.text").joinpath("blacklist.txt")
118
118
 
119
- # -----------------------------------------------------------------------------
120
- # EPUB defaults
121
- # -----------------------------------------------------------------------------
122
- EPUB_IMAGE_FOLDER = "Images"
123
- EPUB_TEXT_FOLDER = "Text"
124
-
125
- EPUB_IMAGE_WRAPPER = (
126
- '<div class="duokan-image-single illus"><img src="../Images/{filename}" /></div>'
127
- )
128
-
129
- EPUB_OPTIONS = {
130
- # guide 是 EPUB 2 的一个部分, 包含封面, 目录, 索引等重要导航信息
131
- "epub2_guide": True,
132
- # landmark 是 EPUB 3 用来标识重要页面 (如目录, 封面, 起始页) 的 <nav> 结构
133
- "epub3_landmark": True,
134
- # EPUB 3 允许提供一个 page list, 让电子书在不同设备上仍然保持相对一致的分页结构
135
- "epub3_pages": True,
136
- # 这个名字会出现在 EPUB 阅读器的导航栏
137
- "landmark_title": "Guide",
138
- # 这个名字会显示在 EPUB 阅读器的分页导航栏
139
- "pages_title": "Pages",
140
- # 是否根据 book.spine 的排列顺序自动设置 EPUB 阅读器的 page-progression-direction
141
- "spine_direction": True,
142
- # 控制 EPUB 阅读器的默认翻页方向 (LTR 或 RTL)
143
- "package_direction": False,
144
- # 是否为 EPUB 书籍中的章节 添加播放顺序
145
- "play_order": {"enabled": True, "start_from": 1},
146
- }
147
-
148
119
  # ---------------------------------------------------------------------
149
120
  # Pretrained model registry (e.g. used in font recovery or OCR)
150
121
  # ---------------------------------------------------------------------
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: novel-downloader
3
- Version: 1.4.1
3
+ Version: 1.4.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
@@ -46,7 +46,6 @@ Requires-Dist: aiohttp
46
46
  Requires-Dist: playwright
47
47
  Requires-Dist: lxml
48
48
  Requires-Dist: platformdirs
49
- Requires-Dist: ebooklib
50
49
  Provides-Extra: dev
51
50
  Requires-Dist: black; extra == "dev"
52
51
  Requires-Dist: mypy; extra == "dev"
@@ -55,6 +54,7 @@ Requires-Dist: pytest; extra == "dev"
55
54
  Requires-Dist: pytest-cov; extra == "dev"
56
55
  Requires-Dist: pytest-mock; extra == "dev"
57
56
  Requires-Dist: types-requests; extra == "dev"
57
+ Requires-Dist: types-lxml; extra == "dev"
58
58
  Requires-Dist: types-PyYAML; extra == "dev"
59
59
  Requires-Dist: pre-commit; extra == "dev"
60
60
  Requires-Dist: commitizen; extra == "dev"
@@ -109,6 +109,8 @@ playwright install
109
109
  pip install novel-downloader[font-recovery]
110
110
  ```
111
111
 
112
+ - 详细可见: [安装](https://github.com/BowenZ217/novel-downloader/blob/main/docs/1-installation.md)
113
+
112
114
  ---
113
115
 
114
116
  ### CLI 模式
@@ -1,45 +1,40 @@
1
- novel_downloader/__init__.py,sha256=nUZvGoS76c8un9BEm7XCbBulkgbGiFZCB87m7L_8gC8,218
1
+ novel_downloader/__init__.py,sha256=qYZxJQ-xYLPTjMwE7FYcQM5HYV9Oo_bqCJY55hAqlcE,218
2
2
  novel_downloader/cli/__init__.py,sha256=-2HAut_U1e67MZGdvbpEJ1n5J-bRchzto6L4c-nWeXY,174
3
3
  novel_downloader/cli/clean.py,sha256=hOk8SJQwBCw2oOObTdEI79wpnmZ25uB1s9LQK1-4LNU,4487
4
4
  novel_downloader/cli/config.py,sha256=C6QLfegZLp4legmu8KenqyYKNdrk47bH0z86ujLP0pY,6509
5
- novel_downloader/cli/download.py,sha256=HKCxufqnj4vDzCdM7soH_Y_eiVNRGpV17Mz08ADYwqQ,5279
5
+ novel_downloader/cli/download.py,sha256=ff2KMsa9XnbsF_aUQcAc7a06hDYmk4-7yMv4iiXTWlI,6762
6
6
  novel_downloader/cli/export.py,sha256=x9uvyLuvkuaDZGoH212aHZ7XyPT9b2S78AmTN6rkAu4,2283
7
7
  novel_downloader/cli/main.py,sha256=9J8KMuYwL01X6chIaXpQNeS5d3pHnwB9vA9XjKd8RrM,919
8
8
  novel_downloader/config/__init__.py,sha256=2mnf33MQOUnLGCnL1NtNV_rHBejNxBNIbobIGN0tw4E,666
9
- novel_downloader/config/adapter.py,sha256=UYtDlpKFcKmvBBN9ZOI3W7u0a72Fhrpk-DkZmKoKpqk,7281
9
+ novel_downloader/config/adapter.py,sha256=hPRAomAlqhyUlNemm82e4m0SAYa33woulb5ePHMRC3o,8330
10
10
  novel_downloader/config/loader.py,sha256=jo_1rr3UKZRAFFYgO-oHpYLRhF431chmfx4fLGh0MKw,5743
11
11
  novel_downloader/config/site_rules.py,sha256=CJksBSvVAC4sR6cEruf4pM1Jv0zTJb1lcHq0Yn6LPFM,2979
12
12
  novel_downloader/core/__init__.py,sha256=zzrXjQfBUhfLmBD_95oHTjtTsR81NSRtHcxpYBxQlZ4,654
13
13
  novel_downloader/core/downloaders/__init__.py,sha256=AK5zeetVXOn_irgHp-NORPYW65UJM4CsF8ysxf2vKD4,1064
14
- novel_downloader/core/downloaders/base.py,sha256=H3Y9NnSv4lQA6ilKCd7HqAX24R79wXBMkLG5StK8znc,6420
14
+ novel_downloader/core/downloaders/base.py,sha256=h2Y73o9OC8URvlnNNQgwNVx4kk4oqFjk2AsyfmAfshg,6706
15
15
  novel_downloader/core/downloaders/biquge.py,sha256=PTm8eeaHVyw_nvtnuRpZ2hT7hLs2LEPV1Drd2O6idNM,651
16
- novel_downloader/core/downloaders/common.py,sha256=1YNo-e5tuK5bGvuzX3eVmEJznD7f5JMo7a_abIdmEkM,15504
16
+ novel_downloader/core/downloaders/common.py,sha256=-3lp6lLoCubVwqMA4lx6YtnSmKPMA85T1K5m0_vizmg,16323
17
17
  novel_downloader/core/downloaders/esjzone.py,sha256=GBFJ3fIPov483QxkOTaKBU2wd2f8T4GdvzSbRaU9hDI,655
18
18
  novel_downloader/core/downloaders/linovelib.py,sha256=Cd43_70SKbKM8_C8c4qev3pLUgyziW9413qrA8EcStY,663
19
19
  novel_downloader/core/downloaders/qianbi.py,sha256=ARuk1xABOGCjlD_ct5hOKMgWloU187rUJBbICJ2yvkY,651
20
- novel_downloader/core/downloaders/qidian.py,sha256=YrX5HdJDopEjc1kvEJRjMc1S4iR049IGvzUNtgE-LPE,12590
20
+ novel_downloader/core/downloaders/qidian.py,sha256=PkUnOEq1TyKZea--b8nBgFqrhxD0UK8X4m9AUC_wFjk,13135
21
21
  novel_downloader/core/downloaders/sfacg.py,sha256=ShlkIIR6OW_x2FhNDi79S_3AL2CWId2upQmRkApee_E,647
22
22
  novel_downloader/core/downloaders/yamibo.py,sha256=9L0m5Zq0o1y44tCQ4ZRHHqdO3YresJkRAVvCtsQwouk,651
23
23
  novel_downloader/core/exporters/__init__.py,sha256=ATkkdh6RUIaM19mG1XjFiaMnGRgFFGT3ixsqVkU13Q0,867
24
24
  novel_downloader/core/exporters/base.py,sha256=duIdLnj9kKNZ9r2aJV0Rzl-rnQCP8olk12uzduT9PtE,6146
25
25
  novel_downloader/core/exporters/biquge.py,sha256=SJCChYtDLJKrOpwDCT8IeR0v1LoiUQuTTejfGmRnxX8,462
26
+ novel_downloader/core/exporters/epub_util.py,sha256=uSMB_55v6xKJcKyFjJZghl0ZgCFsdGbJJHH22G-BkeQ,37377
26
27
  novel_downloader/core/exporters/esjzone.py,sha256=UP9gtTOv6komWjgvwXkttqDYJJPjjbJdiG3yz9RxHSQ,467
27
28
  novel_downloader/core/exporters/qianbi.py,sha256=x841MNIxpS5eY8u91ODC0cpIhpT-ENnFqs_Yx6HwtdM,462
28
29
  novel_downloader/core/exporters/qidian.py,sha256=ecaZcgqXyLvJtT2J5QXw4qS9gY3d72mgUnV-0frJvhQ,724
29
30
  novel_downloader/core/exporters/sfacg.py,sha256=j4_H-ixvDxd_OJfIvD4Lbs24LaiFjaYqhvhZcks-ItI,457
30
31
  novel_downloader/core/exporters/yamibo.py,sha256=QaY13llqpyxIgmMnMVFtR5yFMIpyMHHdCmVDW4Dq-bo,462
31
32
  novel_downloader/core/exporters/common/__init__.py,sha256=qIOZ_TgnnQZ6p45YQsxpTcB69e0Jq9XMG3IY0NBVsTM,274
32
- novel_downloader/core/exporters/common/epub.py,sha256=1BhaZCZLehX-v8Z7spatyizhHoMfCF08ZfZGpPfB5Kw,6331
33
+ novel_downloader/core/exporters/common/epub.py,sha256=_hFoc3aVRf7xxrWCvukN7Iv5ulYbkSq53nQMfaZb75E,8833
33
34
  novel_downloader/core/exporters/common/main_exporter.py,sha256=-MRZEpAdsfdRt3VxIv4krMaw2UJnrvCnyj5Jde93zuA,3926
34
35
  novel_downloader/core/exporters/common/txt.py,sha256=b5cNvH0hrjaBO89Uddn1IUY1BFhkHJdTd7WjSWk4ndk,4719
35
- novel_downloader/core/exporters/epub_utils/__init__.py,sha256=cPtuQDtuJZPgOHRf_T5sgkQE13jZnOyPoK9hHJeMEEo,993
36
- novel_downloader/core/exporters/epub_utils/css_builder.py,sha256=qvVgHnyoILgqSUoVsHv-cHzIdtfsqxA8WHt9_89puic,2145
37
- novel_downloader/core/exporters/epub_utils/image_loader.py,sha256=hbxoPvXkBIZnoZSIlHwIUx4zWR8QVppWiH1KotMrBXg,3953
38
- novel_downloader/core/exporters/epub_utils/initializer.py,sha256=TGueFff1ydRLdJYBEJnqIkoVCV57ZiR3dGu_c5Hrp8g,3364
39
- novel_downloader/core/exporters/epub_utils/text_to_html.py,sha256=VSYbm33PrwxFmcT-2f_U2j3kuHzdcSMR7PRqOWvZICU,5617
40
- novel_downloader/core/exporters/epub_utils/volume_intro.py,sha256=cwHMVwJeK8TzXnOw4MYWXvbZGt4iWFjdesDm4n_V-Tk,1830
41
36
  novel_downloader/core/exporters/linovelib/__init__.py,sha256=zD7A7OhluipwICssnp27c_oenYozevZH9g0Qj5WOMWY,195
42
- novel_downloader/core/exporters/linovelib/epub.py,sha256=wxfNxOX6kxSaove-YlDlNw1cmsBJFwysk6bS6Gsk8Cw,14503
37
+ novel_downloader/core/exporters/linovelib/epub.py,sha256=yVqv-lnc7Nh-COd4POvQ0vbsAw18NJ8oFO88-zKedb4,13048
43
38
  novel_downloader/core/exporters/linovelib/main_exporter.py,sha256=cHkAp_jdF6uji5Avu1l8z6mR0nSrWYgX6ETDEezkjoE,3700
44
39
  novel_downloader/core/exporters/linovelib/txt.py,sha256=ALlZUl5nNtg4OmYlurMC0acjmTOBV7G8c13DPrxbG4w,4407
45
40
  novel_downloader/core/factory/__init__.py,sha256=_IY3N35onhWD_nw_TyxKOxa6e7Uak9Cv0bp4pK9yb0M,464
@@ -68,7 +63,7 @@ novel_downloader/core/fetchers/qianbi/__init__.py,sha256=h4Rve7fO1GcSJ-DlNC5zw7f
68
63
  novel_downloader/core/fetchers/qianbi/browser.py,sha256=1EmrSwpqSYhEO_ID3RJbUaAOhcqvVnMnch6iOafXbTA,3162
69
64
  novel_downloader/core/fetchers/qianbi/session.py,sha256=c3pJcgi9C1x9QYTBihvazHcgT7XTp2HBYfStTn6gSEg,3141
70
65
  novel_downloader/core/fetchers/qidian/__init__.py,sha256=2LshlX82lFpWZMV6yujHsfue9KM0-F1O3HvMCopIv9M,236
71
- novel_downloader/core/fetchers/qidian/browser.py,sha256=JuFncpirI4HLyfIkR0xZmHL6AZZy7tQOzkzsC24b9ss,8578
66
+ novel_downloader/core/fetchers/qidian/browser.py,sha256=cUgJMrFe_MITHh4MGrDI2-a-MCqXSsoeJsbDus0l2LY,10448
72
67
  novel_downloader/core/fetchers/qidian/session.py,sha256=WrHsov15PoRDYbb1ZRaScJQGRZv6axz9_hVEC1Wt1PM,9746
73
68
  novel_downloader/core/fetchers/sfacg/__init__.py,sha256=bQAIwERsX9XOKrP2LteFKX8Jlhw4oeUNwpZTHXn5RRg,230
74
69
  novel_downloader/core/fetchers/sfacg/browser.py,sha256=15PVS75PxEKR5W7mQbqVxoN0d4V1XVYVF0l1yy_sv_Y,5681
@@ -77,7 +72,7 @@ novel_downloader/core/fetchers/yamibo/__init__.py,sha256=5ds6DNNvpo6F6U5dboEaIsJ
77
72
  novel_downloader/core/fetchers/yamibo/browser.py,sha256=7YRrWbA8_cOcT_z-VjMWP6FUg30TwV6eLW4zJZ_UxSE,7249
78
73
  novel_downloader/core/fetchers/yamibo/session.py,sha256=434EArdKgEYIBZkb1nMub3PQXdRTS-Ov2_1u9MESjOs,7212
79
74
  novel_downloader/core/interfaces/__init__.py,sha256=hB1SjBzuN7qnZx_h3RV4w_roj3ZwShbIG3CV9jGMB14,602
80
- novel_downloader/core/interfaces/downloader.py,sha256=XozFf-7OOtBQDlWNs3IRcBjwTPGFWwseFLGta-sZZmU,1560
75
+ novel_downloader/core/interfaces/downloader.py,sha256=H0S4o5MW22JcvNVECv1bCdwAN0drBwHY31IbvVHn-X0,1557
81
76
  novel_downloader/core/interfaces/exporter.py,sha256=zwIaJ5FXo_JmKYg2UZV9FTWX7xZ2e0QuL4RTNGRtI04,1610
82
77
  novel_downloader/core/interfaces/fetcher.py,sha256=XlP3d-Q_xvuVextZCdLOxDf8BwBbx799L_WLJx0WTB8,4096
83
78
  novel_downloader/core/interfaces/parser.py,sha256=iZeUgNl-zE-wsf1eW4GVCPjEaLSvQrNJi_mVEOU9ulY,1353
@@ -108,12 +103,12 @@ novel_downloader/core/parsers/sfacg/__init__.py,sha256=O2nscvtOweMXHMONdvySTsLSy
108
103
  novel_downloader/core/parsers/sfacg/main_parser.py,sha256=yW18MALAZisJdFO-7peI1h-4XVloEDXeCJvXUz5hJ1A,5899
109
104
  novel_downloader/core/parsers/yamibo/__init__.py,sha256=KJ_fCcakoQrsG36OOd0paXXB1cAIwMirKaA8ZLUKUKI,173
110
105
  novel_downloader/core/parsers/yamibo/main_parser.py,sha256=9sNXsDR2iDVyTYupP_7PyE7BXf2po3sZLq1XEFA8DrI,6554
111
- novel_downloader/locales/en.json,sha256=-bKxndkwJCTCt7ZZGRRKzNaulC7z8XB6Tu7T1SR-1S8,6840
112
- novel_downloader/locales/zh.json,sha256=xzbUsKtkdQvQkehTgIURlQMPepOSWbQBgzTJ4SSJNZc,6699
113
- novel_downloader/models/__init__.py,sha256=G5fYGdaFquJBcllFJ7-YgqkvP4vD3xVEI9MeYcrCr_s,1068
106
+ novel_downloader/locales/en.json,sha256=mcGv24zHS2FFimwCYRLMD8CYzAzngTv1tODZP64GWvY,7002
107
+ novel_downloader/locales/zh.json,sha256=7kkKGt1fudSC9LvmFyAgXfyCC512XfCoyf5by8Egqnc,6849
108
+ novel_downloader/models/__init__.py,sha256=5aQ24IeU8OJDhBZdZ8Ov-xWoLlZm6Qg24r5FPyLTa6Q,1102
114
109
  novel_downloader/models/browser.py,sha256=ly-jM7izQ77yTIG-oau51HJofDpBfrXpIJZJjoQyad8,435
115
110
  novel_downloader/models/chapter.py,sha256=bdAQUDZIuuTVxoYjoOJrbS2u81b1B2mkuZkTSf0m2HQ,492
116
- novel_downloader/models/config.py,sha256=d5G8sob9oNA8rr1N7BvDEJRVSCKJUtD_QBcvWZvGMyw,2792
111
+ novel_downloader/models/config.py,sha256=fYExgkyylDuCUUW8nTFQLBX2rotiumvKV6uMZF1G5Ig,2981
117
112
  novel_downloader/models/login.py,sha256=sY2Jom6PLpA9Z3Uy7plZKhda3Gq7awKOOIIaQ79PpWs,371
118
113
  novel_downloader/models/site_rules.py,sha256=kzDB5F8lf4udAO0WVUrgBOR7ave3jsMBxt7cEoG0bnI,2721
119
114
  novel_downloader/models/tasks.py,sha256=e4DYEXQQQewgQyCCHfc0UYnkPJ96LafmhG3oO5MQP0Q,465
@@ -130,14 +125,14 @@ novel_downloader/tui/__init__.py,sha256=8RB8tBrPcoBzm1tpQlgZqnOZXrdHmlzMRxuk9wsN
130
125
  novel_downloader/tui/app.py,sha256=ytV1u15nGCRj_ff_GeAL3W1XlU6r5Lh_k3HBcAjPRx0,731
131
126
  novel_downloader/tui/main.py,sha256=MBP8SrwEYTpGQm-V9W_4rKnTeslneORfkzFsU3Xj2yA,256
132
127
  novel_downloader/tui/screens/__init__.py,sha256=QsUM5cUEKm7nluQh9acEt37xRWbkZU3vqIpBduepDCU,203
133
- novel_downloader/tui/screens/home.py,sha256=ximy5vwHGrkUD88U6Gr9h3kT-wtOMMLBzB9aEZPuA5w,6716
128
+ novel_downloader/tui/screens/home.py,sha256=izxzn9Aru_fzenEKI9sOY1FNhyWky9zgzv7GVUMoW_8,6736
134
129
  novel_downloader/tui/screens/login.py,sha256=eEVmQFZKQX8mCt_qp96QK8t2pB15FeUrk_oV3jm_Mz4,2224
135
130
  novel_downloader/tui/styles/home_layout.tcss,sha256=VNJs339qiwNUuqwwdK6VkYThCdsqlw-2mEoZVCspdrw,974
136
131
  novel_downloader/tui/widgets/richlog_handler.py,sha256=bhFb0E7Z7-dRS07y_vMjxjPeCic9AD59MFPLhef_R5g,572
137
132
  novel_downloader/utils/__init__.py,sha256=4iUXNUzxeAnGmpGWsB4K_jckUYEW0u_LqWp_OM7mtK8,78
138
133
  novel_downloader/utils/cache.py,sha256=_jVEWAaMGY86kWVnAuuIvJA_hA8dH2ClI7o3p99mEvE,618
139
134
  novel_downloader/utils/chapter_storage.py,sha256=wXXIzNjs1GfPPoqgYYPnQ9Two23McW6ZZNDmhfSC9aY,9831
140
- novel_downloader/utils/constants.py,sha256=1emMOmGRuat0yX8ozZMM1pAUGdU0kYBhDVNW_6dDtps,5700
135
+ novel_downloader/utils/constants.py,sha256=EaxQllQ_dIce5_eRTgAJ-OXRtEk3cMhLUbOKA359198,4435
141
136
  novel_downloader/utils/cookies.py,sha256=WuPBt_z7cF4n7QPIw1julATWt6dbDRCbNdgXHSikmjo,2042
142
137
  novel_downloader/utils/crypto_utils.py,sha256=BRlVR9Nvbu8TQXocJb3po1-kD5HkbCV0yyT84nq_XtI,2052
143
138
  novel_downloader/utils/hash_store.py,sha256=HfzthzcKbHbVaHNpqjaAs2wDeq7iIeY8Mzkt_4v80jQ,9388
@@ -162,9 +157,9 @@ novel_downloader/utils/text_utils/text_cleaning.py,sha256=_Nahr8iv3341IyDXW-KpTn
162
157
  novel_downloader/utils/time_utils/__init__.py,sha256=725vY2PvqFhjbAz0hCOuIuhSCK8HrEqQ_k3YwvubmXo,624
163
158
  novel_downloader/utils/time_utils/datetime_utils.py,sha256=1eyX8lTEqkQ-rEej_GrhbUpaIR5tsFdVSKT-q8s9X-g,4927
164
159
  novel_downloader/utils/time_utils/sleep_utils.py,sha256=C4XYeAtxoVZC9Ju6vhhP9sbOrSpdZG2Nm-x1IYO_OFA,3233
165
- novel_downloader-1.4.1.dist-info/licenses/LICENSE,sha256=XgmnH0mBf-qEiizoVAfJQAKzPB9y3rBa-ni7M0Aqv4A,1066
166
- novel_downloader-1.4.1.dist-info/METADATA,sha256=ZhGsQDAL7bnxkiKs8lUsToC24ueLKshwK0e2KImvduU,7027
167
- novel_downloader-1.4.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
168
- novel_downloader-1.4.1.dist-info/entry_points.txt,sha256=u1Ns5xI_QJyL4HAFCgJvJdib9ugu7M9I2tnQwZjJxrk,112
169
- novel_downloader-1.4.1.dist-info/top_level.txt,sha256=hP4jYWM2LTm1jxsW4hqEB8N0dsRvldO2QdhggJT917I,17
170
- novel_downloader-1.4.1.dist-info/RECORD,,
160
+ novel_downloader-1.4.2.dist-info/licenses/LICENSE,sha256=XgmnH0mBf-qEiizoVAfJQAKzPB9y3rBa-ni7M0Aqv4A,1066
161
+ novel_downloader-1.4.2.dist-info/METADATA,sha256=ogSqUunbmTtsABDdShe_XYxGYLPqyvGnmwKyuAJ82bI,7151
162
+ novel_downloader-1.4.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
163
+ novel_downloader-1.4.2.dist-info/entry_points.txt,sha256=u1Ns5xI_QJyL4HAFCgJvJdib9ugu7M9I2tnQwZjJxrk,112
164
+ novel_downloader-1.4.2.dist-info/top_level.txt,sha256=hP4jYWM2LTm1jxsW4hqEB8N0dsRvldO2QdhggJT917I,17
165
+ novel_downloader-1.4.2.dist-info/RECORD,,
@@ -1,40 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.epub_utils
4
- ------------------------------------------
5
-
6
- This package provides utility functions for constructing EPUB files,
7
- including:
8
-
9
- - CSS inclusion (css_builder)
10
- - Image embedding (image_loader)
11
- - EPUB book initialization (initializer)
12
- - Chapter text-to-HTML conversion (text_to_html)
13
- - Volume intro HTML generation (volume_intro)
14
- """
15
-
16
- from .css_builder import create_css_items
17
- from .image_loader import (
18
- add_images_from_dir,
19
- add_images_from_dirs,
20
- add_images_from_list,
21
- )
22
- from .initializer import init_epub
23
- from .text_to_html import (
24
- chapter_txt_to_html,
25
- generate_book_intro_html,
26
- inline_remote_images,
27
- )
28
- from .volume_intro import create_volume_intro
29
-
30
- __all__ = [
31
- "create_css_items",
32
- "add_images_from_dir",
33
- "add_images_from_dirs",
34
- "add_images_from_list",
35
- "init_epub",
36
- "chapter_txt_to_html",
37
- "create_volume_intro",
38
- "generate_book_intro_html",
39
- "inline_remote_images",
40
- ]
@@ -1,75 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.epub_utils.css_builder
4
- ------------------------------------------------------
5
-
6
- Reads local CSS files and wraps them into epub.EpubItem objects,
7
- returning a list ready to be added to the EPUB.
8
- """
9
-
10
- import logging
11
- from importlib.abc import Traversable
12
- from typing import TypedDict
13
-
14
- from ebooklib import epub
15
-
16
- from novel_downloader.utils.constants import (
17
- CSS_MAIN_PATH,
18
- CSS_VOLUME_INTRO_PATH,
19
- )
20
-
21
- logger = logging.getLogger(__name__)
22
-
23
-
24
- class CssConfig(TypedDict):
25
- include: bool
26
- path: Traversable
27
- uid: str
28
- file_name: str
29
-
30
-
31
- def create_css_items(
32
- include_main: bool = True,
33
- include_volume: bool = True,
34
- ) -> list[epub.EpubItem]:
35
- """
36
- :param include_main: Whether to load the main stylesheet.
37
- :param include_volume: Whether to load the “volume intro” stylesheet.
38
- :returns: A list of epub.EpubItem ready to add to the book.
39
- """
40
- css_config: list[CssConfig] = [
41
- {
42
- "include": include_main,
43
- "path": CSS_MAIN_PATH,
44
- "uid": "style",
45
- "file_name": "Styles/main.css",
46
- },
47
- {
48
- "include": include_volume,
49
- "path": CSS_VOLUME_INTRO_PATH,
50
- "uid": "volume_style",
51
- "file_name": "Styles/volume-intro.css",
52
- },
53
- ]
54
- css_items: list[epub.EpubItem] = []
55
-
56
- for css in css_config:
57
- if css["include"]:
58
- path = css["path"]
59
- try:
60
- content: str = path.read_text(encoding="utf-8")
61
- content_bytes: bytes = content.encode("utf-8")
62
- css_items.append(
63
- epub.EpubItem(
64
- uid=css["uid"],
65
- file_name=css["file_name"],
66
- media_type="text/css",
67
- content=content_bytes,
68
- )
69
- )
70
- except FileNotFoundError:
71
- logger.info(f"[epub] CSS 文件不存在: {css['path']}")
72
- except UnicodeDecodeError:
73
- logger.info(f"[epub] 无法解码文件: {css['path']}")
74
-
75
- return css_items
@@ -1,131 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.epub_utils.image_loader
4
- -------------------------------------------------------
5
-
6
- Utilities for embedding image files into an EpubBook.
7
- """
8
-
9
- import logging
10
- from collections.abc import Iterable, Sequence
11
- from pathlib import Path
12
-
13
- from ebooklib import epub
14
-
15
- from novel_downloader.utils.constants import EPUB_IMAGE_FOLDER
16
-
17
- logger = logging.getLogger(__name__)
18
-
19
- _SUPPORTED_IMAGE_MEDIA_TYPES: dict[str, str] = {
20
- "png": "image/png",
21
- "jpg": "image/jpeg",
22
- "jpeg": "image/jpeg",
23
- "gif": "image/gif",
24
- "svg": "image/svg+xml",
25
- "webp": "image/webp",
26
- }
27
- _DEFAULT_IMAGE_MEDIA_TYPE = "image/jpeg"
28
-
29
-
30
- def add_images_from_list(
31
- book: epub.EpubBook,
32
- image_list: Sequence[str | Path],
33
- ) -> epub.EpubBook:
34
- """
35
- Add a list of image files to the EPUB's image folder.
36
-
37
- :param book: The EpubBook object to modify.
38
- :param image_list: List of paths to image files.
39
- :return: The same EpubBook instance, with images added.
40
- """
41
- for img_path in image_list:
42
- img_path = Path(img_path)
43
- if not img_path.is_file():
44
- continue
45
-
46
- suffix = img_path.suffix.lower().lstrip(".")
47
- media_type = _SUPPORTED_IMAGE_MEDIA_TYPES.get(suffix)
48
- if media_type is None:
49
- media_type = _DEFAULT_IMAGE_MEDIA_TYPE
50
- logger.warning(
51
- "Unknown image suffix '%s' - defaulting media_type to %s",
52
- suffix,
53
- media_type,
54
- )
55
-
56
- try:
57
- content = img_path.read_bytes()
58
- item = epub.EpubItem(
59
- uid=f"img_{img_path.stem}",
60
- file_name=f"{EPUB_IMAGE_FOLDER}/{img_path.name}",
61
- media_type=media_type,
62
- content=content,
63
- )
64
- book.add_item(item)
65
- logger.debug("Embedded image: %s", img_path.name)
66
- except Exception:
67
- logger.exception("Failed to embed image %s", img_path)
68
-
69
- return book
70
-
71
-
72
- def add_images_from_dir(
73
- book: epub.EpubBook,
74
- image_dir: str | Path,
75
- ) -> epub.EpubBook:
76
- """
77
- Load every file in `image_dir` into the EPUB's image folder.
78
-
79
- :param book: The EpubBook object to modify.
80
- :param image_dir: Path to the directory containing image files.
81
- :return: The same EpubBook instance, with images added.
82
- """
83
- image_dir = Path(image_dir)
84
- if not image_dir.is_dir():
85
- logger.warning("Image directory not found or not a directory: %s", image_dir)
86
- return book
87
-
88
- for img_path in image_dir.iterdir():
89
- if not img_path.is_file():
90
- continue
91
-
92
- suffix = img_path.suffix.lower().lstrip(".")
93
- media_type = _SUPPORTED_IMAGE_MEDIA_TYPES.get(suffix)
94
- if media_type is None:
95
- media_type = _DEFAULT_IMAGE_MEDIA_TYPE
96
- logger.warning(
97
- "Unknown image suffix '%s' - defaulting media_type to %s",
98
- suffix,
99
- media_type,
100
- )
101
-
102
- try:
103
- content = img_path.read_bytes()
104
- item = epub.EpubItem(
105
- uid=f"img_{img_path.stem}",
106
- file_name=f"{EPUB_IMAGE_FOLDER}/{img_path.name}",
107
- media_type=media_type,
108
- content=content,
109
- )
110
- book.add_item(item)
111
- logger.debug("Embedded image: %s", img_path.name)
112
- except Exception:
113
- logger.exception("Failed to embed image %s", img_path)
114
-
115
- return book
116
-
117
-
118
- def add_images_from_dirs(
119
- book: epub.EpubBook,
120
- image_dirs: Iterable[str | Path],
121
- ) -> epub.EpubBook:
122
- """
123
- Add all images from multiple directories into the given EpubBook.
124
-
125
- :param book: The EpubBook object to modify.
126
- :param image_dirs: An iterable of directory paths to scan for images.
127
- :return: The same EpubBook instance, with all images added.
128
- """
129
- for img_dir in image_dirs:
130
- book = add_images_from_dir(book, img_dir)
131
- return book
@@ -1,100 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- novel_downloader.core.exporters.epub_utils.initializer
4
- ------------------------------------------------------
5
-
6
- Initializes an epub.EpubBook object, sets metadata
7
- (identifier, title, author, language, description),
8
- adds a cover, and prepares the initial spine and TOC entries.
9
- """
10
-
11
- import logging
12
- from pathlib import Path
13
- from typing import Any
14
-
15
- from ebooklib import epub
16
-
17
- from novel_downloader.utils.constants import (
18
- EPUB_IMAGE_FOLDER,
19
- EPUB_TEXT_FOLDER,
20
- VOLUME_BORDER_IMAGE_PATH,
21
- )
22
-
23
- logger = logging.getLogger(__name__)
24
-
25
-
26
- def init_epub(
27
- book_info: dict[str, Any],
28
- book_id: str,
29
- intro_html: str,
30
- book_cover_path: Path | None = None,
31
- include_toc: bool = False,
32
- ) -> tuple[epub.EpubBook, list[Any], list[Any]]:
33
- """
34
- Initialize an EPUB book with metadata, optional cover, and intro page.
35
-
36
- :param book_info: Dict with keys 'book_name', 'author', 'summary'.
37
- :param book_id: Book identifier (numeric or string).
38
- :param intro_html: Intro content in XHTML format.
39
- :param book_cover_path: Optional Path to the cover image file.
40
- :param include_toc: Whether to include the <nav> item in the spine.
41
- :return: (book, spine, toc_list)
42
- """
43
- book = epub.EpubBook()
44
- book.set_identifier(str(book_id))
45
- book_name = book_info.get("book_name") or book_info.get("volume_name", "未找到书名")
46
- book.set_title(book_name)
47
- book.set_language("zh-CN")
48
- book.add_author(book_info.get("author", "未找到作者"))
49
- desc = book_info.get("summary") or book_info.get("volume_intro", "未找到作品简介")
50
- book.add_metadata("DC", "description", desc)
51
-
52
- spine = []
53
-
54
- # cover
55
- if book_cover_path:
56
- try:
57
- cover_bytes = book_cover_path.read_bytes()
58
- ext = book_cover_path.suffix.lower()
59
- ext = ext if ext in [".jpg", ".jpeg", ".png"] else ".jpeg"
60
- filename = f"{EPUB_IMAGE_FOLDER}/cover{ext}"
61
- book.set_cover(filename, cover_bytes)
62
- spine.append("cover")
63
- except FileNotFoundError:
64
- logger.info(f"[epub] 封面图片不存在: {book_cover_path}")
65
- except Exception as e:
66
- logger.info(f"[epub] 读取封面失败: {book_cover_path},错误:{e}")
67
-
68
- # 导航菜单
69
- if include_toc:
70
- spine.append("nav")
71
-
72
- # 简介页面
73
- intro = epub.EpubHtml(
74
- title="书籍简介",
75
- file_name=f"{EPUB_TEXT_FOLDER}/intro.xhtml",
76
- lang="zh-CN",
77
- uid="intro",
78
- )
79
- intro.content = intro_html
80
- intro.add_link(href="../Styles/main.css", rel="stylesheet", type="text/css")
81
- book.add_item(intro)
82
- spine.append(intro)
83
-
84
- # 添加卷边框图像 (volume_border.png)
85
- try:
86
- border_bytes = VOLUME_BORDER_IMAGE_PATH.read_bytes()
87
- border_item = epub.EpubItem(
88
- uid="volume-border",
89
- file_name=f"{EPUB_IMAGE_FOLDER}/volume_border.png",
90
- media_type="image/png",
91
- content=border_bytes,
92
- )
93
- book.add_item(border_item)
94
- except FileNotFoundError:
95
- logger.info(f"[epub] 卷边框图片不存在: {VOLUME_BORDER_IMAGE_PATH}")
96
- except Exception as e:
97
- logger.info(f"[epub] 读取卷边框失败: {VOLUME_BORDER_IMAGE_PATH}: {e}")
98
-
99
- toc_list = [epub.Link(intro.file_name, "书籍简介", intro.id)]
100
- return book, spine, toc_list