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 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.4'
32
- __version_tuple__ = version_tuple = (1, 2, 4)
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
- # 注 1 : 訂閱連載中的漫畫,有更新時自動推送的卷(冊),暫不計算在使用額度中,不扣減使用額度。
274
- # 注 2 : 對同一卷()書在 12 小時內重複*下載*,不會重複扣減額度。但重復推送是會扣減的。
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]]], retry_times: int = 3) -> str:
396
- while retry_times >= 0:
397
- try:
398
- if callable(url):
399
- result = url()
400
- if asyncio.iscoroutine(result) or isinstance(result, Awaitable):
401
- return await result
402
- return result
403
- elif isinstance(url, str):
404
- return url
405
- except Exception as e:
406
- retry_times -= 1
407
- if retry_times < 0:
408
- raise e
409
- await asyncio.sleep(2)
410
- raise RuntimeError("Max retries exceeded")
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
@@ -55,7 +55,6 @@ class StateManager:
55
55
  if not self._part_states:
56
56
  return
57
57
 
58
- debug("当前状态:", self._part_states)
59
58
  highest_status = max(self._part_states.values())
60
59
  if highest_status != self._current_status:
61
60
  self._current_status = highest_status
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kmoe-manga-downloader
3
- Version: 1.2.4
3
+ Version: 1.2.5
4
4
  Summary: A CLI-downloader for site @kox.moe.
5
5
  Author-email: Chris Zheng <chrisis58@outlook.com>
6
6
  License: MIT License
@@ -1,12 +1,12 @@
1
1
  kmdr/__init__.py,sha256=iLmy2rOkHS_4KZWMD8BgT7R3tLMKeaTCDVf3B4FyYxM,91
2
- kmdr/_version.py,sha256=GrtCd1GIHwyAD6wvryducmyvxntp1-UKa54jH5_s79g,704
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=buvWXGKNBF_Zbx4oUdLi3VDQkanxRN5UinX2J6JhWZE,8952
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=SPnzKDpVPg3utyrPrFr4pYiMI5w3eRCMemcYevH9VzY,1320
29
- kmdr/module/downloader/ReferViaDownloader.py,sha256=o565u6W4G_4UFoqsLkXGRFIlRSMueZB_ZMdiAfhUVCc,1970
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=4FS8cTRDVagT5nFLJOOWa462VtGOz404S2Qpb9NXoUE,15770
32
- kmdr/module/downloader/misc.py,sha256=YEzpBcKteyDyEq_NhYhfh8ssB2R-NQoz99sul-B57BM,2378
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.4.dist-info/licenses/LICENSE,sha256=bKQlsXu8mAYKRZyoZKOEqMcCc8YjT5Q3Hgr21e0yU4E,1068
42
- kmoe_manga_downloader-1.2.4.dist-info/METADATA,sha256=8txEbawVJEN1liNijuJbvacaBlTwp4VVwaVnPpp0plo,10114
43
- kmoe_manga_downloader-1.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
44
- kmoe_manga_downloader-1.2.4.dist-info/entry_points.txt,sha256=DGMytQAhx4uNuKQL7BPkiWESHLXkH-2KSEqwHdygNPA,47
45
- kmoe_manga_downloader-1.2.4.dist-info/top_level.txt,sha256=e0qxOgWp0tl3GLpmXGjZv3--q_TLoJ7GztM48Ov27wM,5
46
- kmoe_manga_downloader-1.2.4.dist-info/RECORD,,
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,,