novel-downloader 1.3.3__tar.gz → 1.4.1__tar.gz

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 (250) hide show
  1. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/PKG-INFO +69 -35
  2. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/README.md +61 -29
  3. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/__init__.py +1 -1
  4. novel_downloader-1.4.1/novel_downloader/cli/clean.py +145 -0
  5. novel_downloader-1.4.1/novel_downloader/cli/config.py +177 -0
  6. novel_downloader-1.4.1/novel_downloader/cli/download.py +173 -0
  7. novel_downloader-1.4.1/novel_downloader/cli/export.py +77 -0
  8. novel_downloader-1.4.1/novel_downloader/cli/main.py +36 -0
  9. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/config/__init__.py +1 -25
  10. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/config/adapter.py +32 -31
  11. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/config/loader.py +3 -3
  12. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/config/site_rules.py +1 -2
  13. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/__init__.py +3 -6
  14. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/downloaders/__init__.py +10 -13
  15. novel_downloader-1.4.1/novel_downloader/core/downloaders/base.py +233 -0
  16. novel_downloader-1.4.1/novel_downloader/core/downloaders/biquge.py +27 -0
  17. novel_downloader-1.4.1/novel_downloader/core/downloaders/common.py +414 -0
  18. novel_downloader-1.4.1/novel_downloader/core/downloaders/esjzone.py +27 -0
  19. novel_downloader-1.4.1/novel_downloader/core/downloaders/linovelib.py +27 -0
  20. novel_downloader-1.4.1/novel_downloader/core/downloaders/qianbi.py +27 -0
  21. novel_downloader-1.4.1/novel_downloader/core/downloaders/qidian.py +352 -0
  22. novel_downloader-1.4.1/novel_downloader/core/downloaders/sfacg.py +27 -0
  23. novel_downloader-1.4.1/novel_downloader/core/downloaders/yamibo.py +27 -0
  24. novel_downloader-1.4.1/novel_downloader/core/exporters/__init__.py +37 -0
  25. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/base.py +73 -39
  26. novel_downloader-1.4.1/novel_downloader/core/exporters/biquge.py +25 -0
  27. novel_downloader-1.4.1/novel_downloader/core/exporters/common/__init__.py +12 -0
  28. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/common/epub.py +22 -22
  29. novel_downloader-1.3.3/novel_downloader/core/savers/common/main_saver.py → novel_downloader-1.4.1/novel_downloader/core/exporters/common/main_exporter.py +35 -40
  30. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/common/txt.py +20 -23
  31. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/epub_utils/__init__.py +8 -3
  32. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/epub_utils/css_builder.py +2 -2
  33. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/epub_utils/image_loader.py +46 -4
  34. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/epub_utils/initializer.py +6 -4
  35. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/epub_utils/text_to_html.py +3 -3
  36. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/epub_utils/volume_intro.py +2 -2
  37. novel_downloader-1.4.1/novel_downloader/core/exporters/esjzone.py +25 -0
  38. novel_downloader-1.4.1/novel_downloader/core/exporters/linovelib/__init__.py +10 -0
  39. novel_downloader-1.4.1/novel_downloader/core/exporters/linovelib/epub.py +449 -0
  40. novel_downloader-1.4.1/novel_downloader/core/exporters/linovelib/main_exporter.py +127 -0
  41. novel_downloader-1.4.1/novel_downloader/core/exporters/linovelib/txt.py +129 -0
  42. novel_downloader-1.4.1/novel_downloader/core/exporters/qianbi.py +25 -0
  43. {novel_downloader-1.3.3/novel_downloader/core/savers → novel_downloader-1.4.1/novel_downloader/core/exporters}/qidian.py +8 -8
  44. novel_downloader-1.4.1/novel_downloader/core/exporters/sfacg.py +25 -0
  45. novel_downloader-1.4.1/novel_downloader/core/exporters/yamibo.py +25 -0
  46. novel_downloader-1.4.1/novel_downloader/core/factory/__init__.py +20 -0
  47. novel_downloader-1.4.1/novel_downloader/core/factory/downloader.py +76 -0
  48. novel_downloader-1.4.1/novel_downloader/core/factory/exporter.py +58 -0
  49. novel_downloader-1.4.1/novel_downloader/core/factory/fetcher.py +96 -0
  50. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/factory/parser.py +17 -12
  51. {novel_downloader-1.3.3/novel_downloader/core/requesters → novel_downloader-1.4.1/novel_downloader/core/fetchers}/__init__.py +22 -15
  52. {novel_downloader-1.3.3/novel_downloader/core/requesters → novel_downloader-1.4.1/novel_downloader/core/fetchers}/base/__init__.py +2 -4
  53. novel_downloader-1.4.1/novel_downloader/core/fetchers/base/browser.py +383 -0
  54. novel_downloader-1.4.1/novel_downloader/core/fetchers/base/rate_limiter.py +86 -0
  55. novel_downloader-1.4.1/novel_downloader/core/fetchers/base/session.py +419 -0
  56. novel_downloader-1.4.1/novel_downloader/core/fetchers/biquge/__init__.py +14 -0
  57. novel_downloader-1.3.3/novel_downloader/core/requesters/biquge/async_session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/biquge/browser.py +18 -6
  58. {novel_downloader-1.3.3/novel_downloader/core/requesters → novel_downloader-1.4.1/novel_downloader/core/fetchers}/biquge/session.py +23 -30
  59. novel_downloader-1.4.1/novel_downloader/core/fetchers/common/__init__.py +14 -0
  60. novel_downloader-1.4.1/novel_downloader/core/fetchers/common/browser.py +79 -0
  61. novel_downloader-1.3.3/novel_downloader/core/requesters/common/async_session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/common/session.py +8 -25
  62. novel_downloader-1.4.1/novel_downloader/core/fetchers/esjzone/__init__.py +14 -0
  63. novel_downloader-1.4.1/novel_downloader/core/fetchers/esjzone/browser.py +202 -0
  64. novel_downloader-1.3.3/novel_downloader/core/requesters/esjzone/async_session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/esjzone/session.py +62 -42
  65. novel_downloader-1.4.1/novel_downloader/core/fetchers/linovelib/__init__.py +14 -0
  66. novel_downloader-1.4.1/novel_downloader/core/fetchers/linovelib/browser.py +193 -0
  67. novel_downloader-1.4.1/novel_downloader/core/fetchers/linovelib/session.py +193 -0
  68. novel_downloader-1.4.1/novel_downloader/core/fetchers/qianbi/__init__.py +14 -0
  69. novel_downloader-1.3.3/novel_downloader/core/requesters/qianbi/session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/qianbi/browser.py +30 -48
  70. novel_downloader-1.3.3/novel_downloader/core/requesters/qianbi/async_session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/qianbi/session.py +18 -6
  71. novel_downloader-1.4.1/novel_downloader/core/fetchers/qidian/__init__.py +14 -0
  72. novel_downloader-1.4.1/novel_downloader/core/fetchers/qidian/browser.py +266 -0
  73. novel_downloader-1.4.1/novel_downloader/core/fetchers/qidian/session.py +326 -0
  74. novel_downloader-1.4.1/novel_downloader/core/fetchers/sfacg/__init__.py +14 -0
  75. novel_downloader-1.4.1/novel_downloader/core/fetchers/sfacg/browser.py +189 -0
  76. novel_downloader-1.3.3/novel_downloader/core/requesters/sfacg/async_session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/sfacg/session.py +43 -73
  77. novel_downloader-1.4.1/novel_downloader/core/fetchers/yamibo/__init__.py +14 -0
  78. novel_downloader-1.4.1/novel_downloader/core/fetchers/yamibo/browser.py +229 -0
  79. novel_downloader-1.3.3/novel_downloader/core/requesters/yamibo/async_session.py → novel_downloader-1.4.1/novel_downloader/core/fetchers/yamibo/session.py +62 -44
  80. novel_downloader-1.4.1/novel_downloader/core/interfaces/__init__.py +27 -0
  81. novel_downloader-1.4.1/novel_downloader/core/interfaces/downloader.py +54 -0
  82. novel_downloader-1.3.3/novel_downloader/core/interfaces/saver.py → novel_downloader-1.4.1/novel_downloader/core/interfaces/exporter.py +12 -12
  83. novel_downloader-1.4.1/novel_downloader/core/interfaces/fetcher.py +162 -0
  84. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/interfaces/parser.py +6 -7
  85. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/__init__.py +5 -6
  86. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/base.py +9 -13
  87. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/biquge/main_parser.py +12 -13
  88. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/common/helper.py +3 -3
  89. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/common/main_parser.py +39 -34
  90. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/esjzone/main_parser.py +20 -14
  91. novel_downloader-1.4.1/novel_downloader/core/parsers/linovelib/__init__.py +10 -0
  92. novel_downloader-1.4.1/novel_downloader/core/parsers/linovelib/main_parser.py +210 -0
  93. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/qianbi/main_parser.py +21 -15
  94. novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/__init__.py +10 -0
  95. novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/book_info_parser.py +113 -0
  96. {novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/browser → novel_downloader-1.4.1/novel_downloader/core/parsers/qidian}/chapter_encrypted.py +162 -135
  97. novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/chapter_normal.py +150 -0
  98. {novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/session → novel_downloader-1.4.1/novel_downloader/core/parsers/qidian}/chapter_router.py +15 -15
  99. {novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/session → novel_downloader-1.4.1/novel_downloader/core/parsers/qidian}/main_parser.py +48 -42
  100. novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/utils/__init__.py +27 -0
  101. novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/utils/decryptor_fetcher.py +145 -0
  102. {novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/shared → novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/utils}/helpers.py +41 -68
  103. {novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/session → novel_downloader-1.4.1/novel_downloader/core/parsers/qidian/utils}/node_decryptor.py +64 -50
  104. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/sfacg/main_parser.py +12 -12
  105. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/yamibo/main_parser.py +10 -10
  106. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/locales/en.json +18 -2
  107. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/locales/zh.json +18 -2
  108. novel_downloader-1.4.1/novel_downloader/models/__init__.py +64 -0
  109. novel_downloader-1.4.1/novel_downloader/models/browser.py +21 -0
  110. novel_downloader-1.4.1/novel_downloader/models/chapter.py +25 -0
  111. novel_downloader-1.4.1/novel_downloader/models/config.py +100 -0
  112. novel_downloader-1.4.1/novel_downloader/models/login.py +20 -0
  113. novel_downloader-1.4.1/novel_downloader/models/site_rules.py +99 -0
  114. novel_downloader-1.4.1/novel_downloader/models/tasks.py +33 -0
  115. novel_downloader-1.4.1/novel_downloader/models/types.py +15 -0
  116. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/config/settings.toml +31 -25
  117. novel_downloader-1.4.1/novel_downloader/resources/json/linovelib_font_map.json +3573 -0
  118. novel_downloader-1.4.1/novel_downloader/tui/__init__.py +7 -0
  119. novel_downloader-1.4.1/novel_downloader/tui/app.py +32 -0
  120. novel_downloader-1.4.1/novel_downloader/tui/main.py +17 -0
  121. novel_downloader-1.4.1/novel_downloader/tui/screens/__init__.py +14 -0
  122. novel_downloader-1.4.1/novel_downloader/tui/screens/home.py +191 -0
  123. novel_downloader-1.4.1/novel_downloader/tui/screens/login.py +74 -0
  124. novel_downloader-1.4.1/novel_downloader/tui/styles/home_layout.tcss +79 -0
  125. novel_downloader-1.4.1/novel_downloader/tui/widgets/richlog_handler.py +24 -0
  126. novel_downloader-1.4.1/novel_downloader/utils/__init__.py +6 -0
  127. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/chapter_storage.py +25 -38
  128. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/constants.py +11 -5
  129. novel_downloader-1.4.1/novel_downloader/utils/cookies.py +66 -0
  130. novel_downloader-1.4.1/novel_downloader/utils/crypto_utils.py +71 -0
  131. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/fontocr/ocr_v1.py +2 -1
  132. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/fontocr/ocr_v2.py +2 -2
  133. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/hash_store.py +10 -18
  134. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/hash_utils.py +3 -2
  135. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/logger.py +2 -3
  136. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/network.py +2 -1
  137. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/text_utils/chapter_formatting.py +6 -1
  138. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/text_utils/font_mapping.py +1 -1
  139. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/text_utils/text_cleaning.py +1 -1
  140. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/time_utils/datetime_utils.py +3 -3
  141. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/time_utils/sleep_utils.py +1 -1
  142. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader.egg-info/PKG-INFO +69 -35
  143. novel_downloader-1.4.1/novel_downloader.egg-info/SOURCES.txt +173 -0
  144. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader.egg-info/entry_points.txt +1 -0
  145. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader.egg-info/requires.txt +5 -4
  146. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/pyproject.toml +11 -7
  147. novel_downloader-1.3.3/novel_downloader/cli/clean.py +0 -126
  148. novel_downloader-1.3.3/novel_downloader/cli/download.py +0 -128
  149. novel_downloader-1.3.3/novel_downloader/cli/interactive.py +0 -66
  150. novel_downloader-1.3.3/novel_downloader/cli/main.py +0 -43
  151. novel_downloader-1.3.3/novel_downloader/cli/settings.py +0 -177
  152. novel_downloader-1.3.3/novel_downloader/config/models.py +0 -187
  153. novel_downloader-1.3.3/novel_downloader/core/downloaders/base/__init__.py +0 -14
  154. novel_downloader-1.3.3/novel_downloader/core/downloaders/base/base_async.py +0 -153
  155. novel_downloader-1.3.3/novel_downloader/core/downloaders/base/base_sync.py +0 -208
  156. novel_downloader-1.3.3/novel_downloader/core/downloaders/biquge/__init__.py +0 -14
  157. novel_downloader-1.3.3/novel_downloader/core/downloaders/biquge/biquge_async.py +0 -27
  158. novel_downloader-1.3.3/novel_downloader/core/downloaders/biquge/biquge_sync.py +0 -27
  159. novel_downloader-1.3.3/novel_downloader/core/downloaders/common/__init__.py +0 -14
  160. novel_downloader-1.3.3/novel_downloader/core/downloaders/common/common_async.py +0 -210
  161. novel_downloader-1.3.3/novel_downloader/core/downloaders/common/common_sync.py +0 -202
  162. novel_downloader-1.3.3/novel_downloader/core/downloaders/esjzone/__init__.py +0 -14
  163. novel_downloader-1.3.3/novel_downloader/core/downloaders/esjzone/esjzone_async.py +0 -27
  164. novel_downloader-1.3.3/novel_downloader/core/downloaders/esjzone/esjzone_sync.py +0 -27
  165. novel_downloader-1.3.3/novel_downloader/core/downloaders/qianbi/__init__.py +0 -14
  166. novel_downloader-1.3.3/novel_downloader/core/downloaders/qianbi/qianbi_async.py +0 -27
  167. novel_downloader-1.3.3/novel_downloader/core/downloaders/qianbi/qianbi_sync.py +0 -27
  168. novel_downloader-1.3.3/novel_downloader/core/downloaders/qidian/__init__.py +0 -10
  169. novel_downloader-1.3.3/novel_downloader/core/downloaders/qidian/qidian_sync.py +0 -219
  170. novel_downloader-1.3.3/novel_downloader/core/downloaders/sfacg/__init__.py +0 -14
  171. novel_downloader-1.3.3/novel_downloader/core/downloaders/sfacg/sfacg_async.py +0 -27
  172. novel_downloader-1.3.3/novel_downloader/core/downloaders/sfacg/sfacg_sync.py +0 -27
  173. novel_downloader-1.3.3/novel_downloader/core/downloaders/yamibo/__init__.py +0 -14
  174. novel_downloader-1.3.3/novel_downloader/core/downloaders/yamibo/yamibo_async.py +0 -27
  175. novel_downloader-1.3.3/novel_downloader/core/downloaders/yamibo/yamibo_sync.py +0 -27
  176. novel_downloader-1.3.3/novel_downloader/core/factory/__init__.py +0 -32
  177. novel_downloader-1.3.3/novel_downloader/core/factory/downloader.py +0 -178
  178. novel_downloader-1.3.3/novel_downloader/core/factory/requester.py +0 -144
  179. novel_downloader-1.3.3/novel_downloader/core/factory/saver.py +0 -56
  180. novel_downloader-1.3.3/novel_downloader/core/interfaces/__init__.py +0 -31
  181. novel_downloader-1.3.3/novel_downloader/core/interfaces/async_downloader.py +0 -36
  182. novel_downloader-1.3.3/novel_downloader/core/interfaces/async_requester.py +0 -84
  183. novel_downloader-1.3.3/novel_downloader/core/interfaces/sync_downloader.py +0 -36
  184. novel_downloader-1.3.3/novel_downloader/core/interfaces/sync_requester.py +0 -82
  185. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/__init__.py +0 -19
  186. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/browser/__init__.py +0 -12
  187. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/browser/chapter_normal.py +0 -93
  188. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/browser/chapter_router.py +0 -71
  189. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/browser/main_parser.py +0 -125
  190. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/session/__init__.py +0 -12
  191. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/session/chapter_encrypted.py +0 -443
  192. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/session/chapter_normal.py +0 -115
  193. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/shared/__init__.py +0 -37
  194. novel_downloader-1.3.3/novel_downloader/core/parsers/qidian/shared/book_info_parser.py +0 -150
  195. novel_downloader-1.3.3/novel_downloader/core/requesters/base/async_session.py +0 -410
  196. novel_downloader-1.3.3/novel_downloader/core/requesters/base/browser.py +0 -337
  197. novel_downloader-1.3.3/novel_downloader/core/requesters/base/session.py +0 -378
  198. novel_downloader-1.3.3/novel_downloader/core/requesters/biquge/__init__.py +0 -14
  199. novel_downloader-1.3.3/novel_downloader/core/requesters/common/__init__.py +0 -17
  200. novel_downloader-1.3.3/novel_downloader/core/requesters/common/session.py +0 -113
  201. novel_downloader-1.3.3/novel_downloader/core/requesters/esjzone/__init__.py +0 -13
  202. novel_downloader-1.3.3/novel_downloader/core/requesters/esjzone/session.py +0 -235
  203. novel_downloader-1.3.3/novel_downloader/core/requesters/qianbi/__init__.py +0 -13
  204. novel_downloader-1.3.3/novel_downloader/core/requesters/qidian/__init__.py +0 -21
  205. novel_downloader-1.3.3/novel_downloader/core/requesters/qidian/broswer.py +0 -307
  206. novel_downloader-1.3.3/novel_downloader/core/requesters/qidian/session.py +0 -290
  207. novel_downloader-1.3.3/novel_downloader/core/requesters/sfacg/__init__.py +0 -13
  208. novel_downloader-1.3.3/novel_downloader/core/requesters/sfacg/session.py +0 -242
  209. novel_downloader-1.3.3/novel_downloader/core/requesters/yamibo/__init__.py +0 -13
  210. novel_downloader-1.3.3/novel_downloader/core/requesters/yamibo/session.py +0 -237
  211. novel_downloader-1.3.3/novel_downloader/core/savers/__init__.py +0 -34
  212. novel_downloader-1.3.3/novel_downloader/core/savers/biquge.py +0 -25
  213. novel_downloader-1.3.3/novel_downloader/core/savers/common/__init__.py +0 -12
  214. novel_downloader-1.3.3/novel_downloader/core/savers/esjzone.py +0 -25
  215. novel_downloader-1.3.3/novel_downloader/core/savers/qianbi.py +0 -25
  216. novel_downloader-1.3.3/novel_downloader/core/savers/sfacg.py +0 -25
  217. novel_downloader-1.3.3/novel_downloader/core/savers/yamibo.py +0 -25
  218. novel_downloader-1.3.3/novel_downloader/resources/config/rules.toml +0 -196
  219. novel_downloader-1.3.3/novel_downloader/utils/__init__.py +0 -0
  220. novel_downloader-1.3.3/novel_downloader/utils/crypto_utils.py +0 -144
  221. novel_downloader-1.3.3/novel_downloader.egg-info/SOURCES.txt +0 -169
  222. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/LICENSE +0 -0
  223. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/cli/__init__.py +0 -0
  224. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/biquge/__init__.py +0 -0
  225. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/common/__init__.py +0 -0
  226. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/esjzone/__init__.py +0 -0
  227. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/qianbi/__init__.py +0 -0
  228. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/sfacg/__init__.py +0 -0
  229. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/core/parsers/yamibo/__init__.py +0 -0
  230. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/css_styles/main.css +0 -0
  231. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/css_styles/volume-intro.css +0 -0
  232. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/images/volume_border.png +0 -0
  233. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/js_scripts/qidian_decrypt_node.js +0 -0
  234. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/json/replace_word_map.json +0 -0
  235. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/resources/text/blacklist.txt +0 -0
  236. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/cache.py +0 -0
  237. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/file_utils/__init__.py +0 -0
  238. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/file_utils/io.py +0 -0
  239. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/file_utils/normalize.py +0 -0
  240. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/file_utils/sanitize.py +0 -0
  241. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/fontocr/__init__.py +0 -0
  242. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/i18n.py +0 -0
  243. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/model_loader.py +0 -0
  244. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/state.py +0 -0
  245. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/text_utils/__init__.py +0 -0
  246. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/text_utils/diff_display.py +0 -0
  247. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader/utils/time_utils/__init__.py +0 -0
  248. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader.egg-info/dependency_links.txt +0 -0
  249. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/novel_downloader.egg-info/top_level.txt +0 -0
  250. {novel_downloader-1.3.3 → novel_downloader-1.4.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: novel-downloader
3
- Version: 1.3.3
3
+ Version: 1.4.1
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
@@ -34,19 +34,18 @@ Classifier: License :: OSI Approved :: MIT License
34
34
  Classifier: Natural Language :: Chinese (Simplified)
35
35
  Classifier: Topic :: Utilities
36
36
  Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.11
37
38
  Classifier: Programming Language :: Python :: 3.12
38
39
  Classifier: Programming Language :: Python :: 3.13
39
- Requires-Python: >=3.12
40
+ Requires-Python: >=3.11
40
41
  Description-Content-Type: text/markdown
41
42
  License-File: LICENSE
43
+ Requires-Dist: textual
42
44
  Requires-Dist: requests
43
45
  Requires-Dist: aiohttp
44
- Requires-Dist: beautifulsoup4
45
- Requires-Dist: DrissionPage
46
- Requires-Dist: opencv-python
46
+ Requires-Dist: playwright
47
47
  Requires-Dist: lxml
48
48
  Requires-Dist: platformdirs
49
- Requires-Dist: click
50
49
  Requires-Dist: ebooklib
51
50
  Provides-Extra: dev
52
51
  Requires-Dist: black; extra == "dev"
@@ -55,6 +54,8 @@ Requires-Dist: ruff; extra == "dev"
55
54
  Requires-Dist: pytest; extra == "dev"
56
55
  Requires-Dist: pytest-cov; extra == "dev"
57
56
  Requires-Dist: pytest-mock; extra == "dev"
57
+ Requires-Dist: types-requests; extra == "dev"
58
+ Requires-Dist: types-PyYAML; extra == "dev"
58
59
  Requires-Dist: pre-commit; extra == "dev"
59
60
  Requires-Dist: commitizen; extra == "dev"
60
61
  Provides-Extra: font-recovery
@@ -63,32 +64,19 @@ Requires-Dist: numpy; extra == "font-recovery"
63
64
  Requires-Dist: tinycss2; extra == "font-recovery"
64
65
  Requires-Dist: fonttools; extra == "font-recovery"
65
66
  Requires-Dist: brotli; extra == "font-recovery"
67
+ Requires-Dist: opencv-python; extra == "font-recovery"
66
68
  Requires-Dist: pillow; extra == "font-recovery"
67
69
  Requires-Dist: huggingface_hub; extra == "font-recovery"
68
70
  Dynamic: license-file
69
71
 
70
72
  # novel-downloader
71
73
 
72
- 一个基于 [DrissionPage](https://www.drissionpage.cn) 和 [requests](https://github.com/psf/requests) 的小说下载工具/库。
74
+ 一个基于 [playwright](https://playwright.dev/) 和 [aiohttp](https://github.com/aio-libs/aiohttp) 的小说下载工具/库。
73
75
 
74
- ---
75
-
76
- ## 项目简介
77
-
78
- **novel-downloader** 支持多种小说网站的章节抓取与合并导出,
79
- - **轻量化抓取**: 绝大多数站点仅依赖 `requests` 实现 HTTP 请求, 无需额外浏览器驱动
80
- - 对于起点中文网 (Qidian), 可在配置中选择:
81
- - `mode: session` : 纯 Requests 模式
82
- - `mode: browser` : 基于 `DrissionPage` 驱动 Chrome 的浏览器模式 (可处理更复杂的 JS/加密)。
83
- - **自动登录** (可选)
84
- - 配置 `login_required: true` 后自动检测并重用历史 Cookie
85
- - 首次登录或 Cookie 失效时:
86
- - **browser** 模式: 在程序打开的浏览器窗口登录, 登录后回车继续
87
- - **session** 模式: 根据提示粘贴浏览器中已登录的 Cookie (参考 [复制 Cookies](https://github.com/BowenZ217/novel-downloader/blob/main/docs/copy-cookies.md))
76
+ > 本项目开发环境为 Python 3.12, 需确保运行环境为 Python 3.11 及以上版本
88
77
 
89
78
  ## 功能特性
90
79
 
91
- - 抓取起点中文网免费及已订阅章节内容
92
80
  - 支持断点续爬, 自动续传未完成任务
93
81
  - 自动整合所有章节并导出为:
94
82
  - TXT
@@ -101,25 +89,71 @@ Dynamic: license-file
101
89
 
102
90
  ## 快速开始
103
91
 
92
+ ### 安装
93
+
94
+ 使用 `pip` 安装:
95
+
104
96
  ```bash
105
- # 克隆 + 安装
106
97
  pip install novel-downloader
98
+ ```
99
+
100
+ 如需使用浏览器模式 (即 `mode: browser`), 请确保已安装 Playwright 依赖:
107
101
 
108
- # 如需支持字体解密功能 (decode_font), 请使用:
109
- # pip install novel-downloader[font-recovery]
102
+ ```bash
103
+ playwright install
104
+ ```
110
105
 
106
+ 如需启用字体解密功能 (`decode_font`, 用于处理起点中文网对近一个月更新章节所采用的字体混淆技术), 请使用扩展安装方式:
107
+
108
+ ```bash
109
+ pip install novel-downloader[font-recovery]
110
+ ```
111
+
112
+ ---
113
+
114
+ ### CLI 模式
115
+
116
+ ```bash
111
117
  # 初始化默认配置 (生成 settings.toml)
112
- novel-cli settings init
118
+ novel-cli config init
113
119
 
114
120
  # 编辑 ./settings.toml 完成 site/book_ids 等
115
- # 可查看 docs/4-settings-schema.md
121
+ # 可查看 docs/3-settings-schema.md
116
122
 
117
- # 运行下载
123
+ # 执行下载任务
118
124
  novel-cli download 123456
119
125
  ```
120
126
 
121
- - 详细可见: [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-supported-sites.md)
122
- - 更多使用方法, 查看 [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-usage-examples.md)
127
+ - 详细可见: [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-supported-sites.md)
128
+ - 更多使用方法, 查看 [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-cli-usage-examples.md)
129
+
130
+ ---
131
+
132
+ ### TUI 模式 (终端用户界面)
133
+
134
+ **注意**: TUI 模式仍在开发中, 目前尚未实现登录和修改设置等功能。建议优先使用稳定的 CLI 模式。
135
+
136
+ ```bash
137
+ # 初始化默认配置 (生成 settings.toml)
138
+ novel-cli config init
139
+
140
+ # 编辑 ./settings.toml 修改网络配置
141
+ # 可查看 docs/3-settings-schema.md
142
+
143
+ # 启动 TUI 界面
144
+ novel-tui
145
+ ```
146
+
147
+ - 详细可见: [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-supported-sites.md)
148
+ - 更多使用方法, 查看 [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-tui-usage-examples.md)
149
+
150
+ ---
151
+
152
+ ### GUI 模式 (图形界面)
153
+
154
+ 尚未实现
155
+
156
+ ---
123
157
 
124
158
  ## 从 GitHub 安装 (开发版)
125
159
 
@@ -139,11 +173,11 @@ pip install .
139
173
 
140
174
  - [项目简介](#项目简介)
141
175
  - [安装](https://github.com/BowenZ217/novel-downloader/blob/main/docs/1-installation.md)
142
- - [环境准备](https://github.com/BowenZ217/novel-downloader/blob/main/docs/2-environment-setup.md)
143
- - [配置](https://github.com/BowenZ217/novel-downloader/blob/main/docs/3-configuration.md)
144
- - [settings.toml 配置说明](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-settings-schema.md)
145
- - [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-usage-examples.md)
146
- - [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-supported-sites.md)
176
+ - [配置](https://github.com/BowenZ217/novel-downloader/blob/main/docs/2-configuration.md)
177
+ - [settings.toml 配置说明](https://github.com/BowenZ217/novel-downloader/blob/main/docs/3-settings-schema.md)
178
+ - [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-supported-sites.md)
179
+ - [TUI 使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-tui-usage-examples.md)
180
+ - [CLI 使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-cli-usage-examples.md)
147
181
  - [复制 Cookies](https://github.com/BowenZ217/novel-downloader/blob/main/docs/copy-cookies.md)
148
182
  - [文件保存](https://github.com/BowenZ217/novel-downloader/blob/main/docs/file-saving.md)
149
183
  - [TODO](https://github.com/BowenZ217/novel-downloader/blob/main/docs/todo.md)
@@ -1,25 +1,11 @@
1
1
  # novel-downloader
2
2
 
3
- 一个基于 [DrissionPage](https://www.drissionpage.cn) 和 [requests](https://github.com/psf/requests) 的小说下载工具/库。
3
+ 一个基于 [playwright](https://playwright.dev/) 和 [aiohttp](https://github.com/aio-libs/aiohttp) 的小说下载工具/库。
4
4
 
5
- ---
6
-
7
- ## 项目简介
8
-
9
- **novel-downloader** 支持多种小说网站的章节抓取与合并导出,
10
- - **轻量化抓取**: 绝大多数站点仅依赖 `requests` 实现 HTTP 请求, 无需额外浏览器驱动
11
- - 对于起点中文网 (Qidian), 可在配置中选择:
12
- - `mode: session` : 纯 Requests 模式
13
- - `mode: browser` : 基于 `DrissionPage` 驱动 Chrome 的浏览器模式 (可处理更复杂的 JS/加密)。
14
- - **自动登录** (可选)
15
- - 配置 `login_required: true` 后自动检测并重用历史 Cookie
16
- - 首次登录或 Cookie 失效时:
17
- - **browser** 模式: 在程序打开的浏览器窗口登录, 登录后回车继续
18
- - **session** 模式: 根据提示粘贴浏览器中已登录的 Cookie (参考 [复制 Cookies](https://github.com/BowenZ217/novel-downloader/blob/main/docs/copy-cookies.md))
5
+ > 本项目开发环境为 Python 3.12, 需确保运行环境为 Python 3.11 及以上版本
19
6
 
20
7
  ## 功能特性
21
8
 
22
- - 抓取起点中文网免费及已订阅章节内容
23
9
  - 支持断点续爬, 自动续传未完成任务
24
10
  - 自动整合所有章节并导出为:
25
11
  - TXT
@@ -32,25 +18,71 @@
32
18
 
33
19
  ## 快速开始
34
20
 
21
+ ### 安装
22
+
23
+ 使用 `pip` 安装:
24
+
35
25
  ```bash
36
- # 克隆 + 安装
37
26
  pip install novel-downloader
27
+ ```
28
+
29
+ 如需使用浏览器模式 (即 `mode: browser`), 请确保已安装 Playwright 依赖:
38
30
 
39
- # 如需支持字体解密功能 (decode_font), 请使用:
40
- # pip install novel-downloader[font-recovery]
31
+ ```bash
32
+ playwright install
33
+ ```
41
34
 
35
+ 如需启用字体解密功能 (`decode_font`, 用于处理起点中文网对近一个月更新章节所采用的字体混淆技术), 请使用扩展安装方式:
36
+
37
+ ```bash
38
+ pip install novel-downloader[font-recovery]
39
+ ```
40
+
41
+ ---
42
+
43
+ ### CLI 模式
44
+
45
+ ```bash
42
46
  # 初始化默认配置 (生成 settings.toml)
43
- novel-cli settings init
47
+ novel-cli config init
44
48
 
45
49
  # 编辑 ./settings.toml 完成 site/book_ids 等
46
- # 可查看 docs/4-settings-schema.md
50
+ # 可查看 docs/3-settings-schema.md
47
51
 
48
- # 运行下载
52
+ # 执行下载任务
49
53
  novel-cli download 123456
50
54
  ```
51
55
 
52
- - 详细可见: [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-supported-sites.md)
53
- - 更多使用方法, 查看 [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-usage-examples.md)
56
+ - 详细可见: [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-supported-sites.md)
57
+ - 更多使用方法, 查看 [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-cli-usage-examples.md)
58
+
59
+ ---
60
+
61
+ ### TUI 模式 (终端用户界面)
62
+
63
+ **注意**: TUI 模式仍在开发中, 目前尚未实现登录和修改设置等功能。建议优先使用稳定的 CLI 模式。
64
+
65
+ ```bash
66
+ # 初始化默认配置 (生成 settings.toml)
67
+ novel-cli config init
68
+
69
+ # 编辑 ./settings.toml 修改网络配置
70
+ # 可查看 docs/3-settings-schema.md
71
+
72
+ # 启动 TUI 界面
73
+ novel-tui
74
+ ```
75
+
76
+ - 详细可见: [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-supported-sites.md)
77
+ - 更多使用方法, 查看 [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-tui-usage-examples.md)
78
+
79
+ ---
80
+
81
+ ### GUI 模式 (图形界面)
82
+
83
+ 尚未实现
84
+
85
+ ---
54
86
 
55
87
  ## 从 GitHub 安装 (开发版)
56
88
 
@@ -70,11 +102,11 @@ pip install .
70
102
 
71
103
  - [项目简介](#项目简介)
72
104
  - [安装](https://github.com/BowenZ217/novel-downloader/blob/main/docs/1-installation.md)
73
- - [环境准备](https://github.com/BowenZ217/novel-downloader/blob/main/docs/2-environment-setup.md)
74
- - [配置](https://github.com/BowenZ217/novel-downloader/blob/main/docs/3-configuration.md)
75
- - [settings.toml 配置说明](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-settings-schema.md)
76
- - [使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-usage-examples.md)
77
- - [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-supported-sites.md)
105
+ - [配置](https://github.com/BowenZ217/novel-downloader/blob/main/docs/2-configuration.md)
106
+ - [settings.toml 配置说明](https://github.com/BowenZ217/novel-downloader/blob/main/docs/3-settings-schema.md)
107
+ - [支持站点列表](https://github.com/BowenZ217/novel-downloader/blob/main/docs/4-supported-sites.md)
108
+ - [TUI 使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/5-tui-usage-examples.md)
109
+ - [CLI 使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-cli-usage-examples.md)
78
110
  - [复制 Cookies](https://github.com/BowenZ217/novel-downloader/blob/main/docs/copy-cookies.md)
79
111
  - [文件保存](https://github.com/BowenZ217/novel-downloader/blob/main/docs/file-saving.md)
80
112
  - [TODO](https://github.com/BowenZ217/novel-downloader/blob/main/docs/todo.md)
@@ -6,7 +6,7 @@ novel_downloader
6
6
  Core package for the Novel Downloader project.
7
7
  """
8
8
 
9
- __version__ = "1.3.3"
9
+ __version__ = "1.4.1"
10
10
 
11
11
  __author__ = "Saudade Z"
12
12
  __email__ = "saudadez217@gmail.com"
@@ -0,0 +1,145 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ novel_downloader.cli.clean
4
+ --------------------------
5
+
6
+ CLI subcommands for clean resources.
7
+ """
8
+
9
+ import shutil
10
+ from argparse import Namespace, _SubParsersAction
11
+ from pathlib import Path
12
+
13
+ from novel_downloader.utils.constants import (
14
+ CONFIG_DIR,
15
+ DATA_DIR,
16
+ JS_SCRIPT_DIR,
17
+ LOGGER_DIR,
18
+ MODEL_CACHE_DIR,
19
+ REC_CHAR_MODEL_REPO,
20
+ )
21
+ from novel_downloader.utils.i18n import t
22
+
23
+
24
+ def register_clean_subcommand(subparsers: _SubParsersAction) -> None: # type: ignore
25
+ parser = subparsers.add_parser("clean", help=t("help_clean"))
26
+
27
+ parser.add_argument("--logs", action="store_true", help=t("clean_logs"))
28
+ parser.add_argument("--cache", action="store_true", help=t("clean_cache"))
29
+ parser.add_argument("--data", action="store_true", help=t("clean_data"))
30
+ parser.add_argument("--config", action="store_true", help=t("clean_config"))
31
+ parser.add_argument("--models", action="store_true", help=t("clean_models"))
32
+ parser.add_argument("--all", action="store_true", help=t("clean_all"))
33
+ parser.add_argument("-y", "--yes", action="store_true", help=t("clean_yes"))
34
+
35
+ parser.add_argument("--hf-cache", action="store_true", help=t("clean_hf_cache"))
36
+ parser.add_argument(
37
+ "--hf-cache-all", action="store_true", help=t("clean_hf_cache_all")
38
+ )
39
+
40
+ parser.set_defaults(func=handle_clean)
41
+
42
+
43
+ def handle_clean(args: Namespace) -> None:
44
+ targets: list[Path] = []
45
+
46
+ if args.hf_cache_all:
47
+ try:
48
+ if _clean_model_repo_cache(all=True):
49
+ print(t("clean_hf_cache_all_done"))
50
+ except Exception as e:
51
+ print(t("clean_hf_cache_all_fail", err=str(e)))
52
+ elif args.hf_cache:
53
+ try:
54
+ if _clean_model_repo_cache(repo_id=REC_CHAR_MODEL_REPO):
55
+ print(t("clean_hf_model_done", repo=REC_CHAR_MODEL_REPO))
56
+ else:
57
+ print(t("clean_hf_model_not_found", repo=REC_CHAR_MODEL_REPO))
58
+ except Exception as e:
59
+ print(t("clean_hf_model_fail", err=str(e)))
60
+
61
+ if args.all:
62
+ if not args.yes:
63
+ confirm = prompt(t("clean_confirm"), default="n")
64
+ if confirm.lower() != "y":
65
+ print(t("clean_cancelled"))
66
+ return
67
+ targets = [
68
+ LOGGER_DIR,
69
+ JS_SCRIPT_DIR,
70
+ DATA_DIR,
71
+ CONFIG_DIR,
72
+ MODEL_CACHE_DIR,
73
+ ]
74
+ else:
75
+ if args.logs:
76
+ targets.append(LOGGER_DIR)
77
+ if args.cache:
78
+ targets.append(JS_SCRIPT_DIR)
79
+ if args.data:
80
+ targets.append(DATA_DIR)
81
+ if args.config:
82
+ targets.append(CONFIG_DIR)
83
+ if args.models:
84
+ targets.append(MODEL_CACHE_DIR)
85
+
86
+ if not targets and not args.hf_cache and not args.hf_cache_all:
87
+ print(t("clean_nothing"))
88
+ return
89
+
90
+ for path in targets:
91
+ _delete_path(path)
92
+
93
+
94
+ def prompt(message: str, default: str = "n") -> str:
95
+ """
96
+ Prompt the user for input with a default option.
97
+
98
+ :param message: The prompt message to display to the user.
99
+ :param default: The default value to use if the user provides no input ("y" or "n").
100
+ :return: The user's input (lowercased), or the default value if no input is given.
101
+ """
102
+ try:
103
+ full_prompt = f"{message} [{'Y/n' if default.lower() == 'y' else 'y/N'}]: "
104
+ response = input(full_prompt).strip().lower()
105
+ return response if response else default.lower()
106
+ except (KeyboardInterrupt, EOFError):
107
+ print("\n" + "Cancelled.")
108
+ return default.lower()
109
+
110
+
111
+ def _delete_path(p: Path) -> None:
112
+ if p.exists():
113
+ if p.is_file():
114
+ p.unlink()
115
+ else:
116
+ shutil.rmtree(p, ignore_errors=True)
117
+ print(f"[clean] {t('clean_deleted')}: {p}")
118
+ else:
119
+ print(f"[clean] {t('clean_not_found')}: {p}")
120
+
121
+
122
+ def _clean_model_repo_cache(
123
+ repo_id: str | None = None,
124
+ all: bool = False,
125
+ ) -> bool:
126
+ """
127
+ Delete Hugging Face cache for a specific repo.
128
+ """
129
+ from huggingface_hub import scan_cache_dir
130
+
131
+ cache_info = scan_cache_dir()
132
+
133
+ if all:
134
+ targets = cache_info.repos
135
+ elif repo_id:
136
+ targets = [r for r in cache_info.repos if r.repo_id == repo_id]
137
+ else:
138
+ return False
139
+
140
+ strategy = cache_info.delete_revisions(
141
+ *[rev.commit_hash for r in targets for rev in r.revisions]
142
+ )
143
+ print(f"[clean] Will free {strategy.expected_freed_size_str}")
144
+ strategy.execute()
145
+ return True
@@ -0,0 +1,177 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ novel_downloader.cli.config
4
+ ---------------------------
5
+
6
+ CLI subcommands for configuration management.
7
+ """
8
+
9
+ import shutil
10
+ from argparse import Namespace, _SubParsersAction
11
+ from importlib.resources import as_file
12
+ from pathlib import Path
13
+
14
+ from novel_downloader.config import save_config_file, save_rules_as_json
15
+ from novel_downloader.utils.constants import DEFAULT_SETTINGS_PATHS
16
+ from novel_downloader.utils.i18n import t
17
+ from novel_downloader.utils.logger import setup_logging
18
+ from novel_downloader.utils.state import state_mgr
19
+
20
+ # from novel_downloader.utils.hash_store import img_hash_store
21
+
22
+
23
+ def register_config_subcommand(subparsers: _SubParsersAction) -> None: # type: ignore
24
+ parser = subparsers.add_parser("config", help=t("help_config"))
25
+ config_subparsers = parser.add_subparsers(dest="subcommand", required=True)
26
+
27
+ _register_init(config_subparsers)
28
+ _register_set_lang(config_subparsers)
29
+ _register_set_config(config_subparsers)
30
+ _register_update_rules(config_subparsers)
31
+ _register_set_cookies(config_subparsers)
32
+ # _register_add_hash(config_subparsers)
33
+
34
+
35
+ def _register_init(subparsers: _SubParsersAction) -> None: # type: ignore
36
+ parser = subparsers.add_parser("init", help=t("settings_init_help"))
37
+ parser.add_argument(
38
+ "--force", action="store_true", help=t("settings_init_force_help")
39
+ )
40
+ parser.set_defaults(func=_handle_init)
41
+
42
+
43
+ def _register_set_lang(subparsers: _SubParsersAction) -> None: # type: ignore
44
+ parser = subparsers.add_parser("set-lang", help=t("settings_set_lang_help"))
45
+ parser.add_argument("lang", choices=["zh", "en"], help="Language code")
46
+ parser.set_defaults(func=_handle_set_lang)
47
+
48
+
49
+ def _register_set_config(subparsers: _SubParsersAction) -> None: # type: ignore
50
+ parser = subparsers.add_parser("set-config", help=t("settings_set_config_help"))
51
+ parser.add_argument("path", type=str, help="Path to YAML config file")
52
+ parser.set_defaults(func=_handle_set_config)
53
+
54
+
55
+ def _register_update_rules(subparsers: _SubParsersAction) -> None: # type: ignore
56
+ parser = subparsers.add_parser("update-rules", help=t("settings_update_rules_help"))
57
+ parser.add_argument("path", type=str, help="Path to TOML/YAML/JSON rule file")
58
+ parser.set_defaults(func=_handle_update_rules)
59
+
60
+
61
+ def _register_set_cookies(subparsers: _SubParsersAction) -> None: # type: ignore
62
+ parser = subparsers.add_parser("set-cookies", help=t("settings_set_cookies_help"))
63
+ parser.add_argument("site", nargs="?", help="Site identifier")
64
+ parser.add_argument("cookies", nargs="?", help="Cookies string")
65
+ parser.set_defaults(func=_handle_set_cookies)
66
+
67
+
68
+ # def _register_add_hash(subparsers: _SubParsersAction) -> None: # type: ignore
69
+ # parser = subparsers.add_parser("add-hash", help=t("settings_add_hash_help"))
70
+ # parser.add_argument("--path", type=str, help=t("settings_add_hash_path_help"))
71
+ # parser.set_defaults(func=_handle_add_hash)
72
+
73
+
74
+ def _handle_init(args: Namespace) -> None:
75
+ setup_logging()
76
+ cwd = Path.cwd()
77
+
78
+ for resource in DEFAULT_SETTINGS_PATHS:
79
+ target_path = cwd / resource.name
80
+ should_copy = True
81
+
82
+ if target_path.exists():
83
+ if args.force:
84
+ print(t("settings_init_overwrite", filename=resource.name))
85
+ else:
86
+ print(t("settings_init_exists", filename=resource.name))
87
+ resp = (
88
+ input(
89
+ t("settings_init_confirm_overwrite", filename=resource.name)
90
+ + " [y/N]: "
91
+ )
92
+ .strip()
93
+ .lower()
94
+ )
95
+ should_copy = resp == "y"
96
+
97
+ if not should_copy:
98
+ print(t("settings_init_skip", filename=resource.name))
99
+ continue
100
+
101
+ try:
102
+ with as_file(resource) as actual_path:
103
+ shutil.copy(actual_path, target_path)
104
+ print(t("settings_init_copy", filename=resource.name))
105
+ except Exception as e:
106
+ print(t("settings_init_error", filename=resource.name, err=str(e)))
107
+ raise
108
+
109
+
110
+ def _handle_set_lang(args: Namespace) -> None:
111
+ state_mgr.set_language(args.lang)
112
+ print(t("settings_set_lang", lang=args.lang))
113
+
114
+
115
+ def _handle_set_config(args: Namespace) -> None:
116
+ try:
117
+ save_config_file(args.path)
118
+ print(t("settings_set_config", path=args.path))
119
+ except Exception as e:
120
+ print(t("settings_set_config_fail", err=str(e)))
121
+ raise
122
+
123
+
124
+ def _handle_update_rules(args: Namespace) -> None:
125
+ try:
126
+ save_rules_as_json(args.path)
127
+ print(t("settings_update_rules", path=args.path))
128
+ except Exception as e:
129
+ print(t("settings_update_rules_fail", err=str(e)))
130
+ raise
131
+
132
+
133
+ def _handle_set_cookies(args: Namespace) -> None:
134
+ site = args.site or input(t("settings_set_cookies_prompt_site") + ": ").strip()
135
+ cookies = (
136
+ args.cookies or input(t("settings_set_cookies_prompt_payload") + ": ").strip()
137
+ )
138
+
139
+ try:
140
+ state_mgr.set_cookies(site, cookies)
141
+ print(t("settings_set_cookies_success", site=site))
142
+ except Exception as e:
143
+ print(t("settings_set_cookies_fail", err=str(e)))
144
+ raise
145
+
146
+
147
+ # def _handle_add_hash(args: Namespace) -> None:
148
+ # if args.path:
149
+ # try:
150
+ # img_hash_store.add_from_map(args.path)
151
+ # img_hash_store.save()
152
+ # print(t("settings_add_hash_loaded", path=args.path))
153
+ # except Exception as e:
154
+ # print(t("settings_add_hash_load_fail", err=str(e)))
155
+ # raise
156
+ # else:
157
+ # print(t("settings_add_hash_prompt_tip"))
158
+ # while True:
159
+ # img_path = input(t("settings_add_hash_prompt_img") + ": ").strip()
160
+ # if not img_path or img_path.lower() in {"exit", "quit"}:
161
+ # break
162
+ # if not Path(img_path).exists():
163
+ # print(t("settings_add_hash_path_invalid"))
164
+ # continue
165
+
166
+ # label = input(t("settings_add_hash_prompt_label") + ": ").strip()
167
+ # if not label or label.lower() in {"exit", "quit"}:
168
+ # break
169
+
170
+ # try:
171
+ # img_hash_store.add_image(img_path, label)
172
+ # print(t("settings_add_hash_added", img=img_path, label=label))
173
+ # except Exception as e:
174
+ # print(t("settings_add_hash_failed", err=str(e)))
175
+
176
+ # img_hash_store.save()
177
+ # print(t("settings_add_hash_saved"))