jmcomic 2.3.14__py3-none-any.whl → 2.3.15__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.
- jmcomic/__init__.py +1 -1
- jmcomic/jm_client_impl.py +11 -1
- jmcomic/jm_config.py +7 -3
- jmcomic/jm_downloader.py +0 -4
- jmcomic/jm_option.py +66 -21
- jmcomic/jm_plugin.py +48 -9
- {jmcomic-2.3.14.dist-info → jmcomic-2.3.15.dist-info}/METADATA +4 -4
- jmcomic-2.3.15.dist-info/RECORD +17 -0
- {jmcomic-2.3.14.dist-info → jmcomic-2.3.15.dist-info}/WHEEL +1 -1
- jmcomic-2.3.14.dist-info/RECORD +0 -17
- {jmcomic-2.3.14.dist-info → jmcomic-2.3.15.dist-info}/LICENSE +0 -0
- {jmcomic-2.3.14.dist-info → jmcomic-2.3.15.dist-info}/entry_points.txt +0 -0
- {jmcomic-2.3.14.dist-info → jmcomic-2.3.15.dist-info}/top_level.txt +0 -0
jmcomic/__init__.py
CHANGED
jmcomic/jm_client_impl.py
CHANGED
|
@@ -584,7 +584,7 @@ class JmApiClient(AbstractJmClient):
|
|
|
584
584
|
def get_decode(self, url, **kwargs) -> JmApiResp:
|
|
585
585
|
# set headers
|
|
586
586
|
headers, key_ts = self.headers_key_ts
|
|
587
|
-
kwargs
|
|
587
|
+
kwargs['headers'] = headers
|
|
588
588
|
|
|
589
589
|
resp = self.get(url, **kwargs)
|
|
590
590
|
return JmApiResp.wrap(resp, key_ts)
|
|
@@ -610,6 +610,16 @@ class JmApiClient(AbstractJmClient):
|
|
|
610
610
|
# 2. 是否是特殊的内容
|
|
611
611
|
# 暂无
|
|
612
612
|
|
|
613
|
+
@classmethod
|
|
614
|
+
@field_cache('__init_cookies__')
|
|
615
|
+
def fetch_init_cookies(cls, client: 'JmApiClient'):
|
|
616
|
+
resp = client.setting()
|
|
617
|
+
return dict(resp.resp.cookies)
|
|
618
|
+
|
|
619
|
+
def after_init(self):
|
|
620
|
+
cookies = self.__class__.fetch_init_cookies(self)
|
|
621
|
+
self.get_root_postman().get_meta_data()['cookies'] = cookies
|
|
622
|
+
|
|
613
623
|
|
|
614
624
|
class FutureClientProxy(JmcomicClient):
|
|
615
625
|
"""
|
jmcomic/jm_config.py
CHANGED
|
@@ -64,7 +64,7 @@ class JmModuleConfig:
|
|
|
64
64
|
|
|
65
65
|
# 移动端API的相关配置
|
|
66
66
|
# API密钥
|
|
67
|
-
|
|
67
|
+
APP_SECRET = '18comicAPP'
|
|
68
68
|
|
|
69
69
|
# 域名配置 - 移动端
|
|
70
70
|
# 图片域名
|
|
@@ -247,7 +247,7 @@ class JmModuleConfig:
|
|
|
247
247
|
key_ts = time_stamp()
|
|
248
248
|
|
|
249
249
|
import hashlib
|
|
250
|
-
token = hashlib.md5(f"{key_ts}{cls.
|
|
250
|
+
token = hashlib.md5(f"{key_ts}{cls.APP_SECRET}".encode()).hexdigest()
|
|
251
251
|
|
|
252
252
|
return {
|
|
253
253
|
'token': token,
|
|
@@ -331,7 +331,11 @@ class JmModuleConfig:
|
|
|
331
331
|
'impl': None,
|
|
332
332
|
'retry_times': 5
|
|
333
333
|
},
|
|
334
|
-
'plugins': {
|
|
334
|
+
'plugins': {
|
|
335
|
+
# 如果插件抛出参数校验异常,只debug。(全局配置,可以被插件的局部配置覆盖)
|
|
336
|
+
# 可选值:ignore(忽略),debug(打印日志),raise(抛异常)。
|
|
337
|
+
'valid': 'debug',
|
|
338
|
+
},
|
|
335
339
|
}
|
|
336
340
|
|
|
337
341
|
@classmethod
|
jmcomic/jm_downloader.py
CHANGED
jmcomic/jm_option.py
CHANGED
|
@@ -311,12 +311,12 @@ class JmOption:
|
|
|
311
311
|
"""
|
|
312
312
|
return self.new_jm_client(**kwargs)
|
|
313
313
|
|
|
314
|
-
def new_jm_client(self, domain=None, impl=None, **kwargs) -> JmcomicClient:
|
|
314
|
+
def new_jm_client(self, domain=None, impl=None, cache=None, **kwargs) -> JmcomicClient:
|
|
315
315
|
# 所有需要用到的 self.client 配置项如下
|
|
316
316
|
postman_conf: dict = self.client.postman.src_dict # postman dsl 配置
|
|
317
317
|
impl: str = impl or self.client.impl # client_key
|
|
318
318
|
retry_times: int = self.client.retry_times # 重试次数
|
|
319
|
-
cache: str = self.client.cache # 启用缓存
|
|
319
|
+
cache: str = cache or self.client.cache # 启用缓存
|
|
320
320
|
|
|
321
321
|
# domain
|
|
322
322
|
def decide_domain():
|
|
@@ -340,7 +340,10 @@ class JmOption:
|
|
|
340
340
|
# headers
|
|
341
341
|
meta_data = postman_conf['meta_data']
|
|
342
342
|
if meta_data['headers'] is None:
|
|
343
|
-
|
|
343
|
+
headers = self.decide_postman_headers(impl, domain[0])
|
|
344
|
+
# if headers is None:
|
|
345
|
+
# postman_conf['type'] = 'requests'
|
|
346
|
+
meta_data['headers'] = headers
|
|
344
347
|
|
|
345
348
|
# postman
|
|
346
349
|
postman = Postmans.create(data=postman_conf)
|
|
@@ -349,7 +352,8 @@ class JmOption:
|
|
|
349
352
|
clazz = JmModuleConfig.client_impl_class(impl)
|
|
350
353
|
if clazz == AbstractJmClient or not issubclass(clazz, AbstractJmClient):
|
|
351
354
|
raise NotImplementedError(clazz)
|
|
352
|
-
|
|
355
|
+
|
|
356
|
+
client: AbstractJmClient = clazz(
|
|
353
357
|
postman,
|
|
354
358
|
retry_times,
|
|
355
359
|
fallback_domain_list=decide_domain(),
|
|
@@ -442,36 +446,77 @@ class JmOption:
|
|
|
442
446
|
|
|
443
447
|
ExceptionTool.require_true(plugin_class is not None, f'[{group}] 未注册的plugin: {key}')
|
|
444
448
|
|
|
445
|
-
self.invoke_plugin(plugin_class, kwargs, extra)
|
|
449
|
+
self.invoke_plugin(plugin_class, kwargs, extra, pinfo)
|
|
450
|
+
|
|
451
|
+
def invoke_plugin(self, plugin_class, kwargs: Any, extra: dict, pinfo: dict):
|
|
452
|
+
# 检查插件的参数类型
|
|
453
|
+
kwargs = self.fix_kwargs(kwargs)
|
|
454
|
+
# 把插件的配置数据kwargs和附加数据extra合并,extra会覆盖kwargs
|
|
455
|
+
if len(extra) != 0:
|
|
456
|
+
kwargs.update(extra)
|
|
446
457
|
|
|
447
|
-
def invoke_plugin(self, plugin_class, kwargs: Any, extra: dict):
|
|
448
458
|
# 保证 jm_plugin.py 被加载
|
|
449
|
-
from .jm_plugin import JmOptionPlugin
|
|
459
|
+
from .jm_plugin import JmOptionPlugin, PluginValidationException
|
|
450
460
|
|
|
461
|
+
plugin = plugin_class
|
|
451
462
|
plugin_class: Type[JmOptionPlugin]
|
|
452
|
-
pkey = plugin_class.plugin_key
|
|
453
463
|
|
|
454
464
|
try:
|
|
455
|
-
# 检查插件的参数类型
|
|
456
|
-
kwargs = self.fix_kwargs(kwargs)
|
|
457
|
-
# 把插件的配置数据kwargs和附加数据extra合并
|
|
458
|
-
# extra会覆盖kwargs
|
|
459
|
-
if len(extra) != 0:
|
|
460
|
-
kwargs.update(extra)
|
|
461
465
|
# 构建插件对象
|
|
462
|
-
plugin = plugin_class.build(self)
|
|
466
|
+
plugin: JmOptionPlugin = plugin_class.build(self)
|
|
467
|
+
|
|
468
|
+
jm_debug('plugin.invoke', f'调用插件: [{plugin_class.plugin_key}]')
|
|
463
469
|
# 调用插件功能
|
|
464
|
-
jm_debug('plugin.invoke', f'调用插件: [{pkey}]')
|
|
465
470
|
plugin.invoke(**kwargs)
|
|
471
|
+
|
|
472
|
+
except PluginValidationException as e:
|
|
473
|
+
# 插件抛出的参数校验异常
|
|
474
|
+
self.handle_plugin_valid_exception(e, pinfo, kwargs, plugin)
|
|
475
|
+
|
|
466
476
|
except JmcomicException as e:
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
477
|
+
# 模块内部异常,通过不是插件抛出的,而是插件调用了例如Client,Client请求失败抛出的
|
|
478
|
+
self.handle_plugin_exception(e, pinfo, kwargs, plugin)
|
|
479
|
+
|
|
470
480
|
except BaseException as e:
|
|
471
|
-
|
|
472
|
-
|
|
481
|
+
# 为插件兜底,捕获其他所有异常
|
|
482
|
+
self.handle_plugin_unexpected_error(e, pinfo, kwargs, plugin)
|
|
483
|
+
|
|
484
|
+
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
|
485
|
+
def handle_plugin_valid_exception(self, e, pinfo: dict, kwargs: dict, plugin):
|
|
486
|
+
from .jm_plugin import PluginValidationException
|
|
487
|
+
e: PluginValidationException
|
|
488
|
+
|
|
489
|
+
mode = pinfo.get('valid', self.plugins.valid)
|
|
490
|
+
|
|
491
|
+
if mode == 'ignore':
|
|
492
|
+
# ignore
|
|
493
|
+
return
|
|
494
|
+
|
|
495
|
+
if mode == 'debug':
|
|
496
|
+
# debug
|
|
497
|
+
jm_debug('plugin.validation',
|
|
498
|
+
f'插件 [{e.plugin.plugin_key}] 参数校验异常:{e.msg}'
|
|
499
|
+
)
|
|
500
|
+
return
|
|
501
|
+
|
|
502
|
+
if mode == 'raise':
|
|
503
|
+
# raise
|
|
473
504
|
raise e
|
|
474
505
|
|
|
506
|
+
# 其他的mode可以通过继承+方法重写来扩展
|
|
507
|
+
|
|
508
|
+
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
|
509
|
+
def handle_plugin_unexpected_error(self, e, pinfo: dict, kwargs: dict, plugin):
|
|
510
|
+
msg = str(e)
|
|
511
|
+
jm_debug('plugin.error', f'插件 [{plugin.plugin_key}],运行遇到未捕获异常,异常信息: {msg}')
|
|
512
|
+
raise e
|
|
513
|
+
|
|
514
|
+
# noinspection PyMethodMayBeStatic,PyUnusedLocal
|
|
515
|
+
def handle_plugin_exception(self, e, pinfo: dict, kwargs: dict, plugin):
|
|
516
|
+
msg = str(e)
|
|
517
|
+
jm_debug('plugin.exception', f'插件 [{plugin.plugin_key}],调用失败,异常信息: {msg}')
|
|
518
|
+
raise e
|
|
519
|
+
|
|
475
520
|
# noinspection PyMethodMayBeStatic
|
|
476
521
|
def fix_kwargs(self, kwargs) -> Dict[str, Any]:
|
|
477
522
|
"""
|
jmcomic/jm_plugin.py
CHANGED
|
@@ -5,6 +5,13 @@
|
|
|
5
5
|
from .jm_option import *
|
|
6
6
|
|
|
7
7
|
|
|
8
|
+
class PluginValidationException(Exception):
|
|
9
|
+
|
|
10
|
+
def __init__(self, plugin: 'JmOptionPlugin', msg: str):
|
|
11
|
+
self.plugin = plugin
|
|
12
|
+
self.msg = msg
|
|
13
|
+
|
|
14
|
+
|
|
8
15
|
class JmOptionPlugin:
|
|
9
16
|
plugin_key: str
|
|
10
17
|
|
|
@@ -33,6 +40,15 @@ class JmOptionPlugin:
|
|
|
33
40
|
msg=msg
|
|
34
41
|
)
|
|
35
42
|
|
|
43
|
+
def require_true(self, case: Any, msg: str):
|
|
44
|
+
"""
|
|
45
|
+
独立于ExceptionTool的一套异常抛出体系
|
|
46
|
+
"""
|
|
47
|
+
if case:
|
|
48
|
+
return
|
|
49
|
+
|
|
50
|
+
raise PluginValidationException(self, msg)
|
|
51
|
+
|
|
36
52
|
|
|
37
53
|
class JmLoginPlugin(JmOptionPlugin):
|
|
38
54
|
"""
|
|
@@ -44,8 +60,8 @@ class JmLoginPlugin(JmOptionPlugin):
|
|
|
44
60
|
username: str,
|
|
45
61
|
password: str,
|
|
46
62
|
) -> None:
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
self.require_true(username, '用户名不能为空')
|
|
64
|
+
self.require_true(password, '密码不能为空')
|
|
49
65
|
|
|
50
66
|
client = self.option.new_jm_client()
|
|
51
67
|
client.login(username, password)
|
|
@@ -326,14 +342,19 @@ class ZipPlugin(JmOptionPlugin):
|
|
|
326
342
|
删除所有文件和文件夹
|
|
327
343
|
"""
|
|
328
344
|
import os
|
|
329
|
-
for
|
|
330
|
-
for
|
|
331
|
-
for f,
|
|
345
|
+
for photo_dict in all_downloaded.values():
|
|
346
|
+
for image_list in photo_dict.values():
|
|
347
|
+
for f, _ in image_list:
|
|
348
|
+
# check not exist
|
|
349
|
+
if file_not_exists(f):
|
|
350
|
+
continue
|
|
351
|
+
|
|
332
352
|
os.remove(f)
|
|
333
353
|
self.debug(f'删除原文件: {f}', 'remove')
|
|
334
354
|
|
|
335
355
|
for d in dir_list:
|
|
336
|
-
|
|
356
|
+
# check exist
|
|
357
|
+
if file_exists(d) and len(os.listdir(d)) == 0:
|
|
337
358
|
os.removedirs(d)
|
|
338
359
|
self.debug(f'删除文件夹: {d}', 'remove')
|
|
339
360
|
|
|
@@ -403,11 +424,29 @@ class SendQQEmailPlugin(JmOptionPlugin):
|
|
|
403
424
|
album=None,
|
|
404
425
|
downloader=None,
|
|
405
426
|
) -> None:
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
return
|
|
427
|
+
self.require_true(msg_from and msg_to and password, '发件人、收件人、授权码都不能为空')
|
|
428
|
+
|
|
409
429
|
from common import EmailConfig
|
|
410
430
|
econfig = EmailConfig(msg_from, msg_to, password)
|
|
411
431
|
epostman = econfig.create_email_postman()
|
|
412
432
|
epostman.send(content, title)
|
|
433
|
+
|
|
413
434
|
self.debug('Email sent successfully')
|
|
435
|
+
|
|
436
|
+
|
|
437
|
+
class DebugTopicFilterPlugin(JmOptionPlugin):
|
|
438
|
+
plugin_key = 'debug_topic_filter'
|
|
439
|
+
|
|
440
|
+
def invoke(self, whitelist) -> None:
|
|
441
|
+
if whitelist is not None:
|
|
442
|
+
whitelist = set(whitelist)
|
|
443
|
+
|
|
444
|
+
old_jm_debug = JmModuleConfig.debug_executor
|
|
445
|
+
|
|
446
|
+
def new_jm_debug(topic, msg):
|
|
447
|
+
if whitelist is not None and topic not in whitelist:
|
|
448
|
+
return
|
|
449
|
+
|
|
450
|
+
old_jm_debug(topic, msg)
|
|
451
|
+
|
|
452
|
+
JmModuleConfig.debug_executor = new_jm_debug
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: jmcomic
|
|
3
|
-
Version: 2.3.
|
|
3
|
+
Version: 2.3.15
|
|
4
4
|
Summary: Python API For JMComic (禁漫天堂)
|
|
5
5
|
Home-page: https://github.com/hect0x7/JMComic-Crawler-Python
|
|
6
6
|
Author: hect0x7
|
|
@@ -68,7 +68,7 @@ $ jmcomic 422866
|
|
|
68
68
|
|
|
69
69
|
- GitHub Actions:网页上直接输入本子id就能下载([教程:使用GitHub Actions下载禁漫本子](./assets/docs/sources/tutorial/1_github_actions.md))
|
|
70
70
|
- 命令行:无需写Python代码,简单易用([教程:使用命令行下载禁漫本子](./assets/docs/sources/tutorial/2_command_line.md))
|
|
71
|
-
- Python
|
|
71
|
+
- Python代码:最本质、最强大的使用方式,需要你有一定的python编程基础
|
|
72
72
|
- 支持**网页端**和**移动端**两种客户端实现,可通过配置切换(**移动端不限ip兼容性好,网页端限制ip地区但效率高**)
|
|
73
73
|
- 支持**自动重试和域名切换**机制
|
|
74
74
|
- **多线程下载**(可细化到一图一线程,效率极高)
|
|
@@ -80,9 +80,9 @@ $ jmcomic 422866
|
|
|
80
80
|
- **可扩展性强**
|
|
81
81
|
|
|
82
82
|
- **支持Plugin插件,可以方便地扩展功能,以及使用别人的插件**
|
|
83
|
-
- 目前内置支持的插件有:`登录插件` `硬件占用监控插件` `只下载新章插件` `压缩文件插件` `下载特定后缀图片插件` `发送QQ邮件插件`
|
|
83
|
+
- 目前内置支持的插件有:`登录插件` `硬件占用监控插件` `只下载新章插件` `压缩文件插件` `下载特定后缀图片插件` `发送QQ邮件插件` `日志主题过滤插件`
|
|
84
84
|
- 支持自定义本子/章节/图片下载前后的回调函数
|
|
85
|
-
- 支持自定义debug
|
|
85
|
+
- 支持自定义debug/logging
|
|
86
86
|
- 支持自定义类:`Downloader(负责调度)` `Option(负责配置)` `Client(负责请求)` `实体类`等
|
|
87
87
|
|
|
88
88
|
## 进阶使用
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
jmcomic/__init__.py,sha256=us33H3aqW0Hlu7igzVxvRBtQ2S_8fwX92WfPTPnVUQ4,879
|
|
2
|
+
jmcomic/api.py,sha256=wzHtdI3AoB1NOKbx7hlcRD_KSUu_CexHKXS0pOLTAsI,2497
|
|
3
|
+
jmcomic/cl.py,sha256=ArDxQvt4G2YungPUqYHG5zWkUxQh71nY-T_IS2jzIV8,3489
|
|
4
|
+
jmcomic/jm_client_impl.py,sha256=ojNeh4BKRfrxxkWS1_VQr8ZpaknWRADGXPGWyQM2O1s,25068
|
|
5
|
+
jmcomic/jm_client_interface.py,sha256=r-y81BqiQSj74dwjnpa22uHbaYPVAENG6QOegx9g-F0,13087
|
|
6
|
+
jmcomic/jm_config.py,sha256=qL12dheI3iraHpw-SejweqTk7q5zpp-y0btOKXvA9I8,13422
|
|
7
|
+
jmcomic/jm_downloader.py,sha256=QcvBzTWAwGuZ9b10R5qYnXE_rjEIJvobsvNF5G5ZqXU,7207
|
|
8
|
+
jmcomic/jm_entity.py,sha256=6N5EBAWIl-rbVAak8HuGeyNB6KPM_kQ6ekPKfZht4c0,15082
|
|
9
|
+
jmcomic/jm_option.py,sha256=uNq6cjUkPXiAViEbdBW9XmvrFkNuE8X3bhpUJ-dVx70,18659
|
|
10
|
+
jmcomic/jm_plugin.py,sha256=VEfGu3xyj415dHR4VUVf-43O24S42Ki33dtdSzWGuvY,14223
|
|
11
|
+
jmcomic/jm_toolkit.py,sha256=K4ip55Di7ZZDv_Bnj-NvaOSKoRHaCmrMrXliD2vSJhw,21850
|
|
12
|
+
jmcomic-2.3.15.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
13
|
+
jmcomic-2.3.15.dist-info/METADATA,sha256=R3FlUuJYhRF87TxmDMwkqAWgV5N_K363zBX9N_KQEE8,4944
|
|
14
|
+
jmcomic-2.3.15.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
15
|
+
jmcomic-2.3.15.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
|
|
16
|
+
jmcomic-2.3.15.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
17
|
+
jmcomic-2.3.15.dist-info/RECORD,,
|
jmcomic-2.3.14.dist-info/RECORD
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
jmcomic/__init__.py,sha256=cpaa_TivIu_XDHXwKdE7w8-XJz0GNk5ZkNsE4YU-zAs,879
|
|
2
|
-
jmcomic/api.py,sha256=wzHtdI3AoB1NOKbx7hlcRD_KSUu_CexHKXS0pOLTAsI,2497
|
|
3
|
-
jmcomic/cl.py,sha256=ArDxQvt4G2YungPUqYHG5zWkUxQh71nY-T_IS2jzIV8,3489
|
|
4
|
-
jmcomic/jm_client_impl.py,sha256=1E9tIePPNW2OguqS8-Jk3uBlsirkEEYqtPzd53oaY5E,24742
|
|
5
|
-
jmcomic/jm_client_interface.py,sha256=r-y81BqiQSj74dwjnpa22uHbaYPVAENG6QOegx9g-F0,13087
|
|
6
|
-
jmcomic/jm_config.py,sha256=Wl9cfMiEoJszVd_SEIaxlux9N8gHfYQt1V0jHq6cJy8,13197
|
|
7
|
-
jmcomic/jm_downloader.py,sha256=TV_NhM4JEe210rAGypvoL181O4y5ejiiFSg-q38HBO0,7256
|
|
8
|
-
jmcomic/jm_entity.py,sha256=6N5EBAWIl-rbVAak8HuGeyNB6KPM_kQ6ekPKfZht4c0,15082
|
|
9
|
-
jmcomic/jm_option.py,sha256=3nI2e0U9V7w00xpM16358SvoOnKBvZUEfK4uQCBG5d8,16976
|
|
10
|
-
jmcomic/jm_plugin.py,sha256=kBE5lrfCkWn5ZXOq2K-w7es24vUM-WGBQC_A3tBl2jk,13194
|
|
11
|
-
jmcomic/jm_toolkit.py,sha256=K4ip55Di7ZZDv_Bnj-NvaOSKoRHaCmrMrXliD2vSJhw,21850
|
|
12
|
-
jmcomic-2.3.14.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
13
|
-
jmcomic-2.3.14.dist-info/METADATA,sha256=fCkMQgNJo7kFx2nhwz6L2Xk9kUAPJFkuoI4vGOPB_rk,4903
|
|
14
|
-
jmcomic-2.3.14.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
|
15
|
-
jmcomic-2.3.14.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
|
|
16
|
-
jmcomic-2.3.14.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
17
|
-
jmcomic-2.3.14.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|