kmoe-manga-downloader 1.2.4__py3-none-any.whl → 1.2.5__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.
- kmdr/_version.py +2 -2
- kmdr/core/defaults.py +1 -0
- kmdr/module/downloader/DirectDownloader.py +3 -2
- kmdr/module/downloader/ReferViaDownloader.py +5 -3
- kmdr/module/downloader/download_utils.py +28 -20
- kmdr/module/downloader/misc.py +0 -1
- {kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/METADATA +1 -1
- {kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/RECORD +12 -12
- {kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/WHEEL +0 -0
- {kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/entry_points.txt +0 -0
- {kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/licenses/LICENSE +0 -0
- {kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/top_level.txt +0 -0
kmdr/_version.py
CHANGED
|
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
|
28
28
|
commit_id: COMMIT_ID
|
|
29
29
|
__commit_id__: COMMIT_ID
|
|
30
30
|
|
|
31
|
-
__version__ = version = '1.2.
|
|
32
|
-
__version_tuple__ = version_tuple = (1, 2,
|
|
31
|
+
__version__ = version = '1.2.5'
|
|
32
|
+
__version_tuple__ = version_tuple = (1, 2, 5)
|
|
33
33
|
|
|
34
34
|
__commit_id__ = commit_id = None
|
kmdr/core/defaults.py
CHANGED
|
@@ -70,6 +70,7 @@ def argument_parser():
|
|
|
70
70
|
download_parser.add_argument('-r', '--retry', type=int, help='网络请求失败时的重试次数', required=False)
|
|
71
71
|
download_parser.add_argument('-c', '--callback', type=str, help='每个卷下载完成后执行的回调脚本,例如: `echo {v.name} downloaded!`', required=False)
|
|
72
72
|
download_parser.add_argument('-m', '--method', type=int, help='下载方法,对应网站上的不同下载方式', required=False, choices=[1, 2], default=1)
|
|
73
|
+
download_parser.add_argument('--vip', action='store_true', help='尝试使用 VIP 链接进行下载(下载速度可能不及 CDN 方式)')
|
|
73
74
|
|
|
74
75
|
login_parser = subparsers.add_parser('login', help='登录到 Kmoe')
|
|
75
76
|
login_parser.add_argument('-u', '--username', type=str, help='用户名', required=True)
|
|
@@ -11,8 +11,9 @@ from .download_utils import download_file_multipart, readable_safe_filename
|
|
|
11
11
|
}
|
|
12
12
|
)
|
|
13
13
|
class DirectDownloader(Downloader):
|
|
14
|
-
def __init__(self, dest='.', callback=None, retry=3, num_workers=8, proxy=None, *args, **kwargs):
|
|
14
|
+
def __init__(self, dest='.', callback=None, retry=3, num_workers=8, proxy=None, vip=False, *args, **kwargs):
|
|
15
15
|
super().__init__(dest, callback, retry, num_workers, proxy, *args, **kwargs)
|
|
16
|
+
self._use_vip = vip
|
|
16
17
|
|
|
17
18
|
async def _download(self, book: BookInfo, volume: VolInfo):
|
|
18
19
|
sub_dir = readable_safe_filename(book.name)
|
|
@@ -33,5 +34,5 @@ class DirectDownloader(Downloader):
|
|
|
33
34
|
return API_ROUTE.DOWNLOAD.format(
|
|
34
35
|
book_id=book.id,
|
|
35
36
|
volume_id=volume.id,
|
|
36
|
-
is_vip=self._profile.is_vip
|
|
37
|
+
is_vip=self._profile.is_vip if not self._use_vip else 0
|
|
37
38
|
)
|
|
@@ -6,6 +6,7 @@ from async_lru import alru_cache
|
|
|
6
6
|
from kmdr.core import Downloader, VolInfo, DOWNLOADER, BookInfo
|
|
7
7
|
from kmdr.core.constants import API_ROUTE
|
|
8
8
|
from kmdr.core.error import ResponseError
|
|
9
|
+
from kmdr.core.utils import async_retry
|
|
9
10
|
from kmdr.core.console import debug
|
|
10
11
|
|
|
11
12
|
from .download_utils import download_file_multipart, readable_safe_filename
|
|
@@ -13,9 +14,9 @@ from .download_utils import download_file_multipart, readable_safe_filename
|
|
|
13
14
|
|
|
14
15
|
@DOWNLOADER.register(order=10)
|
|
15
16
|
class ReferViaDownloader(Downloader):
|
|
16
|
-
def __init__(self, dest='.', callback=None, retry=3, num_workers=8, proxy=None, *args, **kwargs):
|
|
17
|
+
def __init__(self, dest='.', callback=None, retry=3, num_workers=8, proxy=None, vip=False, *args, **kwargs):
|
|
17
18
|
super().__init__(dest, callback, retry, num_workers, proxy, *args, **kwargs)
|
|
18
|
-
|
|
19
|
+
self._use_vip = vip
|
|
19
20
|
|
|
20
21
|
async def _download(self, book: BookInfo, volume: VolInfo):
|
|
21
22
|
sub_dir = readable_safe_filename(book.name)
|
|
@@ -36,13 +37,14 @@ class ReferViaDownloader(Downloader):
|
|
|
36
37
|
)
|
|
37
38
|
|
|
38
39
|
@alru_cache(maxsize=128)
|
|
40
|
+
@async_retry()
|
|
39
41
|
async def fetch_download_url(self, book_id: str, volume_id: str) -> str:
|
|
40
42
|
|
|
41
43
|
async with self._session.get(
|
|
42
44
|
API_ROUTE.GETDOWNURL.format(
|
|
43
45
|
book_id=book_id,
|
|
44
46
|
volume_id=volume_id,
|
|
45
|
-
is_vip=self._profile.is_vip
|
|
47
|
+
is_vip=self._profile.is_vip if not self._use_vip else 0
|
|
46
48
|
)
|
|
47
49
|
) as response:
|
|
48
50
|
response.raise_for_status()
|
|
@@ -267,11 +267,16 @@ async def _fetch_content_length(
|
|
|
267
267
|
"""
|
|
268
268
|
if headers is None:
|
|
269
269
|
headers = {}
|
|
270
|
-
|
|
270
|
+
|
|
271
271
|
async with session.head(url, headers=headers, allow_redirects=True) as response:
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
272
|
+
response.raise_for_status()
|
|
273
|
+
if 'Content-Length' in response.headers:
|
|
274
|
+
return int(response.headers['Content-Length'])
|
|
275
|
+
|
|
276
|
+
async with session.get(url, headers=headers, allow_redirects=True) as response:
|
|
277
|
+
# 普通下载链接可能不支持 HEAD 请求,尝试使用 GET 请求获取文件大小
|
|
278
|
+
# see: https://github.com/chrisis58/kmoe-manga-downloader/issues/25
|
|
279
|
+
debug("HEAD 请求未返回 Content-Length,尝试使用 GET 请求获取文件大小")
|
|
275
280
|
response.raise_for_status()
|
|
276
281
|
if 'Content-Length' not in response.headers:
|
|
277
282
|
raise ResponseError("无法从服务器获取文件大小,请检查网络连接或稍后重试。", status_code=response.status)
|
|
@@ -392,19 +397,22 @@ def safe_filename(name: str) -> str:
|
|
|
392
397
|
"""
|
|
393
398
|
return re.sub(r'[\\/:*?"<>|]', '_', name)
|
|
394
399
|
|
|
395
|
-
async def fetch_url(url: Union[str, Callable[[], str], Callable[[], Awaitable[str]]]
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
400
|
+
async def fetch_url(url: Union[str, Callable[[], str], Callable[[], Awaitable[str]]]) -> str:
|
|
401
|
+
"""
|
|
402
|
+
获取下载链接的包装函数,支持直接传入字符串或异步/同步的 Supplier 函数。
|
|
403
|
+
|
|
404
|
+
:note: 不包含重试机制,调用方需自行处理。
|
|
405
|
+
:param url: 下载链接或其 Supplier
|
|
406
|
+
:return: 下载链接
|
|
407
|
+
"""
|
|
408
|
+
|
|
409
|
+
if callable(url):
|
|
410
|
+
result = url()
|
|
411
|
+
if asyncio.iscoroutine(result) or isinstance(result, Awaitable):
|
|
412
|
+
# 如果 url() 是一个异步函数,等待它
|
|
413
|
+
return await result
|
|
414
|
+
# 如果 url() 是一个同步函数,直接返回
|
|
415
|
+
return result
|
|
416
|
+
elif isinstance(url, str):
|
|
417
|
+
# 如果 url 只是个字符串,直接返回
|
|
418
|
+
return url
|
kmdr/module/downloader/misc.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
kmdr/__init__.py,sha256=iLmy2rOkHS_4KZWMD8BgT7R3tLMKeaTCDVf3B4FyYxM,91
|
|
2
|
-
kmdr/_version.py,sha256=
|
|
2
|
+
kmdr/_version.py,sha256=C5VYXj2vxw4EsF0YnMCGGmDah6DWTG6kq2PyZN-lNSw,704
|
|
3
3
|
kmdr/main.py,sha256=B9CK53GlWO91-135AJDFOfqglSmYJe5-nZrha4A0LLs,2166
|
|
4
4
|
kmdr/core/__init__.py,sha256=aR3mhP1A81oTmTnBOonVQm_mFvFeNCOo7kalZVfszAc,416
|
|
5
5
|
kmdr/core/bases.py,sha256=47M6VyrIMnmTEvwZtt8WsPAjGz5vagkRyTpci16aH2k,3973
|
|
6
6
|
kmdr/core/console.py,sha256=gD_PKjuAjePUJx-49ef9IBunetCiKt1LMI0EIU5kcZw,2016
|
|
7
7
|
kmdr/core/constants.py,sha256=JFj8FHO9ab6AeIzHz3LaC8l3ziLLFi75vil8wMPfZoA,1869
|
|
8
8
|
kmdr/core/context.py,sha256=ZhUfuCmZN0s1AQnxxkMFqYkCpjkRvJd53RUZWMhH8Gw,1390
|
|
9
|
-
kmdr/core/defaults.py,sha256=
|
|
9
|
+
kmdr/core/defaults.py,sha256=o9Py-Y51xNMFxyZ_okpvUjh4Z92QX7y8RaWKJ98Q-JY,9100
|
|
10
10
|
kmdr/core/error.py,sha256=gH4tcFpLRJXKQCwEnvfVM0lkhlakCwS-IYtNEkpO9a4,1984
|
|
11
11
|
kmdr/core/protocol.py,sha256=_4Ba6BU4oEFK2O61UH_-X2-bmZtUd61O20WGarvXVOM,399
|
|
12
12
|
kmdr/core/registry.py,sha256=m5jKma2SLbYN6hG2WqkxoyOYUENE4a-e0CzRALkGD7k,5654
|
|
@@ -25,11 +25,11 @@ kmdr/module/configurer/OptionLister.py,sha256=bGlrxouPiBGpGv8UiGPcT3KL6SWMJckQKd
|
|
|
25
25
|
kmdr/module/configurer/OptionSetter.py,sha256=BQXIgyLoMDSNua2x96FtX-9JmJhVpPJ5o0tWHj_-7B0,898
|
|
26
26
|
kmdr/module/configurer/__init__.py,sha256=nSWGwUCcwOkvg28zxRd0S3b4jeag_W0IhzP74xq0ewE,204
|
|
27
27
|
kmdr/module/configurer/option_validate.py,sha256=9QzVO9wwGwhXMPXx2zLJSIsyVle7-GTgxCoPn7Tp6kw,3535
|
|
28
|
-
kmdr/module/downloader/DirectDownloader.py,sha256=
|
|
29
|
-
kmdr/module/downloader/ReferViaDownloader.py,sha256=
|
|
28
|
+
kmdr/module/downloader/DirectDownloader.py,sha256=Wc_a3tfeHqc5HidPqxcsNN97cJJbajx0QHxE5PPmtP8,1387
|
|
29
|
+
kmdr/module/downloader/ReferViaDownloader.py,sha256=W92pPcB98lUM4wGt90eE93CaNtL5ffzhwNo4iUJChZk,2095
|
|
30
30
|
kmdr/module/downloader/__init__.py,sha256=PajPBQ4ZJwz_6Ok6k-HV7-YSibxAW5m5voYyP-U-_f4,97
|
|
31
|
-
kmdr/module/downloader/download_utils.py,sha256=
|
|
32
|
-
kmdr/module/downloader/misc.py,sha256=
|
|
31
|
+
kmdr/module/downloader/download_utils.py,sha256=IvwmLosyuqTOjSpLOfvST6c4uhtdCQU2tfP1x8rtayY,15956
|
|
32
|
+
kmdr/module/downloader/misc.py,sha256=P8hqtYIiD1AR6wzfJ0JBghpSJ_zx2_vTg8jDHcEU8hM,2328
|
|
33
33
|
kmdr/module/lister/BookUrlLister.py,sha256=R1sak_GQG8HKfdSzHF-Dy1iby6TgFlxKJLf2dwBr0Bw,550
|
|
34
34
|
kmdr/module/lister/FollowedBookLister.py,sha256=d2IxWAf1VSL1Kv8SQkzbxDUunFb7UkxkreUbWQvs6tc,2906
|
|
35
35
|
kmdr/module/lister/__init__.py,sha256=VVRMRGXASdIagzlmOuhy9gKjJzf8Rj3000BPzeWpHHE,91
|
|
@@ -38,9 +38,9 @@ kmdr/module/picker/ArgsFilterPicker.py,sha256=wBCDa6KsSSOLLQk8D4ftZ9ZnwPLiHIirxf
|
|
|
38
38
|
kmdr/module/picker/DefaultVolPicker.py,sha256=qScmRtwpe1u3fY7HMIo15YXtwB4LYAIJaTu_EkrAJbs,1780
|
|
39
39
|
kmdr/module/picker/__init__.py,sha256=qYELEkv0nFT8DadItB6fdUTED2CHrC43wuPKO7QrCCQ,93
|
|
40
40
|
kmdr/module/picker/utils.py,sha256=baJzpQSSSBdTPZ2scrEeNOssGYOL0nNwxN1gTsOAqnc,1604
|
|
41
|
-
kmoe_manga_downloader-1.2.
|
|
42
|
-
kmoe_manga_downloader-1.2.
|
|
43
|
-
kmoe_manga_downloader-1.2.
|
|
44
|
-
kmoe_manga_downloader-1.2.
|
|
45
|
-
kmoe_manga_downloader-1.2.
|
|
46
|
-
kmoe_manga_downloader-1.2.
|
|
41
|
+
kmoe_manga_downloader-1.2.5.dist-info/licenses/LICENSE,sha256=bKQlsXu8mAYKRZyoZKOEqMcCc8YjT5Q3Hgr21e0yU4E,1068
|
|
42
|
+
kmoe_manga_downloader-1.2.5.dist-info/METADATA,sha256=4mGjK0VYcz7kdsdrMidT-7nFQ3fFm_Jtp0z7-rodLrM,10114
|
|
43
|
+
kmoe_manga_downloader-1.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
44
|
+
kmoe_manga_downloader-1.2.5.dist-info/entry_points.txt,sha256=DGMytQAhx4uNuKQL7BPkiWESHLXkH-2KSEqwHdygNPA,47
|
|
45
|
+
kmoe_manga_downloader-1.2.5.dist-info/top_level.txt,sha256=e0qxOgWp0tl3GLpmXGjZv3--q_TLoJ7GztM48Ov27wM,5
|
|
46
|
+
kmoe_manga_downloader-1.2.5.dist-info/RECORD,,
|
|
File without changes
|
{kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{kmoe_manga_downloader-1.2.4.dist-info → kmoe_manga_downloader-1.2.5.dist-info}/top_level.txt
RENAMED
|
File without changes
|