novel-downloader 1.2.2__py3-none-any.whl → 1.3.1__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.
- novel_downloader/__init__.py +1 -2
- novel_downloader/cli/__init__.py +0 -1
- novel_downloader/cli/clean.py +2 -10
- novel_downloader/cli/download.py +16 -22
- novel_downloader/cli/interactive.py +0 -1
- novel_downloader/cli/main.py +1 -3
- novel_downloader/cli/settings.py +8 -8
- novel_downloader/config/__init__.py +0 -1
- novel_downloader/config/adapter.py +32 -27
- novel_downloader/config/loader.py +116 -108
- novel_downloader/config/models.py +35 -29
- novel_downloader/config/site_rules.py +2 -4
- novel_downloader/core/__init__.py +0 -1
- novel_downloader/core/downloaders/__init__.py +4 -4
- novel_downloader/core/downloaders/base/__init__.py +14 -0
- novel_downloader/core/downloaders/{base_async_downloader.py → base/base_async.py} +49 -53
- novel_downloader/core/downloaders/{base_downloader.py → base/base_sync.py} +64 -43
- novel_downloader/core/downloaders/biquge/__init__.py +12 -0
- novel_downloader/core/downloaders/biquge/biquge_sync.py +25 -0
- novel_downloader/core/downloaders/common/__init__.py +14 -0
- novel_downloader/core/downloaders/{common_asynb_downloader.py → common/common_async.py} +42 -33
- novel_downloader/core/downloaders/{common_downloader.py → common/common_sync.py} +33 -21
- novel_downloader/core/downloaders/qidian/__init__.py +10 -0
- novel_downloader/core/downloaders/{qidian_downloader.py → qidian/qidian_sync.py} +79 -62
- novel_downloader/core/factory/__init__.py +4 -5
- novel_downloader/core/factory/{downloader_factory.py → downloader.py} +25 -26
- novel_downloader/core/factory/{parser_factory.py → parser.py} +12 -14
- novel_downloader/core/factory/{requester_factory.py → requester.py} +29 -16
- novel_downloader/core/factory/{saver_factory.py → saver.py} +4 -9
- novel_downloader/core/interfaces/__init__.py +8 -9
- novel_downloader/core/interfaces/{async_downloader_protocol.py → async_downloader.py} +4 -5
- novel_downloader/core/interfaces/{async_requester_protocol.py → async_requester.py} +23 -12
- novel_downloader/core/interfaces/{parser_protocol.py → parser.py} +11 -6
- novel_downloader/core/interfaces/{saver_protocol.py → saver.py} +2 -3
- novel_downloader/core/interfaces/{downloader_protocol.py → sync_downloader.py} +6 -7
- novel_downloader/core/interfaces/{requester_protocol.py → sync_requester.py} +31 -17
- novel_downloader/core/parsers/__init__.py +5 -4
- novel_downloader/core/parsers/{base_parser.py → base.py} +18 -9
- novel_downloader/core/parsers/biquge/__init__.py +10 -0
- novel_downloader/core/parsers/biquge/main_parser.py +126 -0
- novel_downloader/core/parsers/{common_parser → common}/__init__.py +2 -3
- novel_downloader/core/parsers/{common_parser → common}/helper.py +13 -13
- novel_downloader/core/parsers/{common_parser → common}/main_parser.py +15 -9
- novel_downloader/core/parsers/{qidian_parser → qidian}/__init__.py +2 -3
- novel_downloader/core/parsers/{qidian_parser → qidian}/browser/__init__.py +2 -3
- novel_downloader/core/parsers/{qidian_parser → qidian}/browser/chapter_encrypted.py +40 -48
- novel_downloader/core/parsers/{qidian_parser → qidian}/browser/chapter_normal.py +17 -21
- novel_downloader/core/parsers/{qidian_parser → qidian}/browser/chapter_router.py +10 -9
- novel_downloader/core/parsers/{qidian_parser → qidian}/browser/main_parser.py +14 -10
- novel_downloader/core/parsers/{qidian_parser → qidian}/session/__init__.py +2 -3
- novel_downloader/core/parsers/{qidian_parser → qidian}/session/chapter_encrypted.py +36 -44
- novel_downloader/core/parsers/{qidian_parser → qidian}/session/chapter_normal.py +19 -23
- novel_downloader/core/parsers/{qidian_parser → qidian}/session/chapter_router.py +10 -9
- novel_downloader/core/parsers/{qidian_parser → qidian}/session/main_parser.py +14 -10
- novel_downloader/core/parsers/{qidian_parser → qidian}/session/node_decryptor.py +7 -10
- novel_downloader/core/parsers/{qidian_parser → qidian}/shared/__init__.py +2 -3
- novel_downloader/core/parsers/{qidian_parser → qidian}/shared/book_info_parser.py +5 -6
- novel_downloader/core/parsers/{qidian_parser → qidian}/shared/helpers.py +7 -8
- novel_downloader/core/requesters/__init__.py +9 -5
- novel_downloader/core/requesters/base/__init__.py +16 -0
- novel_downloader/core/requesters/{base_async_session.py → base/async_session.py} +177 -73
- novel_downloader/core/requesters/base/browser.py +340 -0
- novel_downloader/core/requesters/base/session.py +364 -0
- novel_downloader/core/requesters/biquge/__init__.py +12 -0
- novel_downloader/core/requesters/biquge/session.py +90 -0
- novel_downloader/core/requesters/{common_requester → common}/__init__.py +4 -5
- novel_downloader/core/requesters/common/async_session.py +96 -0
- novel_downloader/core/requesters/common/session.py +113 -0
- novel_downloader/core/requesters/qidian/__init__.py +21 -0
- novel_downloader/core/requesters/qidian/broswer.py +307 -0
- novel_downloader/core/requesters/qidian/session.py +287 -0
- novel_downloader/core/savers/__init__.py +5 -3
- novel_downloader/core/savers/{base_saver.py → base.py} +12 -13
- novel_downloader/core/savers/biquge.py +25 -0
- novel_downloader/core/savers/{common_saver → common}/__init__.py +2 -3
- novel_downloader/core/savers/{common_saver/common_epub.py → common/epub.py} +23 -51
- novel_downloader/core/savers/{common_saver → common}/main_saver.py +43 -9
- novel_downloader/core/savers/{common_saver/common_txt.py → common/txt.py} +16 -46
- novel_downloader/core/savers/epub_utils/__init__.py +0 -1
- novel_downloader/core/savers/epub_utils/css_builder.py +13 -7
- novel_downloader/core/savers/epub_utils/initializer.py +4 -5
- novel_downloader/core/savers/epub_utils/text_to_html.py +2 -3
- novel_downloader/core/savers/epub_utils/volume_intro.py +1 -3
- novel_downloader/core/savers/{qidian_saver.py → qidian.py} +12 -6
- novel_downloader/locales/en.json +8 -4
- novel_downloader/locales/zh.json +5 -1
- novel_downloader/resources/config/settings.toml +88 -0
- novel_downloader/utils/cache.py +2 -2
- novel_downloader/utils/chapter_storage.py +340 -0
- novel_downloader/utils/constants.py +6 -4
- novel_downloader/utils/crypto_utils.py +3 -3
- novel_downloader/utils/file_utils/__init__.py +0 -1
- novel_downloader/utils/file_utils/io.py +12 -17
- novel_downloader/utils/file_utils/normalize.py +1 -3
- novel_downloader/utils/file_utils/sanitize.py +2 -9
- novel_downloader/utils/fontocr/__init__.py +0 -1
- novel_downloader/utils/fontocr/ocr_v1.py +19 -22
- novel_downloader/utils/fontocr/ocr_v2.py +147 -60
- novel_downloader/utils/hash_store.py +19 -20
- novel_downloader/utils/hash_utils.py +0 -1
- novel_downloader/utils/i18n.py +3 -4
- novel_downloader/utils/logger.py +5 -6
- novel_downloader/utils/model_loader.py +5 -8
- novel_downloader/utils/network.py +9 -10
- novel_downloader/utils/state.py +6 -7
- novel_downloader/utils/text_utils/__init__.py +0 -1
- novel_downloader/utils/text_utils/chapter_formatting.py +2 -7
- novel_downloader/utils/text_utils/diff_display.py +0 -1
- novel_downloader/utils/text_utils/font_mapping.py +1 -4
- novel_downloader/utils/text_utils/text_cleaning.py +0 -1
- novel_downloader/utils/time_utils/__init__.py +0 -1
- novel_downloader/utils/time_utils/datetime_utils.py +8 -10
- novel_downloader/utils/time_utils/sleep_utils.py +1 -3
- {novel_downloader-1.2.2.dist-info → novel_downloader-1.3.1.dist-info}/METADATA +14 -17
- novel_downloader-1.3.1.dist-info/RECORD +127 -0
- {novel_downloader-1.2.2.dist-info → novel_downloader-1.3.1.dist-info}/WHEEL +1 -1
- novel_downloader/core/requesters/base_browser.py +0 -214
- novel_downloader/core/requesters/base_session.py +0 -246
- novel_downloader/core/requesters/common_requester/common_async_session.py +0 -98
- novel_downloader/core/requesters/common_requester/common_session.py +0 -126
- novel_downloader/core/requesters/qidian_requester/__init__.py +0 -22
- novel_downloader/core/requesters/qidian_requester/qidian_broswer.py +0 -396
- novel_downloader/core/requesters/qidian_requester/qidian_session.py +0 -202
- novel_downloader/resources/config/settings.yaml +0 -76
- novel_downloader-1.2.2.dist-info/RECORD +0 -115
- {novel_downloader-1.2.2.dist-info → novel_downloader-1.3.1.dist-info}/entry_points.txt +0 -0
- {novel_downloader-1.2.2.dist-info → novel_downloader-1.3.1.dist-info}/licenses/LICENSE +0 -0
- {novel_downloader-1.2.2.dist-info → novel_downloader-1.3.1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,127 @@
|
|
1
|
+
novel_downloader/__init__.py,sha256=Y0WoBdVWGywHUpWuZFqGD1AcO5ovZtJEFIEDGLJ6b8M,218
|
2
|
+
novel_downloader/cli/__init__.py,sha256=-2HAut_U1e67MZGdvbpEJ1n5J-bRchzto6L4c-nWeXY,174
|
3
|
+
novel_downloader/cli/clean.py,sha256=yjPDEoJRZnP_Xq-y0vA2ZhyNP-GxCM1UosW4gVR3VBI,3687
|
4
|
+
novel_downloader/cli/download.py,sha256=Q6ySIHalzX5qRTs_R1VH2xWpFbw88_UIiqYy0olxqeg,3995
|
5
|
+
novel_downloader/cli/interactive.py,sha256=7VLwKpDnSlNrA9biRu8v1bzur-khT5509RtW7EzFNvU,2130
|
6
|
+
novel_downloader/cli/main.py,sha256=JJdIEhMyjo_W2M-Uo3tstnSWDbmip9-UqSTVN6-YV3I,1128
|
7
|
+
novel_downloader/cli/settings.py,sha256=WOpy6aIsL4g_Zn_1kL4GEpkKiyxmgnTVMBhwJFo9J8s,6532
|
8
|
+
novel_downloader/config/__init__.py,sha256=-d48yLzDISMNUTxNTcAJGNKPXiZCB6Jv6yQBNO28A-8,1105
|
9
|
+
novel_downloader/config/adapter.py,sha256=kbqOHXHpf6TYxOPgkAa-4EzSKcpJEvzfm48iWaVQhMs,6965
|
10
|
+
novel_downloader/config/loader.py,sha256=EeMJqM0erh8lV-eYbd9TyrWmPRi7VEEkSTFb8YMxYHU,5745
|
11
|
+
novel_downloader/config/models.py,sha256=FE58OXH70eJE2R-TGSOWz2OaLjI9uvcEsyq-5uHrj48,5231
|
12
|
+
novel_downloader/config/site_rules.py,sha256=Win_tfW9jlpktfg4PZCl8R_GKqJaSbwL_9zIFUsF0WE,2964
|
13
|
+
novel_downloader/core/__init__.py,sha256=lg9azoOEI0W1pO1FgPLIJ2fUWLSYyNdng2NNR7Jl_NI,755
|
14
|
+
novel_downloader/core/downloaders/__init__.py,sha256=YCDQDJNkk2zAhXF4y6XuXjGNTJobdpSUZ8Kc40xDCi8,580
|
15
|
+
novel_downloader/core/downloaders/base/__init__.py,sha256=lGbWlGjbtP2GeHr9BJ4s56QDhA13XT66PX-SNkWjCo8,257
|
16
|
+
novel_downloader/core/downloaders/base/base_async.py,sha256=_lgq0Wzf5HebMCFub1zgGDJ74gprXpz0OqID9m80UoQ,4200
|
17
|
+
novel_downloader/core/downloaders/base/base_sync.py,sha256=En_8TVQOwqseee0y0bLHkLJc3xpohG-oRccgbK1gf4M,5824
|
18
|
+
novel_downloader/core/downloaders/biquge/__init__.py,sha256=uZgwfQxpPotRSi7WILOyybl4Ztjnmas2SLR3tXLXm6I,196
|
19
|
+
novel_downloader/core/downloaders/biquge/biquge_sync.py,sha256=T_9flRTQ-CRYuzCpsLxeFvR_lMFkzQiSTLNKfZWfJb0,785
|
20
|
+
novel_downloader/core/downloaders/common/__init__.py,sha256=KZwtl9K7ZhN8Nnnk9BBOVWZ-QJ5GQBsRAoG7x2OlVYM,273
|
21
|
+
novel_downloader/core/downloaders/common/common_async.py,sha256=SNgxQWkAIBj0_d5b-ClwP-T9CjPJimzgdWJXXsIyv58,7456
|
22
|
+
novel_downloader/core/downloaders/common/common_sync.py,sha256=vIPoH6bCm1vCHg5rW_HxZg9vehuS0Cy1wr3B97G0qhY,6966
|
23
|
+
novel_downloader/core/downloaders/qidian/__init__.py,sha256=LCdrqLI2iTCGERmlAwKtr-PKtvDh_rs2vKD891-ixvo,189
|
24
|
+
novel_downloader/core/downloaders/qidian/qidian_sync.py,sha256=hGm24AnKRjkKEPDUUdXmdYH34coC3iwo21kRSBIcdeI,8065
|
25
|
+
novel_downloader/core/factory/__init__.py,sha256=q9eT93OcyyUDoZxwhKWdgb_kUTIJ8nGSisH0wuiuBSw,687
|
26
|
+
novel_downloader/core/factory/downloader.py,sha256=7uxGPIAKGwyJ-OfmyCM8a3ON0M4sHz0p6rMie2o7ts4,4878
|
27
|
+
novel_downloader/core/factory/parser.py,sha256=h3KZIDArl66Q1qeI_h778snglhmRYrkS6872B9YiQgA,1684
|
28
|
+
novel_downloader/core/factory/requester.py,sha256=oY1x8eMn982BG6oSlt3gSyYy_eT7bJgph9Uj_FgMvcI,3283
|
29
|
+
novel_downloader/core/factory/saver.py,sha256=v0wb7XlbxNRyczrfkU1DXtFmp_HCjd7u4wM27mkamfQ,1144
|
30
|
+
novel_downloader/core/interfaces/__init__.py,sha256=ym_dJH0x9UCMvqgIiy9__Tkek7hy_LS_i56KhpOKnXQ,791
|
31
|
+
novel_downloader/core/interfaces/async_downloader.py,sha256=uMEOpbgYAK0aAVSdnnRVCoCAiwhggovz9mEBV6uPEpo,961
|
32
|
+
novel_downloader/core/interfaces/async_requester.py,sha256=_LPbfWw2uJf7r3RbLjUdRRJWQJrSLRsUFHyrXC3XEds,2139
|
33
|
+
novel_downloader/core/interfaces/parser.py,sha256=THAlFhZ8MPYtH_Ulbv6Cw_nKwekQDbLfsytsMMt3NzE,1331
|
34
|
+
novel_downloader/core/interfaces/saver.py,sha256=BjXNeQLTC7Bg5mGyFoL9Yq7V1kC53POjXOWG9BFVBf4,1580
|
35
|
+
novel_downloader/core/interfaces/sync_downloader.py,sha256=1QRH0aQFd_xwliMXUyiEhog2k2tj2pMkJBjJyKbx7cs,917
|
36
|
+
novel_downloader/core/interfaces/sync_requester.py,sha256=sMtJVWdqwAgar_yMSE-ZcivdUCJgvHjtZWX_c2mX-XA,1926
|
37
|
+
novel_downloader/core/parsers/__init__.py,sha256=4bO2zhVFqg02G6xZ8fm-r-_AexQgwpQ2iQepQV5PESw,524
|
38
|
+
novel_downloader/core/parsers/base.py,sha256=lyS9Uv95ttQePr5_JXt-tmLbgQBJMr13EvSgBRGoYSQ,3099
|
39
|
+
novel_downloader/core/parsers/biquge/__init__.py,sha256=oaLgBLdMW7DcdsEGXW-S91Z6_p5XmBcBIp7TX79hmV4,173
|
40
|
+
novel_downloader/core/parsers/biquge/main_parser.py,sha256=Dx4Oilqi-lpoRd8O99BSwI0qqvdVT_RCLGjDcm5ZhTc,4408
|
41
|
+
novel_downloader/core/parsers/common/__init__.py,sha256=MzNUUxvf7jmeO0LvQ_FRW0QLKuYVXkkTgJ4CxWZKF-Y,341
|
42
|
+
novel_downloader/core/parsers/common/helper.py,sha256=SSNES1AlGu5LqPXN61Rp6SmVgR4oKaI2gvLJfEYBsF4,12054
|
43
|
+
novel_downloader/core/parsers/common/main_parser.py,sha256=SaUxkcHl5UHKPzDVlHAUwAOyV1F6X1tDQZJJpeDCse8,2987
|
44
|
+
novel_downloader/core/parsers/qidian/__init__.py,sha256=-KvMBzggUaj5zeZKFpVbbx5GRJdykwaFPfxJc4KzF-Q,484
|
45
|
+
novel_downloader/core/parsers/qidian/browser/__init__.py,sha256=6oRiuhptJHjNh9lhfe9bjh2_9fKv9h8f_mv-VvCs48o,315
|
46
|
+
novel_downloader/core/parsers/qidian/browser/chapter_encrypted.py,sha256=UyBX5NqfCPappbVhMP_mPCYUsTJesgkOs_VjrCjlfj4,17407
|
47
|
+
novel_downloader/core/parsers/qidian/browser/chapter_normal.py,sha256=1I6PkrGEOjHvz-VRdjm9PfXFA8uInifkVYgw597Xqto,3014
|
48
|
+
novel_downloader/core/parsers/qidian/browser/chapter_router.py,sha256=92pczn5_had3I5i67bmt2Qeg4pmOh5MquYtwJ3_ByzE,2124
|
49
|
+
novel_downloader/core/parsers/qidian/browser/main_parser.py,sha256=dwqEUG60Il5tWCpA8NCmazegm4fqmuXgV9oq8wNm0fw,3898
|
50
|
+
novel_downloader/core/parsers/qidian/session/__init__.py,sha256=hNxcEkTgD7mTZukHjCQm7L62HBiT7GUCOu6JZjPYwTY,308
|
51
|
+
novel_downloader/core/parsers/qidian/session/chapter_encrypted.py,sha256=kGL8mClK-fThEVNw8FQEnFTqJhn7kaoapFjK01NCpEo,15727
|
52
|
+
novel_downloader/core/parsers/qidian/session/chapter_normal.py,sha256=T3UOKRf0ET-ngz0oMfsSRU_24ODIaJ_wWdNo0CDcabU,3688
|
53
|
+
novel_downloader/core/parsers/qidian/session/chapter_router.py,sha256=dHumd9itE8Scai_h7pctI0o21f6HL4DtMpZpSZg2KDk,2001
|
54
|
+
novel_downloader/core/parsers/qidian/session/main_parser.py,sha256=h6sE0XByX1gbdUAi1sDEgmJ2xBANsicX5DB8T1IDPwo,3989
|
55
|
+
novel_downloader/core/parsers/qidian/session/node_decryptor.py,sha256=qKJ6BDkshtQNSHmrjnsbIVvAX08g4MmwIrQFJmakvYU,5629
|
56
|
+
novel_downloader/core/parsers/qidian/shared/__init__.py,sha256=9Yb0qCiszbIfuUUQ1gHKcW1xjItHGJug8aM2cSKLcY8,940
|
57
|
+
novel_downloader/core/parsers/qidian/shared/book_info_parser.py,sha256=kKkRuF1QUA97VlX7XO7zcwAjWhjIqYB5onx_uzvjj6g,4809
|
58
|
+
novel_downloader/core/parsers/qidian/shared/helpers.py,sha256=xdzWMHaQI_7K-SEV8iUcIj577ys2B2eU_IbOIC7Ilwk,4249
|
59
|
+
novel_downloader/core/requesters/__init__.py,sha256=bBUdZtuWqWnjdhUx8Hu7iajsBY3T18JLRFobh-u_45w,718
|
60
|
+
novel_downloader/core/requesters/base/__init__.py,sha256=lIwwdQWDf83NbAikZGFKUnkSa2jKX4jqKnSy0_zRRlg,296
|
61
|
+
novel_downloader/core/requesters/base/async_session.py,sha256=xayGshZd1tb98kfuMjC4KF8DQlU_SeoPk6m6vowLr9E,13000
|
62
|
+
novel_downloader/core/requesters/base/browser.py,sha256=FY_H6MLvUZllFyeYcfWsvBJnMhfouVrsQs4i5WYy9Tw,10609
|
63
|
+
novel_downloader/core/requesters/base/session.py,sha256=x7PAU8f2Lk3B7n6gIg58Ul6MqK5btZLQKkidEpKuETk,10526
|
64
|
+
novel_downloader/core/requesters/biquge/__init__.py,sha256=T1PQXdHUEhR0WRltFW4aTOCWIF3isWXUFx-WjUXU99M,184
|
65
|
+
novel_downloader/core/requesters/biquge/session.py,sha256=toSdptICqGWknk_J5Ocb0yQ8oD0zXQDCiA1qbpXzTzA,2563
|
66
|
+
novel_downloader/core/requesters/common/__init__.py,sha256=QRYbc4QEUszv_bgBdKCXHq82K8MIUhgYDMnm3iceAzI,465
|
67
|
+
novel_downloader/core/requesters/common/async_session.py,sha256=5RwGAXmtCdeLCuMkqT_ZyERi1lYgOpUE1gTTf_f2uck,3051
|
68
|
+
novel_downloader/core/requesters/common/session.py,sha256=bqr4viPytTaD6XRuXEcSjSe6CfI9zABqhbITFvyrx-Y,3430
|
69
|
+
novel_downloader/core/requesters/qidian/__init__.py,sha256=DyiuNMoBVAVxMJspdElgQ8fvpf4gKtCAc_nqW4qQ0rM,506
|
70
|
+
novel_downloader/core/requesters/qidian/broswer.py,sha256=FxoHLqzO5_cN83qv6dH8STd06_h9sV84WJyTLaN4DUw,10699
|
71
|
+
novel_downloader/core/requesters/qidian/session.py,sha256=TsszpDnUQa5Lj0KpnQccowIS1APITnZ2v63OXbQmCtg,9036
|
72
|
+
novel_downloader/core/savers/__init__.py,sha256=Wnjy7te6uZtSbD_lo2wCBrMprATu8y-UAh-S-HEI9q4,427
|
73
|
+
novel_downloader/core/savers/base.py,sha256=7KCfDdE_Tq5nyoGGenXryd-nortwbJvZKteMsldCpi0,5514
|
74
|
+
novel_downloader/core/savers/biquge.py,sha256=8kZ6hcXuXmaizaKKytjy3LIGX5kMJRwgUJdhYzH5ajE,445
|
75
|
+
novel_downloader/core/savers/qidian.py,sha256=HtIz2SHLL-BZbVuahu6voKpgWtlli14_YYCA9qv7pMA,704
|
76
|
+
novel_downloader/core/savers/common/__init__.py,sha256=V5EbaRwmdXlQKi4Ce9SLstl0c9x9yTTRUB23rXFCvXw,256
|
77
|
+
novel_downloader/core/savers/common/epub.py,sha256=ZmTt3kAODa8lQKpgegbJY_7qcKQmoVQ8h5JPZYBSJbI,6370
|
78
|
+
novel_downloader/core/savers/common/main_saver.py,sha256=O-XFfDAlOun0kSBBHEIktwUcm47CsXgmFOkyK3fP_1M,3826
|
79
|
+
novel_downloader/core/savers/common/txt.py,sha256=nsYQp3-xti5uAj3r736ZKDg0gzrme2YoQ8bUTOG2jHk,4853
|
80
|
+
novel_downloader/core/savers/epub_utils/__init__.py,sha256=ZzOOsuHL9O0CsE9xl0vAcvxxlBz4AkDVOlTnsfNGN7Q,714
|
81
|
+
novel_downloader/core/savers/epub_utils/css_builder.py,sha256=sa8t72YNKkGeqC6dflXz1iefcpUqZ6t80VVZE91XfNw,2087
|
82
|
+
novel_downloader/core/savers/epub_utils/initializer.py,sha256=6qId5UTSjXnqSs9S9XrWGELAgq4fNut71CYIq7b6LQE,3199
|
83
|
+
novel_downloader/core/savers/epub_utils/text_to_html.py,sha256=omqob2yKFYru2dvHTQuGVQH9RH_VQXxMSopzwd_-6_I,4087
|
84
|
+
novel_downloader/core/savers/epub_utils/volume_intro.py,sha256=aJAdEU2YvYkX2sqnU5VkZ33XRfb5x083GdDmDXcQpUI,1771
|
85
|
+
novel_downloader/locales/en.json,sha256=Q7dkpaet_NyjMRIHiBaIu5JBz1pX3-VdffpcwYBZbRQ,5888
|
86
|
+
novel_downloader/locales/zh.json,sha256=Aq1zxm18-ijifsExK5kZeBLDV8drYRsHslsjJd9v9QU,5782
|
87
|
+
novel_downloader/resources/config/rules.toml,sha256=hrED6h3Z3cjSY5hRPQhp4TFAU5QXnN9xHfVABOJQNrM,4979
|
88
|
+
novel_downloader/resources/config/settings.toml,sha256=yLqI38FhY6d9_fiKUSsabIo_YRR3j8uRDTu85Bf70uQ,3769
|
89
|
+
novel_downloader/resources/css_styles/main.css,sha256=WM6GePwdOGgM86fbbOxQ0_0oerTBDZeQHt8zRVfcJp8,1617
|
90
|
+
novel_downloader/resources/css_styles/volume-intro.css,sha256=6gaUnNKkrb2w8tYJRq1BGD1FwbhT1I5W2GI_Zelo9G4,1156
|
91
|
+
novel_downloader/resources/images/volume_border.png,sha256=2dEVimnTHKOfLMhi7bhkh_5joWNnrqg8duomLSNOZx4,28613
|
92
|
+
novel_downloader/resources/js_scripts/qidian_decrypt_node.js,sha256=spNrk_gXI7pPW9abr4XGc2LASMe1UuN4BUe4cH24L8s,2195
|
93
|
+
novel_downloader/resources/json/replace_word_map.json,sha256=ptL9sGO9aK7rnnAaOIyZ0OiH7gaT0BhFzficzYZSDks,55
|
94
|
+
novel_downloader/resources/text/blacklist.txt,sha256=sovK9JgARZP3lud5b1EZgvv8LSVKPthf4ADpCSZZgQ8,154
|
95
|
+
novel_downloader/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
96
|
+
novel_downloader/utils/cache.py,sha256=_jVEWAaMGY86kWVnAuuIvJA_hA8dH2ClI7o3p99mEvE,618
|
97
|
+
novel_downloader/utils/chapter_storage.py,sha256=bbQ6mLvIzhWNUypIcgg6-nPo1_fIgGCOyQ3eejuvcK4,10100
|
98
|
+
novel_downloader/utils/constants.py,sha256=7qr6_w7bM-Xf-Pz6ZFgamsR9JNl7RgFNmHvSWN2fcgg,5507
|
99
|
+
novel_downloader/utils/crypto_utils.py,sha256=9uMNpg0rAWaoD3YsqDucFajPjoQuwEfeZDInUBISuSI,4166
|
100
|
+
novel_downloader/utils/hash_store.py,sha256=pFg2SzPF9sZqezNx-24jSDvYw4YMSBOpiIjyUbZx_r8,9739
|
101
|
+
novel_downloader/utils/hash_utils.py,sha256=oaXICmANsqImXW1qNSVmVQbMfNbx35FHe7EHL2VT2tM,2974
|
102
|
+
novel_downloader/utils/i18n.py,sha256=pdAcSIA5Tp-uPEBwNByHL7C1NayTnpOsl7zFv9p2G1k,1033
|
103
|
+
novel_downloader/utils/logger.py,sha256=n5xggOejtNdZv2X9f4Cq8weOaT1KG0n0-im2LIYycu0,3377
|
104
|
+
novel_downloader/utils/model_loader.py,sha256=JKgRFrr4HlAW9zuDUBAuuo_Kk_T_g9dWiU8E3zYk0vo,1996
|
105
|
+
novel_downloader/utils/network.py,sha256=2VX33jo11tzHSqvinpd0VoXDkXK_uxdxqaq50ndWXXg,8622
|
106
|
+
novel_downloader/utils/state.py,sha256=FcNJ85GvBu7uEIjy0QHGr4sXMbHPEMkCjwUKNg5EabI,5132
|
107
|
+
novel_downloader/utils/file_utils/__init__.py,sha256=zvOm2qSEmWd_mRGJceGBZb5MYMSDAlWYjS5MkVQNZgI,1159
|
108
|
+
novel_downloader/utils/file_utils/io.py,sha256=73uRrr41_Obqy9HMFBnvcOcApMZYBNi4KWT4DpskSk8,7472
|
109
|
+
novel_downloader/utils/file_utils/normalize.py,sha256=MrsCq4FqmskKRkHRV_J0z0dmn69OerMum-9sqx2XOGM,2023
|
110
|
+
novel_downloader/utils/file_utils/sanitize.py,sha256=rE-u4vpDL10zH8FT8d9wqwWsz-7dR6PJ-LE45K8VaeE,2112
|
111
|
+
novel_downloader/utils/fontocr/__init__.py,sha256=fe-04om3xxBvFKt5BBCApXCzv-Z0K_AY7lv9IB1jEHM,543
|
112
|
+
novel_downloader/utils/fontocr/ocr_v1.py,sha256=WreUf0E0n9oDP2C2JBDKVT2_Lsm46zKuFjYAySI64LY,11209
|
113
|
+
novel_downloader/utils/fontocr/ocr_v2.py,sha256=HpcHZYl3BCMICqeznghkUre0shHRO9KhhjrGSrtFbzE,27311
|
114
|
+
novel_downloader/utils/text_utils/__init__.py,sha256=JQtEnJ22K9o_syY5PV4Bf_p4BKZonX5g9-A5eqlxpZs,806
|
115
|
+
novel_downloader/utils/text_utils/chapter_formatting.py,sha256=9y5TodhpC-FNh5cTHNQNKDEMF9WLyA4pCxuGTLzY6KA,1279
|
116
|
+
novel_downloader/utils/text_utils/diff_display.py,sha256=aUvjMcYO-1_P8ZYiYbmYbJOByKo2bWoBV_ifRuAqwb8,2528
|
117
|
+
novel_downloader/utils/text_utils/font_mapping.py,sha256=ePpNLSrIEwIpqpnPZBMODj-gyNAPjLITyt6JQ50EfNw,867
|
118
|
+
novel_downloader/utils/text_utils/text_cleaning.py,sha256=KQhTGKiSX-eBVmjSpggxtf1hSjQLTu3cIjt65Ir4SWs,1632
|
119
|
+
novel_downloader/utils/time_utils/__init__.py,sha256=BwlvP0T9ABLdIxfcZXPmPv2yWO6F3-JiPwnBJioLouE,556
|
120
|
+
novel_downloader/utils/time_utils/datetime_utils.py,sha256=DfKobjxcrJlPdB32rqaP2ZCQ6ORohiwt6n2TRFrBraM,4815
|
121
|
+
novel_downloader/utils/time_utils/sleep_utils.py,sha256=FshjN9WW-y_pC5GJmN62J7uwXtRBzW3Wr82CEhg_UnU,1809
|
122
|
+
novel_downloader-1.3.1.dist-info/licenses/LICENSE,sha256=XgmnH0mBf-qEiizoVAfJQAKzPB9y3rBa-ni7M0Aqv4A,1066
|
123
|
+
novel_downloader-1.3.1.dist-info/METADATA,sha256=aKQcIaO_5xm9ce7TZ6MGOB01I0Xi3kB-s3OfAdZombA,6154
|
124
|
+
novel_downloader-1.3.1.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
|
125
|
+
novel_downloader-1.3.1.dist-info/entry_points.txt,sha256=v23QrJrfrAcYpxUYslCVxubOVRRTaTw7vlG_tfMsFP8,65
|
126
|
+
novel_downloader-1.3.1.dist-info/top_level.txt,sha256=hP4jYWM2LTm1jxsW4hqEB8N0dsRvldO2QdhggJT917I,17
|
127
|
+
novel_downloader-1.3.1.dist-info/RECORD,,
|
@@ -1,214 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
"""
|
4
|
-
novel_downloader.core.requesters.base_browser
|
5
|
-
---------------------------------------------
|
6
|
-
|
7
|
-
This module defines the BaseBrowser class, which provides common functionalities
|
8
|
-
for browser operations. Derived classes can extend these methods for
|
9
|
-
specialized purposes.
|
10
|
-
"""
|
11
|
-
|
12
|
-
import abc
|
13
|
-
import logging
|
14
|
-
from typing import Any, Dict, Literal, Optional, cast
|
15
|
-
|
16
|
-
from DrissionPage import Chromium, ChromiumOptions
|
17
|
-
from DrissionPage._pages.mix_tab import MixTab
|
18
|
-
|
19
|
-
from novel_downloader.config.models import RequesterConfig
|
20
|
-
from novel_downloader.core.interfaces import RequesterProtocol
|
21
|
-
from novel_downloader.utils.constants import (
|
22
|
-
DEFAULT_USER_AGENT,
|
23
|
-
DEFAULT_USER_DATA_DIR,
|
24
|
-
DEFAULT_USER_PROFILE_NAME,
|
25
|
-
)
|
26
|
-
|
27
|
-
logger = logging.getLogger(__name__)
|
28
|
-
|
29
|
-
|
30
|
-
def _is_valid(value: str) -> bool:
|
31
|
-
return bool(value and value.strip())
|
32
|
-
|
33
|
-
|
34
|
-
class BaseBrowser(RequesterProtocol, abc.ABC):
|
35
|
-
"""
|
36
|
-
BaseBrowser wraps basic browser operations using DrissionPage,
|
37
|
-
with full control over browser configuration, session profile,
|
38
|
-
retry and timeout behavior.
|
39
|
-
|
40
|
-
Attributes:
|
41
|
-
_options (ChromiumOptions): Configuration object for Chromium.
|
42
|
-
_browser (Chromium): Chromium instance.
|
43
|
-
_page (ChromiumPage): The active browser tab.
|
44
|
-
"""
|
45
|
-
|
46
|
-
def is_async(self) -> Literal[False]:
|
47
|
-
return False
|
48
|
-
|
49
|
-
def _init_browser(self, config: RequesterConfig) -> None:
|
50
|
-
"""
|
51
|
-
Initialize the browser with specified options from RequesterConfig.
|
52
|
-
|
53
|
-
:param config: Configuration settings for
|
54
|
-
browser behavior, profile, timeouts, etc.
|
55
|
-
"""
|
56
|
-
self._config = config
|
57
|
-
self._options = ChromiumOptions()
|
58
|
-
|
59
|
-
user_data_path = (
|
60
|
-
config.user_data_folder
|
61
|
-
if _is_valid(config.user_data_folder)
|
62
|
-
else DEFAULT_USER_DATA_DIR
|
63
|
-
)
|
64
|
-
if _is_valid(config.user_data_folder):
|
65
|
-
logger.warning(
|
66
|
-
"[browser] Using user_data_folder='%s'. "
|
67
|
-
"This may interfere with an active Chrome session. "
|
68
|
-
"Do NOT use this profile in both the browser and "
|
69
|
-
"this script at the same time.",
|
70
|
-
config.user_data_folder,
|
71
|
-
)
|
72
|
-
self._options.set_user_data_path(user_data_path)
|
73
|
-
|
74
|
-
profile_name = (
|
75
|
-
config.profile_name
|
76
|
-
if _is_valid(config.profile_name)
|
77
|
-
else DEFAULT_USER_PROFILE_NAME
|
78
|
-
)
|
79
|
-
self._options.set_user(profile_name)
|
80
|
-
|
81
|
-
self._options.headless(config.headless)
|
82
|
-
self._options.set_user_agent(DEFAULT_USER_AGENT)
|
83
|
-
self._options.set_timeouts(base=config.wait_time)
|
84
|
-
self._options.set_retry(
|
85
|
-
times=config.retry_times, interval=config.retry_interval
|
86
|
-
)
|
87
|
-
|
88
|
-
self._disable_images_orig = config.disable_images
|
89
|
-
if config.disable_images:
|
90
|
-
self._options.no_imgs(True)
|
91
|
-
if config.mute_audio:
|
92
|
-
self._options.mute(True)
|
93
|
-
|
94
|
-
# self._options.set_argument('--disable-blink-features', 'AutomationControlled')
|
95
|
-
# self._options.set_argument('--log-level', '3')
|
96
|
-
# self._options.set_argument('--disable-gpu')
|
97
|
-
# self._options.set_argument('no-sandbox')
|
98
|
-
|
99
|
-
self._setup()
|
100
|
-
|
101
|
-
def _setup(self) -> None:
|
102
|
-
"""
|
103
|
-
Set up the browser instance and open the default tab.
|
104
|
-
"""
|
105
|
-
self._browser = Chromium(self._options)
|
106
|
-
self._page = cast(MixTab, self._browser.get_tab())
|
107
|
-
|
108
|
-
def login(self, max_retries: int = 3, manual_login: bool = False) -> bool:
|
109
|
-
"""
|
110
|
-
Attempt to log in
|
111
|
-
"""
|
112
|
-
raise NotImplementedError(
|
113
|
-
"Login is not supported by this browser type. "
|
114
|
-
"Override login() in your subclass to enable it."
|
115
|
-
)
|
116
|
-
|
117
|
-
@abc.abstractmethod
|
118
|
-
def get_book_info(self, book_id: str, wait_time: Optional[float] = None) -> str:
|
119
|
-
"""
|
120
|
-
Fetch the raw HTML (or JSON) of the book info page.
|
121
|
-
|
122
|
-
:param book_id: The book identifier.
|
123
|
-
:param wait_time: Base number of seconds to wait before returning content.
|
124
|
-
:return: The page content as a string.
|
125
|
-
"""
|
126
|
-
...
|
127
|
-
|
128
|
-
@abc.abstractmethod
|
129
|
-
def get_book_chapter(
|
130
|
-
self, book_id: str, chapter_id: str, wait_time: Optional[float] = None
|
131
|
-
) -> str:
|
132
|
-
"""
|
133
|
-
Fetch the raw HTML (or JSON) of a single chapter.
|
134
|
-
|
135
|
-
:param book_id: The book identifier.
|
136
|
-
:param chapter_id: The chapter identifier.
|
137
|
-
:param wait_time: Base number of seconds to wait before returning content.
|
138
|
-
:return: The chapter content as a string.
|
139
|
-
"""
|
140
|
-
...
|
141
|
-
|
142
|
-
def get_bookcase(self, wait_time: Optional[float] = None) -> str:
|
143
|
-
"""
|
144
|
-
Optional: Retrieve the HTML content of the authenticated user's bookcase page.
|
145
|
-
|
146
|
-
Subclasses that support login+bookcase retrieval should override this.
|
147
|
-
|
148
|
-
:param wait_time: Base number of seconds to wait before returning content.
|
149
|
-
:return: The HTML markup of the bookcase page.
|
150
|
-
:raises NotImplementedError: If bookcase fetching is not supported.
|
151
|
-
"""
|
152
|
-
raise NotImplementedError(
|
153
|
-
"Bookcase fetching is not supported by this browser type. "
|
154
|
-
"Override get_bookcase() in your subclass to enable it."
|
155
|
-
)
|
156
|
-
|
157
|
-
@property
|
158
|
-
def page(self) -> Optional[MixTab]:
|
159
|
-
"""
|
160
|
-
Return the current Chromium page object.
|
161
|
-
|
162
|
-
:return: ChromiumPage instance of the current tab.
|
163
|
-
"""
|
164
|
-
return self._page
|
165
|
-
|
166
|
-
@property
|
167
|
-
def browser(self) -> Optional[Chromium]:
|
168
|
-
"""
|
169
|
-
Return the Chromium browser instance.
|
170
|
-
|
171
|
-
:return: Chromium instance used by this browser.
|
172
|
-
"""
|
173
|
-
return self._browser
|
174
|
-
|
175
|
-
def _clear_browser_refs(self) -> None:
|
176
|
-
"""
|
177
|
-
Clear internal browser/page references without quitting.
|
178
|
-
"""
|
179
|
-
self._browser = None
|
180
|
-
self._page = None
|
181
|
-
|
182
|
-
def shutdown(self) -> None:
|
183
|
-
"""
|
184
|
-
Shutdown the browser session and release resources.
|
185
|
-
|
186
|
-
This quits the Chromium instance and clears references to browser and page.
|
187
|
-
"""
|
188
|
-
if self._browser:
|
189
|
-
self._browser.quit()
|
190
|
-
self._clear_browser_refs()
|
191
|
-
|
192
|
-
def __getstate__(self) -> Dict[str, Any]:
|
193
|
-
"""
|
194
|
-
Prepare object state for serialization (e.g., pickling).
|
195
|
-
|
196
|
-
Removes browser-related fields that cannot be pickled.
|
197
|
-
|
198
|
-
:return: A dict representing the serializable object state.
|
199
|
-
"""
|
200
|
-
state = self.__dict__.copy()
|
201
|
-
state.pop("_browser", None)
|
202
|
-
state.pop("_page", None)
|
203
|
-
return state
|
204
|
-
|
205
|
-
def __setstate__(self, state: Dict[str, Any]) -> None:
|
206
|
-
"""
|
207
|
-
Restore object state after deserialization.
|
208
|
-
|
209
|
-
Automatically reinitializes the browser setup.
|
210
|
-
|
211
|
-
:param state: The saved state dictionary.
|
212
|
-
"""
|
213
|
-
self.__dict__.update(state)
|
214
|
-
self._setup()
|
@@ -1,246 +0,0 @@
|
|
1
|
-
#!/usr/bin/env python3
|
2
|
-
# -*- coding: utf-8 -*-
|
3
|
-
"""
|
4
|
-
novel_downloader.core.requesters.base_session
|
5
|
-
---------------------------------------------
|
6
|
-
|
7
|
-
This module defines the BaseSession class, which provides basic HTTP
|
8
|
-
request capabilities using the requests library. It maintains a
|
9
|
-
persistent session and supports retries, headers, and timeout configurations.
|
10
|
-
"""
|
11
|
-
|
12
|
-
import abc
|
13
|
-
from typing import Any, Dict, Literal, Optional, Union
|
14
|
-
|
15
|
-
import requests
|
16
|
-
from requests import Response, Session
|
17
|
-
from requests.adapters import HTTPAdapter, Retry
|
18
|
-
|
19
|
-
from novel_downloader.config.models import RequesterConfig
|
20
|
-
from novel_downloader.core.interfaces import RequesterProtocol
|
21
|
-
from novel_downloader.utils.constants import DEFAULT_USER_HEADERS
|
22
|
-
|
23
|
-
|
24
|
-
class BaseSession(RequesterProtocol, abc.ABC):
|
25
|
-
"""
|
26
|
-
BaseSession wraps basic HTTP operations using requests.Session,
|
27
|
-
supporting retry logic, timeout, and persistent connections.
|
28
|
-
|
29
|
-
Attributes:
|
30
|
-
_session (requests.Session): The persistent HTTP session.
|
31
|
-
_timeout (float): Timeout for each request in seconds.
|
32
|
-
"""
|
33
|
-
|
34
|
-
def is_async(self) -> Literal[False]:
|
35
|
-
return False
|
36
|
-
|
37
|
-
def _init_session(
|
38
|
-
self, config: RequesterConfig, cookies: Optional[Dict[str, str]] = None
|
39
|
-
) -> None:
|
40
|
-
"""
|
41
|
-
Initialize the requests.Session with default headers and retry strategy.
|
42
|
-
|
43
|
-
:param config: Configuration object for session behavior
|
44
|
-
(timeouts, retries, headers, etc.)
|
45
|
-
"""
|
46
|
-
self._config = config
|
47
|
-
self._timeout = config.timeout
|
48
|
-
self._retry_times = config.retry_times
|
49
|
-
self._retry_interval = config.retry_interval
|
50
|
-
self._cookies = cookies or {}
|
51
|
-
self._headers = DEFAULT_USER_HEADERS
|
52
|
-
self._session: Optional[Session] = None
|
53
|
-
|
54
|
-
self._setup()
|
55
|
-
|
56
|
-
def _setup(self) -> None:
|
57
|
-
"""
|
58
|
-
Set up the session with retry strategy and apply default headers.
|
59
|
-
"""
|
60
|
-
self._session = requests.Session()
|
61
|
-
|
62
|
-
retry_strategy = Retry(
|
63
|
-
total=self._config.retry_times,
|
64
|
-
backoff_factor=self._config.retry_interval,
|
65
|
-
status_forcelist=[429, 500, 502, 503, 504],
|
66
|
-
allowed_methods=["HEAD", "GET", "OPTIONS"],
|
67
|
-
)
|
68
|
-
|
69
|
-
adapter = HTTPAdapter(max_retries=retry_strategy)
|
70
|
-
self._session.mount("http://", adapter)
|
71
|
-
self._session.mount("https://", adapter)
|
72
|
-
self._session.headers.update(self._headers)
|
73
|
-
|
74
|
-
if self._cookies:
|
75
|
-
self._session.cookies.update(self._cookies)
|
76
|
-
|
77
|
-
def login(self, max_retries: int = 3, manual_login: bool = False) -> bool:
|
78
|
-
"""
|
79
|
-
Attempt to log in
|
80
|
-
"""
|
81
|
-
raise NotImplementedError(
|
82
|
-
"Login is not supported by this session type. "
|
83
|
-
"Override login() in your subclass to enable it."
|
84
|
-
)
|
85
|
-
|
86
|
-
@abc.abstractmethod
|
87
|
-
def get_book_info(self, book_id: str, wait_time: Optional[float] = None) -> str:
|
88
|
-
"""
|
89
|
-
Fetch the raw HTML (or JSON) of the book info page.
|
90
|
-
|
91
|
-
:param book_id: The book identifier.
|
92
|
-
:param wait_time: Base number of seconds to wait before returning content.
|
93
|
-
:return: The page content as a string.
|
94
|
-
"""
|
95
|
-
...
|
96
|
-
|
97
|
-
@abc.abstractmethod
|
98
|
-
def get_book_chapter(
|
99
|
-
self, book_id: str, chapter_id: str, wait_time: Optional[float] = None
|
100
|
-
) -> str:
|
101
|
-
"""
|
102
|
-
Fetch the raw HTML (or JSON) of a single chapter.
|
103
|
-
|
104
|
-
:param book_id: The book identifier.
|
105
|
-
:param chapter_id: The chapter identifier.
|
106
|
-
:param wait_time: Base number of seconds to wait before returning content.
|
107
|
-
:return: The chapter content as a string.
|
108
|
-
"""
|
109
|
-
...
|
110
|
-
|
111
|
-
def get_bookcase(self, wait_time: Optional[float] = None) -> str:
|
112
|
-
"""
|
113
|
-
Optional: Retrieve the HTML content of the authenticated user's bookcase page.
|
114
|
-
|
115
|
-
Subclasses that support user login and bookcase retrieval should override this.
|
116
|
-
|
117
|
-
:param wait_time: Base number of seconds to wait before returning content.
|
118
|
-
:return: The HTML markup of the bookcase page.
|
119
|
-
:raises NotImplementedError: If the subclass does not implement.
|
120
|
-
"""
|
121
|
-
raise NotImplementedError(
|
122
|
-
"Bookcase fetching is not supported by this session type. "
|
123
|
-
"Override get_bookcase() in your subclass to enable it."
|
124
|
-
)
|
125
|
-
|
126
|
-
def get(
|
127
|
-
self, url: str, params: Optional[Dict[str, Any]] = None, **kwargs: Any
|
128
|
-
) -> Response:
|
129
|
-
"""
|
130
|
-
Send a GET request.
|
131
|
-
|
132
|
-
:param url: The target URL.
|
133
|
-
:param params: Query parameters to include in the request.
|
134
|
-
:param kwargs: Additional arguments passed to requests.
|
135
|
-
:return: Response object from the GET request.
|
136
|
-
:raises RuntimeError: If the session is not initialized.
|
137
|
-
"""
|
138
|
-
if not self._session:
|
139
|
-
raise RuntimeError("Session is not initialized or has been shut down.")
|
140
|
-
return self._session.get(url, params=params, timeout=self._timeout, **kwargs)
|
141
|
-
|
142
|
-
def post(
|
143
|
-
self,
|
144
|
-
url: str,
|
145
|
-
data: Optional[Union[Dict[str, Any], bytes]] = None,
|
146
|
-
json: Optional[Dict[str, Any]] = None,
|
147
|
-
**kwargs: Any,
|
148
|
-
) -> Response:
|
149
|
-
"""
|
150
|
-
Send a POST request.
|
151
|
-
|
152
|
-
:param url: The target URL.
|
153
|
-
:param data: Form data to include in the request body.
|
154
|
-
:param json: JSON body to include in the request.
|
155
|
-
:param kwargs: Additional arguments passed to requests.
|
156
|
-
:return: Response object from the POST request.
|
157
|
-
:raises RuntimeError: If the session is not initialized.
|
158
|
-
"""
|
159
|
-
if not self._session:
|
160
|
-
raise RuntimeError("Session is not initialized or has been shut down.")
|
161
|
-
return self._session.post(
|
162
|
-
url, data=data, json=json, timeout=self._timeout, **kwargs
|
163
|
-
)
|
164
|
-
|
165
|
-
@property
|
166
|
-
def session(self) -> Session:
|
167
|
-
"""
|
168
|
-
Return the active requests.Session.
|
169
|
-
|
170
|
-
:raises RuntimeError: If the session is uninitialized or has been shut down.
|
171
|
-
"""
|
172
|
-
if self._session is None:
|
173
|
-
raise RuntimeError("Session is not initialized or has been shut down.")
|
174
|
-
return self._session
|
175
|
-
|
176
|
-
@property
|
177
|
-
def timeout(self) -> float:
|
178
|
-
"""Return the default timeout setting."""
|
179
|
-
return self._timeout
|
180
|
-
|
181
|
-
@property
|
182
|
-
def retry_times(self) -> int:
|
183
|
-
"""Return the maximum number of retry attempts."""
|
184
|
-
return self._retry_times
|
185
|
-
|
186
|
-
@property
|
187
|
-
def retry_interval(self) -> float:
|
188
|
-
"""Return the base interval (in seconds) between retries."""
|
189
|
-
return self._retry_interval
|
190
|
-
|
191
|
-
@property
|
192
|
-
def headers(self) -> Dict[str, str]:
|
193
|
-
"""Return the default headers."""
|
194
|
-
if not self._session:
|
195
|
-
return {}
|
196
|
-
return {k: v for k, v in self._session.headers.items() if isinstance(v, str)}
|
197
|
-
|
198
|
-
def update_cookies(self, cookies: Dict[str, str], overwrite: bool = True) -> None:
|
199
|
-
"""
|
200
|
-
Update cookies for the current session (if initialized) as well as for the
|
201
|
-
internal cache kept in ``self._cookies`` so that subsequent ``_setup`` calls
|
202
|
-
also see the latest values.
|
203
|
-
"""
|
204
|
-
if not cookies:
|
205
|
-
return
|
206
|
-
|
207
|
-
if overwrite:
|
208
|
-
for k, v in cookies.items():
|
209
|
-
self._cookies[str(k)] = str(v)
|
210
|
-
else:
|
211
|
-
for k, v in cookies.items():
|
212
|
-
self._cookies.setdefault(str(k), str(v))
|
213
|
-
|
214
|
-
if self._session is not None:
|
215
|
-
self._session.cookies.update(self._cookies)
|
216
|
-
|
217
|
-
def shutdown(self) -> None:
|
218
|
-
"""
|
219
|
-
Shutdown and clean up the session.
|
220
|
-
|
221
|
-
This closes the underlying connection pool and removes the session.
|
222
|
-
"""
|
223
|
-
if self._session:
|
224
|
-
self._session.close()
|
225
|
-
self._session = None
|
226
|
-
|
227
|
-
def __getstate__(self) -> Dict[str, Any]:
|
228
|
-
"""
|
229
|
-
Prepare object state for serialization.
|
230
|
-
|
231
|
-
Removes unpickleable session object.
|
232
|
-
|
233
|
-
:return: Serializable dict of the object state.
|
234
|
-
"""
|
235
|
-
state = self.__dict__.copy()
|
236
|
-
state.pop("_session", None)
|
237
|
-
return state
|
238
|
-
|
239
|
-
def __setstate__(self, state: Dict[str, Any]) -> None:
|
240
|
-
"""
|
241
|
-
Restore object state and reinitialize session.
|
242
|
-
|
243
|
-
:param state: Saved state dictionary.
|
244
|
-
"""
|
245
|
-
self.__dict__.update(state)
|
246
|
-
self._setup()
|