novel-downloader 1.4.1__tar.gz → 1.4.3__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 (177) hide show
  1. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/PKG-INFO +5 -2
  2. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/README.md +3 -0
  3. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/__init__.py +1 -1
  4. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/cli/download.py +70 -11
  5. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/config/adapter.py +43 -9
  6. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/__init__.py +19 -1
  7. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/base.py +26 -29
  8. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/biquge.py +1 -3
  9. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/common.py +41 -7
  10. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/esjzone.py +1 -3
  11. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/linovelib.py +1 -3
  12. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/qianbi.py +1 -3
  13. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/qidian.py +61 -37
  14. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/sfacg.py +1 -3
  15. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/yamibo.py +1 -3
  16. novel_downloader-1.4.3/novel_downloader/core/exporters/common/epub.py +277 -0
  17. novel_downloader-1.4.3/novel_downloader/core/exporters/epub_util.py +1358 -0
  18. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/linovelib/epub.py +147 -190
  19. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/factory/downloader.py +3 -6
  20. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/base/browser.py +32 -12
  21. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/esjzone/browser.py +8 -6
  22. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/qidian/browser.py +62 -10
  23. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/yamibo/browser.py +3 -3
  24. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/interfaces/downloader.py +13 -12
  25. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/chapter_encrypted.py +11 -2
  26. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/chapter_normal.py +8 -1
  27. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/main_parser.py +7 -2
  28. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/utils/__init__.py +2 -0
  29. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/utils/helpers.py +9 -0
  30. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/locales/en.json +2 -0
  31. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/locales/zh.json +2 -0
  32. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/__init__.py +2 -0
  33. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/config.py +9 -0
  34. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/config/settings.toml +1 -0
  35. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/screens/home.py +13 -6
  36. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/constants.py +0 -29
  37. {novel_downloader-1.4.1/novel_downloader/utils → novel_downloader-1.4.3/novel_downloader/utils/fontocr}/model_loader.py +2 -2
  38. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/fontocr/ocr_v1.py +2 -1
  39. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/fontocr/ocr_v2.py +2 -1
  40. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/text_utils/__init__.py +8 -1
  41. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/text_utils/text_cleaning.py +51 -0
  42. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader.egg-info/PKG-INFO +5 -2
  43. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader.egg-info/SOURCES.txt +2 -7
  44. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader.egg-info/requires.txt +1 -1
  45. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/pyproject.toml +3 -3
  46. novel_downloader-1.4.1/novel_downloader/core/exporters/common/epub.py +0 -192
  47. novel_downloader-1.4.1/novel_downloader/core/exporters/epub_utils/__init__.py +0 -40
  48. novel_downloader-1.4.1/novel_downloader/core/exporters/epub_utils/css_builder.py +0 -75
  49. novel_downloader-1.4.1/novel_downloader/core/exporters/epub_utils/image_loader.py +0 -131
  50. novel_downloader-1.4.1/novel_downloader/core/exporters/epub_utils/initializer.py +0 -100
  51. novel_downloader-1.4.1/novel_downloader/core/exporters/epub_utils/text_to_html.py +0 -178
  52. novel_downloader-1.4.1/novel_downloader/core/exporters/epub_utils/volume_intro.py +0 -60
  53. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/LICENSE +0 -0
  54. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/cli/__init__.py +0 -0
  55. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/cli/clean.py +0 -0
  56. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/cli/config.py +0 -0
  57. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/cli/export.py +0 -0
  58. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/cli/main.py +0 -0
  59. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/config/__init__.py +0 -0
  60. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/config/loader.py +0 -0
  61. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/config/site_rules.py +0 -0
  62. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/downloaders/__init__.py +0 -0
  63. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/__init__.py +0 -0
  64. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/base.py +0 -0
  65. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/biquge.py +0 -0
  66. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/common/__init__.py +0 -0
  67. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/common/main_exporter.py +0 -0
  68. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/common/txt.py +0 -0
  69. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/esjzone.py +0 -0
  70. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/linovelib/__init__.py +0 -0
  71. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/linovelib/main_exporter.py +0 -0
  72. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/linovelib/txt.py +0 -0
  73. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/qianbi.py +0 -0
  74. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/qidian.py +0 -0
  75. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/sfacg.py +0 -0
  76. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/exporters/yamibo.py +0 -0
  77. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/factory/__init__.py +0 -0
  78. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/factory/exporter.py +0 -0
  79. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/factory/fetcher.py +0 -0
  80. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/factory/parser.py +0 -0
  81. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/__init__.py +0 -0
  82. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/base/__init__.py +0 -0
  83. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/base/rate_limiter.py +0 -0
  84. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/base/session.py +0 -0
  85. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/biquge/__init__.py +0 -0
  86. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/biquge/browser.py +0 -0
  87. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/biquge/session.py +0 -0
  88. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/common/__init__.py +0 -0
  89. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/common/browser.py +0 -0
  90. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/common/session.py +0 -0
  91. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/esjzone/__init__.py +0 -0
  92. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/esjzone/session.py +0 -0
  93. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/linovelib/__init__.py +0 -0
  94. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/linovelib/browser.py +0 -0
  95. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/linovelib/session.py +0 -0
  96. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/qianbi/__init__.py +0 -0
  97. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/qianbi/browser.py +0 -0
  98. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/qianbi/session.py +0 -0
  99. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/qidian/__init__.py +0 -0
  100. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/qidian/session.py +0 -0
  101. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/sfacg/__init__.py +0 -0
  102. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/sfacg/browser.py +0 -0
  103. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/sfacg/session.py +0 -0
  104. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/yamibo/__init__.py +0 -0
  105. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/fetchers/yamibo/session.py +0 -0
  106. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/interfaces/__init__.py +0 -0
  107. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/interfaces/exporter.py +0 -0
  108. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/interfaces/fetcher.py +0 -0
  109. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/interfaces/parser.py +0 -0
  110. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/__init__.py +0 -0
  111. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/base.py +0 -0
  112. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/biquge/__init__.py +0 -0
  113. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/biquge/main_parser.py +0 -0
  114. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/common/__init__.py +0 -0
  115. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/common/helper.py +0 -0
  116. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/common/main_parser.py +0 -0
  117. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/esjzone/__init__.py +0 -0
  118. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/esjzone/main_parser.py +0 -0
  119. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/linovelib/__init__.py +0 -0
  120. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/linovelib/main_parser.py +0 -0
  121. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qianbi/__init__.py +0 -0
  122. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qianbi/main_parser.py +0 -0
  123. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/__init__.py +0 -0
  124. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/book_info_parser.py +0 -0
  125. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/chapter_router.py +0 -0
  126. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/utils/decryptor_fetcher.py +0 -0
  127. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/qidian/utils/node_decryptor.py +0 -0
  128. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/sfacg/__init__.py +0 -0
  129. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/sfacg/main_parser.py +0 -0
  130. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/yamibo/__init__.py +0 -0
  131. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/core/parsers/yamibo/main_parser.py +0 -0
  132. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/browser.py +0 -0
  133. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/chapter.py +0 -0
  134. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/login.py +0 -0
  135. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/site_rules.py +0 -0
  136. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/tasks.py +0 -0
  137. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/models/types.py +0 -0
  138. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/css_styles/main.css +0 -0
  139. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/css_styles/volume-intro.css +0 -0
  140. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/images/volume_border.png +0 -0
  141. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/js_scripts/qidian_decrypt_node.js +0 -0
  142. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/json/linovelib_font_map.json +0 -0
  143. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/json/replace_word_map.json +0 -0
  144. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/resources/text/blacklist.txt +0 -0
  145. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/__init__.py +0 -0
  146. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/app.py +0 -0
  147. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/main.py +0 -0
  148. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/screens/__init__.py +0 -0
  149. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/screens/login.py +0 -0
  150. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/styles/home_layout.tcss +0 -0
  151. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/tui/widgets/richlog_handler.py +0 -0
  152. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/__init__.py +0 -0
  153. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/cache.py +0 -0
  154. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/chapter_storage.py +0 -0
  155. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/cookies.py +0 -0
  156. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/crypto_utils.py +0 -0
  157. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/file_utils/__init__.py +0 -0
  158. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/file_utils/io.py +0 -0
  159. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/file_utils/normalize.py +0 -0
  160. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/file_utils/sanitize.py +0 -0
  161. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/fontocr/__init__.py +0 -0
  162. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/hash_store.py +0 -0
  163. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/hash_utils.py +0 -0
  164. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/i18n.py +0 -0
  165. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/logger.py +0 -0
  166. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/network.py +0 -0
  167. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/state.py +0 -0
  168. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/text_utils/chapter_formatting.py +0 -0
  169. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/text_utils/diff_display.py +0 -0
  170. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/text_utils/font_mapping.py +0 -0
  171. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/time_utils/__init__.py +0 -0
  172. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/time_utils/datetime_utils.py +0 -0
  173. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader/utils/time_utils/sleep_utils.py +0 -0
  174. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader.egg-info/dependency_links.txt +0 -0
  175. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader.egg-info/entry_points.txt +0 -0
  176. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/novel_downloader.egg-info/top_level.txt +0 -0
  177. {novel_downloader-1.4.1 → novel_downloader-1.4.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: novel-downloader
3
- Version: 1.4.1
3
+ Version: 1.4.3
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 模式
@@ -180,6 +182,7 @@ pip install .
180
182
  - [CLI 使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-cli-usage-examples.md)
181
183
  - [复制 Cookies](https://github.com/BowenZ217/novel-downloader/blob/main/docs/copy-cookies.md)
182
184
  - [文件保存](https://github.com/BowenZ217/novel-downloader/blob/main/docs/file-saving.md)
185
+ - [模块与接口文档](https://github.com/BowenZ217/novel-downloader/blob/main/docs/api/README.md)
183
186
  - [TODO](https://github.com/BowenZ217/novel-downloader/blob/main/docs/todo.md)
184
187
  - [开发](https://github.com/BowenZ217/novel-downloader/blob/main/docs/develop.md)
185
188
  - [项目说明](#项目说明)
@@ -38,6 +38,8 @@ playwright install
38
38
  pip install novel-downloader[font-recovery]
39
39
  ```
40
40
 
41
+ - 详细可见: [安装](https://github.com/BowenZ217/novel-downloader/blob/main/docs/1-installation.md)
42
+
41
43
  ---
42
44
 
43
45
  ### CLI 模式
@@ -109,6 +111,7 @@ pip install .
109
111
  - [CLI 使用示例](https://github.com/BowenZ217/novel-downloader/blob/main/docs/6-cli-usage-examples.md)
110
112
  - [复制 Cookies](https://github.com/BowenZ217/novel-downloader/blob/main/docs/copy-cookies.md)
111
113
  - [文件保存](https://github.com/BowenZ217/novel-downloader/blob/main/docs/file-saving.md)
114
+ - [模块与接口文档](https://github.com/BowenZ217/novel-downloader/blob/main/docs/api/README.md)
112
115
  - [TODO](https://github.com/BowenZ217/novel-downloader/blob/main/docs/todo.md)
113
116
  - [开发](https://github.com/BowenZ217/novel-downloader/blob/main/docs/develop.md)
114
117
  - [项目说明](#项目说明)
@@ -6,7 +6,7 @@ novel_downloader
6
6
  Core package for the Novel Downloader project.
7
7
  """
8
8
 
9
- __version__ = "1.4.1"
9
+ __version__ = "1.4.3"
10
10
 
11
11
  __author__ = "Saudade Z"
12
12
  __email__ = "saudadez217@gmail.com"
@@ -9,6 +9,7 @@ Download novels from supported sites via CLI.
9
9
  import asyncio
10
10
  import getpass
11
11
  from argparse import Namespace, _SubParsersAction
12
+ from collections.abc import Iterable
12
13
  from dataclasses import asdict
13
14
  from pathlib import Path
14
15
  from typing import Any
@@ -21,7 +22,7 @@ from novel_downloader.core.factory import (
21
22
  get_parser,
22
23
  )
23
24
  from novel_downloader.core.interfaces import FetcherProtocol
24
- from novel_downloader.models import LoginField
25
+ from novel_downloader.models import BookConfig, LoginField
25
26
  from novel_downloader.utils.cookies import resolve_cookies
26
27
  from novel_downloader.utils.i18n import t
27
28
  from novel_downloader.utils.logger import setup_logging
@@ -36,6 +37,9 @@ def register_download_subcommand(subparsers: _SubParsersAction) -> None: # type
36
37
  )
37
38
  parser.add_argument("--config", type=str, help=t("help_config"))
38
39
 
40
+ parser.add_argument("--start", type=str, help=t("download_option_start"))
41
+ parser.add_argument("--end", type=str, help=t("download_option_end"))
42
+
39
43
  parser.set_defaults(func=handle_download)
40
44
 
41
45
 
@@ -44,7 +48,11 @@ def handle_download(args: Namespace) -> None:
44
48
 
45
49
  site: str = args.site
46
50
  config_path: Path | None = Path(args.config) if args.config else None
47
- book_ids: list[str] = args.book_ids or []
51
+ book_ids: list[BookConfig] = _cli_args_to_book_configs(
52
+ args.book_ids,
53
+ args.start,
54
+ args.end,
55
+ )
48
56
 
49
57
  print(t("download_site_info", site=site))
50
58
 
@@ -63,25 +71,73 @@ def handle_download(args: Namespace) -> None:
63
71
  print(t("download_fail_get_ids", err=str(e)))
64
72
  return
65
73
 
66
- invalid_ids = {"0000000000"}
67
- valid_book_ids = set(book_ids) - invalid_ids
74
+ valid_books = _filter_valid_book_configs(book_ids)
68
75
 
69
76
  if not book_ids:
70
77
  print(t("download_no_ids"))
71
78
  return
72
79
 
73
- if not valid_book_ids:
80
+ if not valid_books:
74
81
  print(t("download_only_example", example="0000000000"))
75
82
  print(t("download_edit_config"))
76
83
  return
77
84
 
78
- asyncio.run(_download(adapter, site, valid_book_ids))
85
+ asyncio.run(_download(adapter, site, valid_books))
86
+
87
+
88
+ def _cli_args_to_book_configs(
89
+ book_ids: list[str],
90
+ start_id: str | None,
91
+ end_id: str | None,
92
+ ) -> list[BookConfig]:
93
+ """
94
+ Convert CLI book_ids and optional --start/--end into a list of BookConfig.
95
+ Only the first book_id uses start/end; others are minimal.
96
+ """
97
+ if not book_ids:
98
+ return []
99
+
100
+ result: list[BookConfig] = []
101
+
102
+ first: BookConfig = {"book_id": book_ids[0]}
103
+ if start_id:
104
+ first["start_id"] = start_id
105
+ if end_id:
106
+ first["end_id"] = end_id
107
+ result.append(first)
108
+
109
+ for book_id in book_ids[1:]:
110
+ result.append({"book_id": book_id})
111
+
112
+ return result
113
+
114
+
115
+ def _filter_valid_book_configs(
116
+ books: list[BookConfig],
117
+ invalid_ids: Iterable[str] = ("0000000000",),
118
+ ) -> list[BookConfig]:
119
+ """
120
+ Filter a list of BookConfig:
121
+ - Removes entries with invalid or placeholder book_ids
122
+ - Deduplicates based on book_id while preserving order
123
+ """
124
+ seen = set(invalid_ids)
125
+ result: list[BookConfig] = []
126
+
127
+ for book in books:
128
+ book_id = book["book_id"]
129
+ if book_id in seen:
130
+ continue
131
+ seen.add(book_id)
132
+ result.append(book)
133
+
134
+ return result
79
135
 
80
136
 
81
137
  async def _download(
82
138
  adapter: ConfigAdapter,
83
139
  site: str,
84
- valid_book_ids: set[str],
140
+ valid_books: list[BookConfig],
85
141
  ) -> None:
86
142
  downloader_cfg = adapter.get_downloader_config()
87
143
  fetcher_cfg = adapter.get_fetcher_config()
@@ -105,14 +161,17 @@ async def _download(
105
161
  downloader = get_downloader(
106
162
  fetcher=fetcher,
107
163
  parser=parser,
108
- exporter=exporter,
109
164
  site=site,
110
165
  config=downloader_cfg,
111
166
  )
112
167
 
113
- for book_id in valid_book_ids:
114
- print(t("download_downloading", book_id=book_id, site=site))
115
- await downloader.download(book_id, progress_hook=_print_progress)
168
+ for book in valid_books:
169
+ print(t("download_downloading", book_id=book["book_id"], site=site))
170
+ await downloader.download(
171
+ book,
172
+ progress_hook=_print_progress,
173
+ )
174
+ await asyncio.to_thread(exporter.export, book["book_id"])
116
175
 
117
176
  if downloader_cfg.login_required and fetcher.is_logged_in:
118
177
  await fetcher.save_state()
@@ -10,6 +10,7 @@ site name into structured dataclass-based config models.
10
10
  from typing import Any
11
11
 
12
12
  from novel_downloader.models import (
13
+ BookConfig,
13
14
  DownloaderConfig,
14
15
  ExporterConfig,
15
16
  FetcherConfig,
@@ -126,6 +127,7 @@ class ConfigAdapter:
126
127
  site_cfg = self._get_site_cfg()
127
128
  return ParserConfig(
128
129
  cache_dir=gen.get("cache_dir", "./novel_cache"),
130
+ use_truncation=site_cfg.get("use_truncation", True),
129
131
  decode_font=font_ocr.get("decode_font", False),
130
132
  use_freq=font_ocr.get("use_freq", False),
131
133
  use_ocr=font_ocr.get("use_ocr", True),
@@ -169,22 +171,54 @@ class ConfigAdapter:
169
171
  split_mode=site_cfg.get("split_mode", "book"),
170
172
  )
171
173
 
172
- def get_book_ids(self) -> list[str]:
174
+ def get_book_ids(self) -> list[BookConfig]:
173
175
  """
174
176
  从 config["sites"][site]["book_ids"] 中提取目标书籍列表
175
177
  """
176
178
  site_cfg = self._get_site_cfg()
177
- raw_ids = site_cfg.get("book_ids", [])
179
+ raw = site_cfg.get("book_ids", [])
178
180
 
179
- if isinstance(raw_ids, str):
180
- return [raw_ids]
181
+ if isinstance(raw, str | int):
182
+ return [{"book_id": str(raw)}]
181
183
 
182
- if isinstance(raw_ids, int):
183
- return [str(raw_ids)]
184
+ if isinstance(raw, dict):
185
+ return [self._dict_to_book_config(raw)]
184
186
 
185
- if not isinstance(raw_ids, list):
187
+ if not isinstance(raw, list):
186
188
  raise ValueError(
187
- f"book_ids must be a list or string, got {type(raw_ids).__name__}"
189
+ f"book_ids must be a list or string, got {type(raw).__name__}"
188
190
  )
189
191
 
190
- return [str(book_id) for book_id in raw_ids]
192
+ result: list[BookConfig] = []
193
+ for item in raw:
194
+ try:
195
+ if isinstance(item, str | int):
196
+ result.append({"book_id": str(item)})
197
+ elif isinstance(item, dict):
198
+ result.append(self._dict_to_book_config(item))
199
+ except ValueError:
200
+ continue
201
+
202
+ return result
203
+
204
+ @staticmethod
205
+ def _dict_to_book_config(data: dict[str, Any]) -> BookConfig:
206
+ """
207
+ Converts a dict to BookConfig with type normalization.
208
+ Raises ValueError if 'book_id' is missing.
209
+ """
210
+ if "book_id" not in data:
211
+ raise ValueError("Missing required field 'book_id'")
212
+
213
+ result: BookConfig = {"book_id": str(data["book_id"])}
214
+
215
+ if "start_id" in data:
216
+ result["start_id"] = str(data["start_id"])
217
+
218
+ if "end_id" in data:
219
+ result["end_id"] = str(data["end_id"])
220
+
221
+ if "ignore_ids" in data:
222
+ result["ignore_ids"] = [str(x) for x in data["ignore_ids"]]
223
+
224
+ return result
@@ -14,8 +14,26 @@ downloading and processing online novel content, including:
14
14
  - Exporter: Responsible for exporting downloaded data into various output formats.
15
15
  """
16
16
 
17
- from .factory import get_parser
17
+ from .factory import (
18
+ get_downloader,
19
+ get_exporter,
20
+ get_fetcher,
21
+ get_parser,
22
+ )
23
+ from .interfaces import (
24
+ DownloaderProtocol,
25
+ ExporterProtocol,
26
+ FetcherProtocol,
27
+ ParserProtocol,
28
+ )
18
29
 
19
30
  __all__ = [
31
+ "get_downloader",
32
+ "get_exporter",
33
+ "get_fetcher",
20
34
  "get_parser",
35
+ "DownloaderProtocol",
36
+ "ExporterProtocol",
37
+ "FetcherProtocol",
38
+ "ParserProtocol",
21
39
  ]
@@ -15,11 +15,10 @@ from typing import Any
15
15
 
16
16
  from novel_downloader.core.interfaces import (
17
17
  DownloaderProtocol,
18
- ExporterProtocol,
19
18
  FetcherProtocol,
20
19
  ParserProtocol,
21
20
  )
22
- from novel_downloader.models import DownloaderConfig
21
+ from novel_downloader.models import BookConfig, DownloaderConfig
23
22
 
24
23
 
25
24
  class BaseDownloader(DownloaderProtocol, abc.ABC):
@@ -34,13 +33,11 @@ class BaseDownloader(DownloaderProtocol, abc.ABC):
34
33
  self,
35
34
  fetcher: FetcherProtocol,
36
35
  parser: ParserProtocol,
37
- exporter: ExporterProtocol,
38
36
  config: DownloaderConfig,
39
37
  site: str,
40
38
  ):
41
39
  self._fetcher = fetcher
42
40
  self._parser = parser
43
- self._exporter = exporter
44
41
  self._config = config
45
42
  self._site = site
46
43
 
@@ -53,7 +50,7 @@ class BaseDownloader(DownloaderProtocol, abc.ABC):
53
50
 
54
51
  async def download_many(
55
52
  self,
56
- book_ids: list[str],
53
+ books: list[BookConfig],
57
54
  *,
58
55
  progress_hook: Callable[[int, int], Awaitable[None]] | None = None,
59
56
  **kwargs: Any,
@@ -61,33 +58,34 @@ class BaseDownloader(DownloaderProtocol, abc.ABC):
61
58
  """
62
59
  Download multiple books with pre-download hook and error handling.
63
60
 
64
- :param book_ids: A list of book identifiers to download.
65
- :param progress_hook: (optional) Called after each chapter;
61
+ :param books: List of BookConfig entries.
62
+ :param progress_hook: Optional async callback after each chapter.
66
63
  args: completed_count, total_count.
67
64
  """
68
65
  if not await self._ensure_ready():
66
+ book_ids = [b["book_id"] for b in books]
69
67
  self.logger.warning(
70
- "[%s] login failed, skipping download of %s",
68
+ "[%s] login failed, skipping download of books: %s",
71
69
  self._site,
72
- book_ids,
70
+ ", ".join(book_ids) or "<none>",
73
71
  )
74
72
  return
75
73
 
76
- for book_id in book_ids:
74
+ for book in books:
77
75
  try:
78
76
  await self._download_one(
79
- book_id,
77
+ book,
80
78
  progress_hook=progress_hook,
81
79
  **kwargs,
82
80
  )
83
81
  except Exception as e:
84
- self._handle_download_exception(book_id, e)
82
+ self._handle_download_exception(book, e)
85
83
 
86
84
  await self._finalize()
87
85
 
88
86
  async def download(
89
87
  self,
90
- book_id: str,
88
+ book: BookConfig,
91
89
  *,
92
90
  progress_hook: Callable[[int, int], Awaitable[None]] | None = None,
93
91
  **kwargs: Any,
@@ -95,33 +93,34 @@ class BaseDownloader(DownloaderProtocol, abc.ABC):
95
93
  """
96
94
  Download a single book with pre-download hook and error handling.
97
95
 
98
- :param book_id: The identifier of the book to download.
99
- :param progress_hook: (optional) Called after each chapter;
96
+ :param book: BookConfig with at least 'book_id'.
97
+ :param progress_hook: Optional async callback after each chapter.
100
98
  args: completed_count, total_count.
101
99
  """
102
100
  if not await self._ensure_ready():
103
101
  self.logger.warning(
104
- "[%s] login failed, skipping download of %s",
102
+ "[%s] login failed, skipping download of book: %s (%s-%s)",
105
103
  self._site,
106
- book_id,
104
+ book["book_id"],
105
+ book.get("start_id", "-"),
106
+ book.get("end_id", "-"),
107
107
  )
108
- return
109
108
 
110
109
  try:
111
110
  await self._download_one(
112
- book_id,
111
+ book,
113
112
  progress_hook=progress_hook,
114
113
  **kwargs,
115
114
  )
116
115
  except Exception as e:
117
- self._handle_download_exception(book_id, e)
116
+ self._handle_download_exception(book, e)
118
117
 
119
118
  await self._finalize()
120
119
 
121
120
  @abc.abstractmethod
122
121
  async def _download_one(
123
122
  self,
124
- book_id: str,
123
+ book: BookConfig,
125
124
  *,
126
125
  progress_hook: Callable[[int, int], Awaitable[None]] | None = None,
127
126
  **kwargs: Any,
@@ -156,10 +155,6 @@ class BaseDownloader(DownloaderProtocol, abc.ABC):
156
155
  def parser(self) -> ParserProtocol:
157
156
  return self._parser
158
157
 
159
- @property
160
- def exporter(self) -> ExporterProtocol:
161
- return self._exporter
162
-
163
158
  @property
164
159
  def config(self) -> DownloaderConfig:
165
160
  return self._config
@@ -208,19 +203,21 @@ class BaseDownloader(DownloaderProtocol, abc.ABC):
208
203
  def download_workers(self) -> int:
209
204
  return self._config.download_workers
210
205
 
211
- def _handle_download_exception(self, book_id: str, error: Exception) -> None:
206
+ def _handle_download_exception(self, book: BookConfig, error: Exception) -> None:
212
207
  """
213
208
  Handle download errors in a consistent way.
214
209
 
215
210
  This method can be overridden or extended to implement retry logic, etc.
216
211
 
217
- :param book_id: The ID of the book that failed.
212
+ :param book: The book that failed.
218
213
  :param error: The exception raised during download.
219
214
  """
220
215
  self.logger.warning(
221
- "[%s] Failed to download %r: %s",
216
+ "[%s] Failed to download (book_id=%s, start=%s, end=%s): %s",
222
217
  self.__class__.__name__,
223
- book_id,
218
+ book.get("book_id", "<unknown>"),
219
+ book.get("start_id", "-"),
220
+ book.get("end_id", "-"),
224
221
  error,
225
222
  )
226
223
 
@@ -7,7 +7,6 @@ novel_downloader.core.downloaders.biquge
7
7
 
8
8
  from novel_downloader.core.downloaders.common import CommonDownloader
9
9
  from novel_downloader.core.interfaces import (
10
- ExporterProtocol,
11
10
  FetcherProtocol,
12
11
  ParserProtocol,
13
12
  )
@@ -21,7 +20,6 @@ class BiqugeDownloader(CommonDownloader):
21
20
  self,
22
21
  fetcher: FetcherProtocol,
23
22
  parser: ParserProtocol,
24
- exporter: ExporterProtocol,
25
23
  config: DownloaderConfig,
26
24
  ):
27
- super().__init__(fetcher, parser, exporter, config, "biquge")
25
+ super().__init__(fetcher, parser, config, "biquge")
@@ -12,7 +12,13 @@ from contextlib import suppress
12
12
  from typing import Any, cast
13
13
 
14
14
  from novel_downloader.core.downloaders.base import BaseDownloader
15
- from novel_downloader.models import ChapterDict, CidTask, HtmlTask, RestoreTask
15
+ from novel_downloader.models import (
16
+ BookConfig,
17
+ ChapterDict,
18
+ CidTask,
19
+ HtmlTask,
20
+ RestoreTask,
21
+ )
16
22
  from novel_downloader.utils.chapter_storage import ChapterStorage
17
23
  from novel_downloader.utils.file_utils import save_as_json, save_as_txt
18
24
  from novel_downloader.utils.time_utils import (
@@ -28,7 +34,7 @@ class CommonDownloader(BaseDownloader):
28
34
 
29
35
  async def _download_one(
30
36
  self,
31
- book_id: str,
37
+ book: BookConfig,
32
38
  *,
33
39
  progress_hook: Callable[[int, int], Awaitable[None]] | None = None,
34
40
  **kwargs: Any,
@@ -36,9 +42,13 @@ class CommonDownloader(BaseDownloader):
36
42
  """
37
43
  The full download logic for a single book.
38
44
 
39
- :param book_id: The identifier of the book to download.
45
+ :param book: BookConfig with at least 'book_id'.
40
46
  """
41
47
  TAG = "[Downloader]"
48
+ book_id = book["book_id"]
49
+ start_id = book.get("start_id")
50
+ end_id = book.get("end_id")
51
+ ignore_set = set(book.get("ignore_ids", []))
42
52
 
43
53
  raw_base = self.raw_data_dir / book_id
44
54
  cache_base = self.cache_dir / book_id
@@ -145,6 +155,10 @@ class CommonDownloader(BaseDownloader):
145
155
  cid_queue.task_done()
146
156
  continue
147
157
 
158
+ if cid in ignore_set:
159
+ cid_queue.task_done()
160
+ continue
161
+
148
162
  try:
149
163
  async with semaphore:
150
164
  html_list = await self.fetcher.get_book_chapter(book_id, cid)
@@ -369,15 +383,33 @@ class CommonDownloader(BaseDownloader):
369
383
  )
370
384
  )
371
385
 
386
+ found_start = start_id is None
387
+ stop_early = False
372
388
  last_cid: str | None = None
389
+
373
390
  for vol_idx, vol in enumerate(vols):
374
391
  chapters = vol.get("chapters", [])
375
392
  for chap_idx, chap in enumerate(chapters):
393
+ if stop_early:
394
+ break
395
+
376
396
  cid = chap.get("chapterId")
397
+
398
+ # Skip until reaching start_id
399
+ if not found_start:
400
+ if cid == start_id:
401
+ found_start = True
402
+ else:
403
+ completed_count += 1
404
+ last_cid = cid
405
+ continue
406
+
407
+ # Stop when reaching end_id
408
+ if end_id is not None and cid == end_id:
409
+ stop_early = True
410
+
377
411
  if cid and normal_cs.exists(cid) and self.skip_existing:
378
412
  completed_count += 1
379
- if progress_hook:
380
- await progress_hook(completed_count, total_chapters)
381
413
  last_cid = cid
382
414
  continue
383
415
 
@@ -389,8 +421,12 @@ class CommonDownloader(BaseDownloader):
389
421
  prev_cid=last_cid,
390
422
  )
391
423
  )
424
+
392
425
  last_cid = cid
393
426
 
427
+ if stop_early:
428
+ break
429
+
394
430
  await restore_queue.join()
395
431
  await cid_queue.join()
396
432
  await html_queue.join()
@@ -404,8 +440,6 @@ class CommonDownloader(BaseDownloader):
404
440
  normal_cs.close()
405
441
  save_as_json(book_info, info_path)
406
442
 
407
- await asyncio.to_thread(self.exporter.export, book_id)
408
-
409
443
  self.logger.info(
410
444
  "%s Novel '%s' download completed.",
411
445
  TAG,
@@ -7,7 +7,6 @@ novel_downloader.core.downloaders.esjzone
7
7
 
8
8
  from novel_downloader.core.downloaders.common import CommonDownloader
9
9
  from novel_downloader.core.interfaces import (
10
- ExporterProtocol,
11
10
  FetcherProtocol,
12
11
  ParserProtocol,
13
12
  )
@@ -21,7 +20,6 @@ class EsjzoneDownloader(CommonDownloader):
21
20
  self,
22
21
  fetcher: FetcherProtocol,
23
22
  parser: ParserProtocol,
24
- exporter: ExporterProtocol,
25
23
  config: DownloaderConfig,
26
24
  ):
27
- super().__init__(fetcher, parser, exporter, config, "esjzone")
25
+ super().__init__(fetcher, parser, config, "esjzone")
@@ -7,7 +7,6 @@ novel_downloader.core.downloaders.linovelib
7
7
 
8
8
  from novel_downloader.core.downloaders.common import CommonDownloader
9
9
  from novel_downloader.core.interfaces import (
10
- ExporterProtocol,
11
10
  FetcherProtocol,
12
11
  ParserProtocol,
13
12
  )
@@ -21,7 +20,6 @@ class LinovelibDownloader(CommonDownloader):
21
20
  self,
22
21
  fetcher: FetcherProtocol,
23
22
  parser: ParserProtocol,
24
- exporter: ExporterProtocol,
25
23
  config: DownloaderConfig,
26
24
  ):
27
- super().__init__(fetcher, parser, exporter, config, "linovelib")
25
+ super().__init__(fetcher, parser, config, "linovelib")
@@ -7,7 +7,6 @@ novel_downloader.core.downloaders.qianbi
7
7
 
8
8
  from novel_downloader.core.downloaders.common import CommonDownloader
9
9
  from novel_downloader.core.interfaces import (
10
- ExporterProtocol,
11
10
  FetcherProtocol,
12
11
  ParserProtocol,
13
12
  )
@@ -21,7 +20,6 @@ class QianbiDownloader(CommonDownloader):
21
20
  self,
22
21
  fetcher: FetcherProtocol,
23
22
  parser: ParserProtocol,
24
- exporter: ExporterProtocol,
25
23
  config: DownloaderConfig,
26
24
  ):
27
- super().__init__(fetcher, parser, exporter, config, "qianbi")
25
+ super().__init__(fetcher, parser, config, "qianbi")