jmcomic 2.3.15__py3-none-any.whl → 2.3.16__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 +12 -15
- jmcomic/jm_config.py +30 -13
- jmcomic/jm_option.py +6 -6
- jmcomic/jm_plugin.py +43 -29
- jmcomic/jm_toolkit.py +1 -1
- {jmcomic-2.3.15.dist-info → jmcomic-2.3.16.dist-info}/METADATA +1 -1
- jmcomic-2.3.16.dist-info/RECORD +17 -0
- jmcomic-2.3.15.dist-info/RECORD +0 -17
- {jmcomic-2.3.15.dist-info → jmcomic-2.3.16.dist-info}/LICENSE +0 -0
- {jmcomic-2.3.15.dist-info → jmcomic-2.3.16.dist-info}/WHEEL +0 -0
- {jmcomic-2.3.15.dist-info → jmcomic-2.3.16.dist-info}/entry_points.txt +0 -0
- {jmcomic-2.3.15.dist-info → jmcomic-2.3.16.dist-info}/top_level.txt +0 -0
jmcomic/__init__.py
CHANGED
jmcomic/jm_client_impl.py
CHANGED
|
@@ -493,13 +493,13 @@ class JmApiClient(AbstractJmClient):
|
|
|
493
493
|
}
|
|
494
494
|
)
|
|
495
495
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
jm_debug('api.scramble', '
|
|
502
|
-
scramble_id =
|
|
496
|
+
scramble_id = PatternTool.match_or_default(resp.text,
|
|
497
|
+
JmcomicText.pattern_html_album_scramble_id,
|
|
498
|
+
None,
|
|
499
|
+
)
|
|
500
|
+
if scramble_id is None:
|
|
501
|
+
jm_debug('api.scramble', f'未匹配到scramble_id,响应文本:{resp.text}')
|
|
502
|
+
scramble_id = str(JmModuleConfig.SCRAMBLE_220980)
|
|
503
503
|
|
|
504
504
|
return scramble_id
|
|
505
505
|
|
|
@@ -610,15 +610,12 @@ 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
613
|
def after_init(self):
|
|
620
|
-
cookies = self.__class__.fetch_init_cookies(self)
|
|
621
|
-
self.get_root_postman().get_meta_data()['cookies'] = cookies
|
|
614
|
+
# cookies = self.__class__.fetch_init_cookies(self)
|
|
615
|
+
# self.get_root_postman().get_meta_data()['cookies'] = cookies
|
|
616
|
+
|
|
617
|
+
self.get_root_postman().get_meta_data()['cookies'] = JmModuleConfig.get_cookies(self)
|
|
618
|
+
pass
|
|
622
619
|
|
|
623
620
|
|
|
624
621
|
class FutureClientProxy(JmcomicClient):
|
jmcomic/jm_config.py
CHANGED
|
@@ -3,7 +3,7 @@ def field_cache(*args, **kwargs):
|
|
|
3
3
|
return field_cache(*args, **kwargs)
|
|
4
4
|
|
|
5
5
|
|
|
6
|
-
def
|
|
6
|
+
def default_jm_debug_logging(topic: str, msg: str):
|
|
7
7
|
from common import format_ts
|
|
8
8
|
print(f'{format_ts()}:【{topic}】{msg}')
|
|
9
9
|
|
|
@@ -62,13 +62,14 @@ class JmModuleConfig:
|
|
|
62
62
|
SCRAMBLE_421926 = 421926 # 2023-02-08后改了图片切割算法
|
|
63
63
|
SCRAMBLE_CACHE = {}
|
|
64
64
|
|
|
65
|
-
# 移动端API
|
|
66
|
-
|
|
67
|
-
APP_SECRET = '18comicAPP'
|
|
65
|
+
# 移动端API密钥
|
|
66
|
+
APP_SECRET = '18comicAPPContent'
|
|
68
67
|
|
|
69
|
-
#
|
|
70
|
-
|
|
71
|
-
|
|
68
|
+
# cookies,目前只在移动端使用,因为移动端请求接口须携带,但不会校验cookies的内容。
|
|
69
|
+
APP_COOKIES = None
|
|
70
|
+
|
|
71
|
+
# 移动端图片域名
|
|
72
|
+
DOMAIN_IMAGE_LIST = str_to_list('''
|
|
72
73
|
cdn-msp.jmapiproxy1.monster
|
|
73
74
|
cdn-msp2.jmapiproxy1.monster
|
|
74
75
|
cdn-msp.jmapiproxy1.cc
|
|
@@ -78,7 +79,7 @@ class JmModuleConfig:
|
|
|
78
79
|
|
|
79
80
|
''')
|
|
80
81
|
|
|
81
|
-
# API域名
|
|
82
|
+
# 移动端API域名
|
|
82
83
|
DOMAIN_API_LIST = str_to_list('''
|
|
83
84
|
www.jmapinode1.top
|
|
84
85
|
www.jmapinode2.top
|
|
@@ -88,8 +89,11 @@ class JmModuleConfig:
|
|
|
88
89
|
|
|
89
90
|
''')
|
|
90
91
|
|
|
91
|
-
#
|
|
92
|
+
# 网页端域名配置
|
|
92
93
|
# 无需配置,默认为None,需要的时候会发起请求获得
|
|
94
|
+
# 使用优先级:
|
|
95
|
+
# 1. DOMAIN_HTML_LIST
|
|
96
|
+
# 2. [DOMAIN_HTML]
|
|
93
97
|
DOMAIN_HTML = None
|
|
94
98
|
DOMAIN_HTML_LIST = None
|
|
95
99
|
|
|
@@ -106,7 +110,7 @@ class JmModuleConfig:
|
|
|
106
110
|
REGISTRY_PLUGIN = {}
|
|
107
111
|
|
|
108
112
|
# 执行debug的函数
|
|
109
|
-
debug_executor =
|
|
113
|
+
debug_executor = default_jm_debug_logging
|
|
110
114
|
# postman构造函数
|
|
111
115
|
postman_constructor = default_postman_constructor
|
|
112
116
|
# 网页正则表达式解析失败时,执行抛出异常的函数,可以替换掉用于debug
|
|
@@ -190,7 +194,7 @@ class JmModuleConfig:
|
|
|
190
194
|
postman = postman or cls.new_postman(session=True)
|
|
191
195
|
|
|
192
196
|
url = postman.with_redirect_catching().get(cls.JM_REDIRECT_URL)
|
|
193
|
-
cls.jm_debug('
|
|
197
|
+
cls.jm_debug('module.html_url', f'获取禁漫网页URL: [{cls.JM_REDIRECT_URL}] → [{url}]')
|
|
194
198
|
return url
|
|
195
199
|
|
|
196
200
|
@classmethod
|
|
@@ -211,9 +215,22 @@ class JmModuleConfig:
|
|
|
211
215
|
from .jm_toolkit import JmcomicText
|
|
212
216
|
domain_list = JmcomicText.analyse_jm_pub_html(resp.text)
|
|
213
217
|
|
|
214
|
-
cls.jm_debug('
|
|
218
|
+
cls.jm_debug('module.html_domain_all', f'获取禁漫网页全部域名: [{resp.url}] → {domain_list}')
|
|
215
219
|
return domain_list
|
|
216
220
|
|
|
221
|
+
@classmethod
|
|
222
|
+
@field_cache("APP_COOKIES")
|
|
223
|
+
def get_cookies(cls, postman=None):
|
|
224
|
+
from .jm_toolkit import JmcomicText
|
|
225
|
+
url = JmcomicText.format_url('/setting', cls.DOMAIN_API_LIST[0])
|
|
226
|
+
postman = postman or cls.new_postman()
|
|
227
|
+
|
|
228
|
+
resp = postman.get(url)
|
|
229
|
+
cookies = dict(resp.cookies)
|
|
230
|
+
|
|
231
|
+
cls.jm_debug('module.cookies', f'获取cookies: [{url}] → {cookies}')
|
|
232
|
+
return cookies
|
|
233
|
+
|
|
217
234
|
@classmethod
|
|
218
235
|
def new_html_headers(cls, domain='18comic.vip'):
|
|
219
236
|
"""
|
|
@@ -247,7 +264,7 @@ class JmModuleConfig:
|
|
|
247
264
|
key_ts = time_stamp()
|
|
248
265
|
|
|
249
266
|
import hashlib
|
|
250
|
-
token = hashlib.md5(f"{key_ts}{cls.APP_SECRET}".encode()).hexdigest()
|
|
267
|
+
token = hashlib.md5(f"{key_ts}{cls.APP_SECRET}".encode("utf-8")).hexdigest()
|
|
251
268
|
|
|
252
269
|
return {
|
|
253
270
|
'token': token,
|
jmcomic/jm_option.py
CHANGED
|
@@ -314,6 +314,7 @@ class JmOption:
|
|
|
314
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
|
+
meta_data: dict = postman_conf['meta_data'] # 请求元信息
|
|
317
318
|
impl: str = impl or self.client.impl # client_key
|
|
318
319
|
retry_times: int = self.client.retry_times # 重试次数
|
|
319
320
|
cache: str = cache or self.client.cache # 启用缓存
|
|
@@ -335,15 +336,11 @@ class JmOption:
|
|
|
335
336
|
|
|
336
337
|
# support kwargs overwrite meta_data
|
|
337
338
|
if len(kwargs) != 0:
|
|
338
|
-
|
|
339
|
+
meta_data.update(kwargs)
|
|
339
340
|
|
|
340
341
|
# headers
|
|
341
|
-
meta_data = postman_conf['meta_data']
|
|
342
342
|
if meta_data['headers'] is None:
|
|
343
|
-
headers = self.decide_postman_headers(impl, domain[0])
|
|
344
|
-
# if headers is None:
|
|
345
|
-
# postman_conf['type'] = 'requests'
|
|
346
|
-
meta_data['headers'] = headers
|
|
343
|
+
meta_data['headers'] = self.decide_postman_headers(impl, domain[0])
|
|
347
344
|
|
|
348
345
|
# postman
|
|
349
346
|
postman = Postmans.create(data=postman_conf)
|
|
@@ -375,6 +372,9 @@ class JmOption:
|
|
|
375
372
|
|
|
376
373
|
if is_client_type(JmHtmlClient):
|
|
377
374
|
# 网页端
|
|
375
|
+
domain_list = JmModuleConfig.DOMAIN_HTML_LIST
|
|
376
|
+
if domain_list is not None:
|
|
377
|
+
return domain_list
|
|
378
378
|
return [JmModuleConfig.get_html_domain()]
|
|
379
379
|
|
|
380
380
|
ExceptionTool.raises(f'没有配置域名,且是无法识别的client类型: {client_key}')
|
jmcomic/jm_plugin.py
CHANGED
|
@@ -249,26 +249,32 @@ class ZipPlugin(JmOptionPlugin):
|
|
|
249
249
|
mkdir_if_not_exists(zip_dir)
|
|
250
250
|
|
|
251
251
|
# 原文件夹 -> zip文件
|
|
252
|
-
dir_zip_dict = {}
|
|
252
|
+
dir_zip_dict: Dict[str, Optional[str]] = {}
|
|
253
253
|
photo_dict = downloader.all_downloaded[album]
|
|
254
254
|
|
|
255
255
|
if level == 'album':
|
|
256
256
|
zip_path = self.get_zip_path(album, None, filename_rule, suffix, zip_dir)
|
|
257
257
|
dir_path = self.zip_album(album, photo_dict, zip_path)
|
|
258
|
-
|
|
258
|
+
if dir_path is not None:
|
|
259
|
+
# 要删除这个album文件夹
|
|
260
|
+
dir_zip_dict[dir_path] = zip_path
|
|
261
|
+
# 也要删除album下的photo文件夹
|
|
262
|
+
for d in files_of_dir(dir_path):
|
|
263
|
+
dir_zip_dict[d] = None
|
|
259
264
|
|
|
260
265
|
elif level == 'photo':
|
|
261
266
|
for photo, image_list in photo_dict.items():
|
|
262
267
|
zip_path = self.get_zip_path(None, photo, filename_rule, suffix, zip_dir)
|
|
263
268
|
dir_path = self.zip_photo(photo, image_list, zip_path)
|
|
264
|
-
|
|
269
|
+
if dir_path is not None:
|
|
270
|
+
dir_zip_dict[dir_path] = zip_path
|
|
265
271
|
|
|
266
272
|
else:
|
|
267
273
|
ExceptionTool.raises(f'Not Implemented Zip Level: {level}')
|
|
268
274
|
|
|
269
275
|
self.after_zip(dir_zip_dict)
|
|
270
276
|
|
|
271
|
-
def zip_photo(self, photo, image_list: list, zip_path: str):
|
|
277
|
+
def zip_photo(self, photo, image_list: list, zip_path: str) -> Optional[str]:
|
|
272
278
|
"""
|
|
273
279
|
压缩photo文件夹
|
|
274
280
|
:returns: photo文件夹路径
|
|
@@ -277,46 +283,54 @@ class ZipPlugin(JmOptionPlugin):
|
|
|
277
283
|
if len(image_list) == 0 \
|
|
278
284
|
else os.path.dirname(image_list[0][0])
|
|
279
285
|
|
|
280
|
-
all_filepath = set(map(lambda t: t[0], image_list))
|
|
286
|
+
all_filepath = set(map(lambda t: self.unified_path(t[0]), image_list))
|
|
281
287
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
backup_dir_to_zip(photo_dir, zip_path, acceptor=lambda f: f in all_filepath)
|
|
288
|
-
self.debug(f'压缩章节[{photo.photo_id}]成功 → {zip_path}', 'finish')
|
|
288
|
+
return self.do_zip(photo_dir,
|
|
289
|
+
zip_path,
|
|
290
|
+
all_filepath,
|
|
291
|
+
f'压缩章节[{photo.photo_id}]成功 → {zip_path}',
|
|
292
|
+
)
|
|
289
293
|
|
|
290
|
-
|
|
294
|
+
@staticmethod
|
|
295
|
+
def unified_path(f):
|
|
296
|
+
return fix_filepath(f, os.path.isdir(f))
|
|
291
297
|
|
|
292
|
-
def zip_album(self, album, photo_dict: dict, zip_path):
|
|
298
|
+
def zip_album(self, album, photo_dict: dict, zip_path) -> Optional[str]:
|
|
293
299
|
"""
|
|
294
300
|
压缩album文件夹
|
|
295
301
|
:returns: album文件夹路径
|
|
296
302
|
"""
|
|
297
|
-
album_dir = self.option.decide_album_dir(album)
|
|
298
303
|
all_filepath: Set[str] = set()
|
|
299
304
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
305
|
+
def addpath(f):
|
|
306
|
+
all_filepath.update(set(f))
|
|
307
|
+
|
|
308
|
+
album_dir = self.option.decide_album_dir(album)
|
|
309
|
+
# addpath(self.option.decide_image_save_dir(photo) for photo in photo_dict.keys())
|
|
310
|
+
addpath(path for ls in photo_dict.values() for path, _ in ls)
|
|
311
|
+
|
|
312
|
+
return self.do_zip(album_dir,
|
|
313
|
+
zip_path,
|
|
314
|
+
all_filepath,
|
|
315
|
+
msg=f'压缩本子[{album.album_id}]成功 → {zip_path}',
|
|
316
|
+
)
|
|
304
317
|
|
|
318
|
+
def do_zip(self, source_dir, zip_path, all_filepath, msg):
|
|
305
319
|
if len(all_filepath) == 0:
|
|
306
320
|
self.debug('无下载文件,无需压缩', 'skip')
|
|
307
|
-
return
|
|
321
|
+
return None
|
|
308
322
|
|
|
309
323
|
from common import backup_dir_to_zip
|
|
310
324
|
backup_dir_to_zip(
|
|
311
|
-
|
|
325
|
+
source_dir,
|
|
312
326
|
zip_path,
|
|
313
|
-
acceptor=lambda f: f in all_filepath
|
|
314
|
-
)
|
|
327
|
+
acceptor=lambda f: os.path.isdir(f) or self.unified_path(f) in all_filepath
|
|
328
|
+
).close()
|
|
315
329
|
|
|
316
|
-
self.debug(
|
|
317
|
-
return
|
|
330
|
+
self.debug(msg, 'finish')
|
|
331
|
+
return self.unified_path(source_dir)
|
|
318
332
|
|
|
319
|
-
def after_zip(self, dir_zip_dict: Dict[str, str]):
|
|
333
|
+
def after_zip(self, dir_zip_dict: Dict[str, Optional[str]]):
|
|
320
334
|
# 是否要删除所有原文件
|
|
321
335
|
if self.delete_original_file is True:
|
|
322
336
|
self.delete_all_files_and_empty_dir(
|
|
@@ -352,10 +366,10 @@ class ZipPlugin(JmOptionPlugin):
|
|
|
352
366
|
os.remove(f)
|
|
353
367
|
self.debug(f'删除原文件: {f}', 'remove')
|
|
354
368
|
|
|
355
|
-
for d in dir_list:
|
|
369
|
+
for d in sorted(dir_list, reverse=True):
|
|
356
370
|
# check exist
|
|
357
|
-
if file_exists(d)
|
|
358
|
-
os.
|
|
371
|
+
if file_exists(d):
|
|
372
|
+
os.rmdir(d)
|
|
359
373
|
self.debug(f'删除文件夹: {d}', 'remove')
|
|
360
374
|
|
|
361
375
|
|
jmcomic/jm_toolkit.py
CHANGED
|
@@ -489,7 +489,7 @@ class JmApiAdaptTool:
|
|
|
489
489
|
|
|
490
490
|
fields['sort'] = sort
|
|
491
491
|
import random
|
|
492
|
-
fields['data_original_domain'] = random.choice(JmModuleConfig.
|
|
492
|
+
fields['data_original_domain'] = random.choice(JmModuleConfig.DOMAIN_IMAGE_LIST)
|
|
493
493
|
|
|
494
494
|
|
|
495
495
|
class JmImageTool:
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
jmcomic/__init__.py,sha256=qqA6jypcSuTQ_DN37vmWjpu-jC8pkxB_s-AiFhj2Y6E,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=fDx5VZnlmYpdie5grHfwf8E-zh-QYrbdHzUJK5nqdw4,25161
|
|
5
|
+
jmcomic/jm_client_interface.py,sha256=r-y81BqiQSj74dwjnpa22uHbaYPVAENG6QOegx9g-F0,13087
|
|
6
|
+
jmcomic/jm_config.py,sha256=x8Xi4aTNn8YX32d_f7Wy775Kp9YTlqYJS64Rl3wpOVY,14092
|
|
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=YxLO4uqnTVqj5A9Ouv_lbQ7rSBA2zgbWuSW0yKuMxdA,18685
|
|
10
|
+
jmcomic/jm_plugin.py,sha256=nLCyrWTjaSXCRcVHZBwJtgzYeeNEc92vOqw0_8AwJpA,14906
|
|
11
|
+
jmcomic/jm_toolkit.py,sha256=YrOlDp_fYQ5Ggu40Py-jArM2D1GfpQ7VJycfnR6aaLs,21846
|
|
12
|
+
jmcomic-2.3.16.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
|
|
13
|
+
jmcomic-2.3.16.dist-info/METADATA,sha256=s1R-negNRV1gArP_eLwwp45AsD-LTzbY36ddCEo3iXY,4944
|
|
14
|
+
jmcomic-2.3.16.dist-info/WHEEL,sha256=Xo9-1PvkuimrydujYJAjF7pCkriuXBpUPEjma1nZyJ0,92
|
|
15
|
+
jmcomic-2.3.16.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
|
|
16
|
+
jmcomic-2.3.16.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
|
|
17
|
+
jmcomic-2.3.16.dist-info/RECORD,,
|
jmcomic-2.3.15.dist-info/RECORD
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
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,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|