jmcomic 2.4.6__py3-none-any.whl → 2.4.7__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 CHANGED
@@ -2,7 +2,7 @@
2
2
  # 被依赖方 <--- 使用方
3
3
  # config <--- entity <--- toolkit <--- client <--- option <--- downloader
4
4
 
5
- __version__ = '2.4.6'
5
+ __version__ = '2.4.7'
6
6
 
7
7
  from .api import *
8
8
  from .jm_plugin import *
jmcomic/jm_client_impl.py CHANGED
@@ -1,3 +1,5 @@
1
+ from threading import Lock
2
+
1
3
  from .jm_client_interface import *
2
4
 
3
5
 
@@ -25,6 +27,7 @@ class AbstractJmClient(
25
27
  self.retry_times = retry_times
26
28
  self.domain_list = domain_list
27
29
  self.CLIENT_CACHE = None
30
+ self.__username = None # help for favorite_folder method
28
31
  self.enable_cache()
29
32
  self.after_init()
30
33
 
@@ -50,7 +53,7 @@ class AbstractJmClient(
50
53
  resp.require_success()
51
54
  return resp
52
55
 
53
- return self.get(img_url, judge=judge)
56
+ return self.get(img_url, judge=judge, headers=JmModuleConfig.new_html_headers())
54
57
 
55
58
  def request_with_retry(self,
56
59
  request,
@@ -61,7 +64,12 @@ class AbstractJmClient(
61
64
  **kwargs,
62
65
  ):
63
66
  """
64
- 统一请求,支持重试
67
+ 支持重试和切换域名的机制
68
+
69
+ 如果url包含了指定域名,则不会切换域名,例如图片URL。
70
+
71
+ 如果需要拿到域名进行回调处理,可以重写 self.update_request_with_specify_domain 方法,例如更新headers
72
+
65
73
  :param request: 请求方法
66
74
  :param url: 图片url / path (/album/xxx)
67
75
  :param domain_index: 域名下标
@@ -74,10 +82,11 @@ class AbstractJmClient(
74
82
 
75
83
  if url.startswith('/'):
76
84
  # path → url
77
- url = self.of_api_url(
78
- api_path=url,
79
- domain=self.domain_list[domain_index],
80
- )
85
+ domain = self.domain_list[domain_index]
86
+ url = self.of_api_url(url, domain)
87
+
88
+ self.update_request_with_specify_domain(kwargs, domain)
89
+
81
90
  jm_log(self.log_topic(), self.decode(url))
82
91
  else:
83
92
  # 图片url
@@ -96,6 +105,8 @@ class AbstractJmClient(
96
105
  try:
97
106
  resp = request(url, **kwargs)
98
107
  return judge(resp)
108
+ except KeyboardInterrupt as e:
109
+ raise e
99
110
  except Exception as e:
100
111
  if self.retry_times == 0:
101
112
  raise e
@@ -107,6 +118,12 @@ class AbstractJmClient(
107
118
  else:
108
119
  return self.request_with_retry(request, url, domain_index + 1, 0, judge, **kwargs)
109
120
 
121
+ def update_request_with_specify_domain(self, kwargs: dict, domain: str):
122
+ """
123
+ 域名自动切换时,用于更新请求参数的回调
124
+ """
125
+ pass
126
+
110
127
  # noinspection PyMethodMayBeStatic
111
128
  def log_topic(self):
112
129
  return self.client_key
@@ -205,6 +222,34 @@ class JmHtmlClient(AbstractJmClient):
205
222
 
206
223
  func_to_cache = ['search', 'fetch_detail_entity']
207
224
 
225
+ def add_favorite_album(self,
226
+ album_id,
227
+ folder_id='0',
228
+ ):
229
+ data = {
230
+ 'album_id': album_id,
231
+ 'fid': folder_id,
232
+ }
233
+
234
+ resp = self.get_jm_html(
235
+ '/ajax/favorite_album',
236
+ data=data,
237
+ )
238
+
239
+ res = resp.json()
240
+
241
+ if res['status'] != 1:
242
+ msg = parse_unicode_escape_text(res['msg'])
243
+ error_msg = PatternTool.match_or_default(msg, JmcomicText.pattern_ajax_favorite_msg, msg)
244
+ # 此圖片已經在您最喜愛的清單!
245
+
246
+ self.raise_request_error(
247
+ resp,
248
+ error_msg
249
+ )
250
+
251
+ return resp
252
+
208
253
  def get_album_detail(self, album_id) -> JmAlbumDetail:
209
254
  return self.fetch_detail_entity(album_id, 'album')
210
255
 
@@ -301,6 +346,7 @@ class JmHtmlClient(AbstractJmClient):
301
346
  return resp
302
347
 
303
348
  self['cookies'] = new_cookies
349
+ self.__username = username
304
350
 
305
351
  return resp
306
352
 
@@ -311,7 +357,8 @@ class JmHtmlClient(AbstractJmClient):
311
357
  username='',
312
358
  ) -> JmFavoritePage:
313
359
  if username == '':
314
- username = self.get_username_or_raise()
360
+ ExceptionTool.require_true(self.__username is not None, 'favorite_folder方法需要传username参数')
361
+ username = self.__username
315
362
 
316
363
  resp = self.get_jm_html(
317
364
  f'/user/{username}/favorite/albums',
@@ -325,13 +372,12 @@ class JmHtmlClient(AbstractJmClient):
325
372
  return JmPageTool.parse_html_to_favorite_page(resp.text)
326
373
 
327
374
  # noinspection PyTypeChecker
328
- def get_username_or_raise(self) -> str:
329
- cookies = self.get_meta_data('cookies', None)
330
- if not cookies:
331
- ExceptionTool.raises('未登录,无法获取到对应的用户名,需要传username参数')
332
-
375
+ def get_username_from_cookies(self) -> str:
376
+ # cookies = self.get_meta_data('cookies', None)
377
+ # if not cookies:
378
+ # ExceptionTool.raises('未登录,无法获取到对应的用户名,请给favorite方法传入username参数')
333
379
  # 解析cookies,可能需要用到 phpserialize,比较麻烦,暂不实现
334
- ExceptionTool.raises('需要传username参数')
380
+ pass
335
381
 
336
382
  def get_jm_html(self, url, require_200=True, **kwargs):
337
383
  """
@@ -351,6 +397,12 @@ class JmHtmlClient(AbstractJmClient):
351
397
 
352
398
  return resp
353
399
 
400
+ def update_request_with_specify_domain(self, kwargs: dict, domain: Optional[str]):
401
+ latest_headers = kwargs.get('headers', None)
402
+ base_headers = self.get_meta_data('headers', None) or JmModuleConfig.new_html_headers(domain)
403
+ base_headers.update(latest_headers or {})
404
+ kwargs['headers'] = base_headers
405
+
354
406
  @classmethod
355
407
  def raise_request_error(cls, resp, msg: Optional[str] = None):
356
408
  """
@@ -393,10 +445,7 @@ class JmHtmlClient(AbstractJmClient):
393
445
  (f' to ({comment_id})' if comment_id is not None else '')
394
446
  )
395
447
 
396
- resp = self.post('/ajax/album_comment',
397
- headers=self.album_comment_headers,
398
- data=data,
399
- )
448
+ resp = self.post('/ajax/album_comment', data=data)
400
449
 
401
450
  ret = JmAlbumCommentResp(resp)
402
451
  jm_log('album.comment', f'{video_id}: [{comment}] ← ({ret.model().cid})')
@@ -469,26 +518,6 @@ class JmHtmlClient(AbstractJmClient):
469
518
  + (f'URL=[{url}]' if url is not None else '')
470
519
  )
471
520
 
472
- album_comment_headers = {
473
- 'authority': '18comic.vip',
474
- 'accept': 'application/json, text/javascript, */*; q=0.01',
475
- 'accept-language': 'zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7',
476
- 'cache-control': 'no-cache',
477
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
478
- 'origin': 'https://18comic.vip',
479
- 'pragma': 'no-cache',
480
- 'referer': 'https://18comic.vip/album/248965/',
481
- 'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"',
482
- 'sec-ch-ua-mobile': '?0',
483
- 'sec-ch-ua-platform': '"Windows"',
484
- 'sec-fetch-dest': 'empty',
485
- 'sec-fetch-mode': 'cors',
486
- 'sec-fetch-site': 'same-origin',
487
- 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
488
- 'Chrome/114.0.0.0 Safari/537.36',
489
- 'x-requested-with': 'XMLHttpRequest',
490
- }
491
-
492
521
 
493
522
  # 基于禁漫移动端(APP)实现的JmClient
494
523
  class JmApiClient(AbstractJmClient):
@@ -581,8 +610,6 @@ class JmApiClient(AbstractJmClient):
581
610
  },
582
611
  )
583
612
 
584
- self.require_resp_success(resp, url)
585
-
586
613
  return JmApiAdaptTool.parse_entity(resp.res_data, clazz)
587
614
 
588
615
  def fetch_scramble_id(self, photo_id):
@@ -600,6 +627,7 @@ class JmApiClient(AbstractJmClient):
600
627
  'express': 'off',
601
628
  'v': time_stamp(),
602
629
  },
630
+ require_success=False,
603
631
  )
604
632
 
605
633
  scramble_id = PatternTool.match_or_default(resp.text,
@@ -712,7 +740,6 @@ class JmApiClient(AbstractJmClient):
712
740
  'password': password,
713
741
  })
714
742
 
715
- resp.require_success()
716
743
  cookies = dict(resp.resp.cookies)
717
744
  cookies.update({'AVS': resp.res_data['s']})
718
745
  self['cookies'] = cookies
@@ -736,7 +763,34 @@ class JmApiClient(AbstractJmClient):
736
763
 
737
764
  return JmPageTool.parse_api_to_favorite_page(resp.model_data)
738
765
 
739
- def req_api(self, url, get=True, **kwargs) -> JmApiResp:
766
+ def add_favorite_album(self,
767
+ album_id,
768
+ folder_id='0',
769
+ ):
770
+ """
771
+ 移动端没有提供folder_id参数
772
+ """
773
+ resp = self.req_api(
774
+ '/favorite',
775
+ data={
776
+ 'aid': album_id,
777
+ },
778
+ )
779
+
780
+ self.require_resp_status_ok(resp)
781
+
782
+ return resp
783
+
784
+ # noinspection PyMethodMayBeStatic
785
+ def require_resp_status_ok(self, resp: JmApiResp):
786
+ """
787
+ 检查返回数据中的status字段是否为ok
788
+ """
789
+ data = resp.model_data
790
+ if data.status == 'ok':
791
+ ExceptionTool.raises_resp(data.msg, resp)
792
+
793
+ def req_api(self, url, get=True, require_success=True, **kwargs) -> JmApiResp:
740
794
  ts = self.decide_headers_and_ts(kwargs, url)
741
795
 
742
796
  if get:
@@ -744,7 +798,15 @@ class JmApiClient(AbstractJmClient):
744
798
  else:
745
799
  resp = self.post(url, **kwargs)
746
800
 
747
- return JmApiResp(resp, ts)
801
+ resp = JmApiResp(resp, ts)
802
+
803
+ if require_success:
804
+ self.require_resp_success(resp, url)
805
+
806
+ return resp
807
+
808
+ def update_request_with_specify_domain(self, kwargs: dict, domain: str):
809
+ pass
748
810
 
749
811
  # noinspection PyMethodMayBeStatic
750
812
  def decide_headers_and_ts(self, kwargs, url):
@@ -791,7 +853,6 @@ class JmApiClient(AbstractJmClient):
791
853
  if JmModuleConfig.flag_api_client_require_cookies:
792
854
  self.ensure_have_cookies()
793
855
 
794
- from threading import Lock
795
856
  client_init_cookies_lock = Lock()
796
857
 
797
858
  def ensure_have_cookies(self):
@@ -826,9 +887,6 @@ class FutureClientProxy(JmcomicClient):
826
887
  ```
827
888
  """
828
889
  client_key = 'cl_proxy_future'
829
- proxy_methods = ['album_comment', 'enable_cache', 'get_domain_list',
830
- 'get_html_domain', 'get_html_domain_all', 'get_jm_image',
831
- 'set_cache_dict', 'get_cache_dict', 'set_domain_list', ]
832
890
 
833
891
  class FutureWrapper:
834
892
  def __init__(self, future, after_done_callback):
@@ -855,8 +913,7 @@ class FutureClientProxy(JmcomicClient):
855
913
  executors=None,
856
914
  ):
857
915
  self.client = client
858
- for method in self.proxy_methods:
859
- setattr(self, method, getattr(client, method))
916
+ self.route_notimpl_method_to_internal_client(client)
860
917
 
861
918
  if executors is None:
862
919
  from concurrent.futures import ThreadPoolExecutor
@@ -867,6 +924,25 @@ class FutureClientProxy(JmcomicClient):
867
924
  from threading import Lock
868
925
  self.lock = Lock()
869
926
 
927
+ def route_notimpl_method_to_internal_client(self, client):
928
+
929
+ impl_methods = str_to_set('''
930
+ get_album_detail
931
+ get_photo_detail
932
+ search
933
+ ''')
934
+
935
+ # 获取对象的所有属性和方法的名称列表
936
+ attributes_and_methods = dir(client)
937
+ # 遍历属性和方法列表,并访问每个方法
938
+ for method in attributes_and_methods:
939
+ # 判断是否为方法(可调用对象)
940
+ if (not method.startswith('_')
941
+ and callable(getattr(client, method))
942
+ and method not in impl_methods
943
+ ):
944
+ setattr(self, method, getattr(client, method))
945
+
870
946
  def get_album_detail(self, album_id) -> JmAlbumDetail:
871
947
  album_id = JmcomicText.parse_to_jm_id(album_id)
872
948
  cache_key = f'album_{album_id}'
@@ -229,6 +229,15 @@ class JmUserClient:
229
229
  """
230
230
  raise NotImplementedError
231
231
 
232
+ def add_favorite_album(self,
233
+ album_id,
234
+ folder_id='0',
235
+ ):
236
+ """
237
+ 把漫画加入收藏夹
238
+ """
239
+ raise NotImplementedError
240
+
232
241
 
233
242
  class JmImageClient:
234
243
 
jmcomic/jm_config.py CHANGED
@@ -260,6 +260,7 @@ class JmModuleConfig:
260
260
  headers = JmMagicConstants.HTML_HEADERS_TEMPLATE.copy()
261
261
  headers.update({
262
262
  'authority': domain,
263
+ 'origin': f'https://{domain}',
263
264
  'referer': f'https://{domain}',
264
265
  })
265
266
  return headers
@@ -296,9 +297,12 @@ class JmModuleConfig:
296
297
  return Postmans.new_postman(**kwargs)
297
298
 
298
299
  # option 相关的默认配置
300
+ # 一般情况下,建议使用option配置文件来定制配置
301
+ # 而如果只想修改几个简单常用的配置,也可以下方的DEFAULT_XXX属性
299
302
  JM_OPTION_VER = '2.1'
300
- DEFAULT_CLIENT_IMPL = 'html'
301
- DEFAULT_PROXIES = ProxyBuilder.system_proxy() # use system proxy by default
303
+ DEFAULT_CLIENT_IMPL = 'html' # 默认Client实现类型为网页端
304
+ DEFAULT_CLIENT_CACHE = True # 默认开启Client缓存,缓存级别是level_option,详见CacheRegistry
305
+ DEFAULT_PROXIES = ProxyBuilder.system_proxy() # 默认使用系统代理
302
306
 
303
307
  default_option_dict: dict = {
304
308
  'log': None,
@@ -355,7 +359,7 @@ class JmModuleConfig:
355
359
  # client cache
356
360
  client = option_dict['client']
357
361
  if client['cache'] is None:
358
- client['cache'] = True
362
+ client['cache'] = cls.DEFAULT_CLIENT_CACHE
359
363
 
360
364
  # client impl
361
365
  if client['impl'] is None:
jmcomic/jm_downloader.py CHANGED
@@ -115,7 +115,7 @@ class JmDownloader(DownloadCallback):
115
115
  """
116
116
  调度本子/章节的下载
117
117
  """
118
- iter_objs = self.filter_iter_objs(iter_objs)
118
+ iter_objs = self.do_filter(iter_objs)
119
119
  count_real = len(iter_objs)
120
120
 
121
121
  if count_real == 0:
@@ -136,14 +136,14 @@ class JmDownloader(DownloadCallback):
136
136
  )
137
137
 
138
138
  # noinspection PyMethodMayBeStatic
139
- def filter_iter_objs(self, detail: DetailEntity):
139
+ def do_filter(self, detail: DetailEntity):
140
140
  """
141
141
  该方法可用于过滤本子/章节,默认不会做过滤。
142
142
  例如:
143
143
  只想下载 本子的最新一章,返回 [album[-1]]
144
144
  只想下载 章节的前10张图片,返回 [photo[:10]]
145
145
 
146
- :param detail: 可能是本子或者章节,需要自行使用 isinstance / is_xxx 判断
146
+ :param detail: 可能是本子或者章节,需要自行使用 isinstance / detail.is_xxx 判断
147
147
  :returns: 只想要下载的 本子的章节 或 章节的图片
148
148
  """
149
149
  return detail
@@ -198,3 +198,18 @@ class JmDownloader(DownloadCallback):
198
198
  jm_log('dler.exception',
199
199
  f'{self.__class__.__name__} Exit with exception: {exc_type, exc_val}'
200
200
  )
201
+
202
+
203
+ class DoNotDownloadImage(JmDownloader):
204
+ """
205
+ 本类仅用于测试
206
+
207
+ 用法:
208
+
209
+ JmModuleConfig.CLASS_DOWNLOADER = DoNotDownloadImage
210
+ """
211
+
212
+ def download_by_image_detail(self, image: JmImageDetail, client: JmcomicClient):
213
+ # ensure make dir
214
+ self.option.decide_image_filepath(image)
215
+ pass
jmcomic/jm_entity.py CHANGED
@@ -175,8 +175,8 @@ class JmImageDetail(JmBaseEntity):
175
175
  self.img_file_suffix: str = img_file_suffix
176
176
 
177
177
  self.from_photo: Optional[JmPhotoDetail] = from_photo
178
- self.query_params: StrNone = query_params
179
- self.index = index # 从1开始
178
+ self.query_params: Optional[str] = query_params
179
+ self.index = index # 从1开始
180
180
 
181
181
  # temp fields, in order to simplify passing parameter
182
182
  self.save_path: str = ''
@@ -266,7 +266,7 @@ class JmPhotoDetail(DetailEntity):
266
266
  self._tags: str = tags
267
267
  self._series_id: int = int(series_id)
268
268
 
269
- self._author: StrNone = author
269
+ self._author: Optional[str] = author
270
270
  self.from_album: Optional[JmAlbumDetail] = from_album
271
271
  self.index = self.album_index
272
272
 
@@ -278,7 +278,7 @@ class JmPhotoDetail(DetailEntity):
278
278
  # page_arr存放了该photo的所有图片文件名 img_name
279
279
  self.page_arr: List[str] = page_arr
280
280
  # 图片的cdn域名
281
- self.data_original_domain: StrNone = data_original_domain
281
+ self.data_original_domain: Optional[str] = data_original_domain
282
282
  # 第一张图的URL
283
283
  self.data_original_0 = data_original_0
284
284
 
@@ -372,7 +372,7 @@ class JmPhotoDetail(DetailEntity):
372
372
  return f'{JmModuleConfig.PROT}{domain}/media/photos/{self.photo_id}/{img_name}'
373
373
 
374
374
  # noinspection PyMethodMayBeStatic
375
- def get_data_original_query_params(self, data_original_0: StrNone) -> str:
375
+ def get_data_original_query_params(self, data_original_0: Optional[str]) -> str:
376
376
  if data_original_0 is None:
377
377
  return f'v={time_stamp()}'
378
378
 
@@ -534,12 +534,18 @@ class JmPageContent(JmBaseEntity, IndexedEntity):
534
534
 
535
535
  @property
536
536
  def page_count(self) -> int:
537
+ """
538
+ 页数
539
+ """
537
540
  page_size = self.page_size
538
541
  import math
539
542
  return math.ceil(int(self.total) / page_size)
540
543
 
541
544
  @property
542
545
  def page_size(self) -> int:
546
+ """
547
+ 页大小
548
+ """
543
549
  raise NotImplementedError
544
550
 
545
551
  def iter_id(self) -> Generator[str, None, None]:
jmcomic/jm_option.py CHANGED
@@ -276,22 +276,10 @@ class JmOption:
276
276
  return JmModuleConfig.option_default_dict()
277
277
 
278
278
  @classmethod
279
- def default(cls, proxies=None, domain=None) -> 'JmOption':
279
+ def default(cls) -> 'JmOption':
280
280
  """
281
281
  使用默认的 JmOption
282
- proxies, domain 为常用配置项,为了方便起见直接支持参数配置。
283
- 其他配置项建议还是使用配置文件
284
- :param proxies: clash; 127.0.0.1:7890; v2ray
285
- :param domain: 18comic.vip; ["18comic.vip"]
286
282
  """
287
- if proxies is not None or domain is not None:
288
- return cls.construct({
289
- 'client': {
290
- 'domain': [domain] if isinstance(domain, str) else domain,
291
- 'postman': {'meta_data': {'proxies': ProxyBuilder.build_by_str(proxies)}},
292
- },
293
- })
294
-
295
283
  return cls.construct({})
296
284
 
297
285
  @classmethod
@@ -372,7 +360,7 @@ class JmOption:
372
360
  """
373
361
  return self.new_jm_client(**kwargs)
374
362
 
375
- def new_jm_client(self, domain=None, impl=None, cache=None, **kwargs) -> JmcomicClient:
363
+ def new_jm_client(self, domain_list=None, impl=None, cache=None, **kwargs) -> JmcomicClient:
376
364
  """
377
365
  创建新的Client(客户端),不同Client之间的元数据不共享
378
366
  """
@@ -380,10 +368,15 @@ class JmOption:
380
368
 
381
369
  # 所有需要用到的 self.client 配置项如下
382
370
  postman_conf: dict = deepcopy(self.client.postman.src_dict) # postman dsl 配置
371
+
383
372
  meta_data: dict = postman_conf['meta_data'] # 元数据
373
+
384
374
  retry_times: int = self.client.retry_times # 重试次数
375
+
385
376
  cache: str = cache if cache is not None else self.client.cache # 启用缓存
377
+
386
378
  impl: str = impl or self.client.impl # client_key
379
+
387
380
  if isinstance(impl, type):
388
381
  # eg: impl = JmHtmlClient
389
382
  # noinspection PyUnresolvedReferences
@@ -392,28 +385,30 @@ class JmOption:
392
385
  # start construct client
393
386
 
394
387
  # domain
395
- def decide_domain():
396
- domain_list: Union[List[str], DictModel, dict] = domain if domain is not None \
397
- else self.client.domain # 域名
388
+ def decide_domain_list():
389
+ nonlocal domain_list
398
390
 
399
- if not isinstance(domain_list, list):
391
+ if domain_list is None:
392
+ domain_list = self.client.domain
393
+
394
+ if not isinstance(domain_list, (list, str)):
395
+ # dict
400
396
  domain_list = domain_list.get(impl, [])
401
397
 
398
+ if isinstance(domain_list, str):
399
+ # multi-lines text
400
+ domain_list = str_to_list(domain_list)
401
+
402
+ # list or str
402
403
  if len(domain_list) == 0:
403
404
  domain_list = self.decide_client_domain(impl)
404
405
 
405
406
  return domain_list
406
407
 
407
- domain: List[str] = decide_domain()
408
-
409
408
  # support kwargs overwrite meta_data
410
409
  if len(kwargs) != 0:
411
410
  meta_data.update(kwargs)
412
411
 
413
- # headers
414
- if meta_data['headers'] is None:
415
- meta_data['headers'] = self.decide_postman_headers(impl, domain[0])
416
-
417
412
  # postman
418
413
  postman = Postmans.create(data=postman_conf)
419
414
 
@@ -424,7 +419,7 @@ class JmOption:
424
419
 
425
420
  client: AbstractJmClient = clazz(
426
421
  postman=postman,
427
- domain_list=domain,
422
+ domain_list=decide_domain_list(),
428
423
  retry_times=retry_times,
429
424
  )
430
425
 
@@ -459,20 +454,6 @@ class JmOption:
459
454
 
460
455
  ExceptionTool.raises(f'没有配置域名,且是无法识别的client类型: {client_key}')
461
456
 
462
- def decide_postman_headers(self, client_key, domain):
463
- is_client_type = lambda ctype: self.client_key_is_given_type(client_key, ctype)
464
-
465
- if is_client_type(JmApiClient):
466
- # 移动端
467
- # 不配置headers,由client每次请求前创建headers
468
- return None
469
-
470
- if is_client_type(JmHtmlClient):
471
- # 网页端
472
- return JmModuleConfig.new_html_headers(domain)
473
-
474
- ExceptionTool.raises(f'没有配置域名,且是无法识别的client类型: {client_key}')
475
-
476
457
  @classmethod
477
458
  def client_key_is_given_type(cls, client_key, ctype: Type[JmcomicClient]):
478
459
  if client_key == ctype.client_key:
jmcomic/jm_plugin.py CHANGED
@@ -208,7 +208,7 @@ class FindUpdatePlugin(JmOptionPlugin):
208
208
  return photo_ls
209
209
 
210
210
  class FindUpdateDownloader(JmDownloader):
211
- def filter_iter_objs(self, detail):
211
+ def do_filter(self, detail):
212
212
  if not detail.is_album():
213
213
  return detail
214
214
 
jmcomic/jm_toolkit.py CHANGED
@@ -55,6 +55,9 @@ class JmcomicText:
55
55
  # 評論(div)
56
56
  pattern_html_album_comment_count = compile(r'<div class="badge"[^>]*?id="total_video_comments">(\d+)</div>'), 0
57
57
 
58
+ # 提取接口返回值信息
59
+ pattern_ajax_favorite_msg = compile(r'</button>(.*?)</div>')
60
+
58
61
  @classmethod
59
62
  def parse_to_jm_domain(cls, text: str):
60
63
  if text.startswith(JmModuleConfig.PROT):
@@ -308,7 +311,7 @@ class PatternTool:
308
311
  def require_match(cls, html: str, pattern: Pattern, msg, rindex=1):
309
312
  match = pattern.search(html)
310
313
  if match is not None:
311
- return match[rindex]
314
+ return match[rindex] if rindex is not None else match
312
315
 
313
316
  ExceptionTool.raises_regex(
314
317
  msg,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jmcomic
3
- Version: 2.4.6
3
+ Version: 2.4.7
4
4
  Summary: Python API For JMComic (禁漫天堂)
5
5
  Home-page: https://github.com/hect0x7/JMComic-Crawler-Python
6
6
  Author: hect0x7
@@ -0,0 +1,17 @@
1
+ jmcomic/__init__.py,sha256=BYuf4ruBex9ljlTlGN0xXdUcus_eKTXS7ZLOqkgKJXM,878
2
+ jmcomic/api.py,sha256=yukYd5NCYYxP8K2Gj72iXu7vg9PHgaOvakQzQxEOcO8,2518
3
+ jmcomic/cl.py,sha256=PBSh0JndNFZw3B7WJPj5Y8SeFdKzHE00jIwYo9An-K0,3475
4
+ jmcomic/jm_client_impl.py,sha256=uG4LIZZdz6zAePkgTq80n5pNV-G069cXiSgBRg_dAO8,34106
5
+ jmcomic/jm_client_interface.py,sha256=xaPtHxdzGYmzsnRfq-fkH__hiARNUtxtjtEzD-SwbPg,14120
6
+ jmcomic/jm_config.py,sha256=88YEZyzxBWJcKmbS6sYhfQ4ZoO6kb7ghMYOgUYBfuWg,13110
7
+ jmcomic/jm_downloader.py,sha256=E1M9CS9bYEHWe8SEsdaq_0c3zxQghpkN_4QLZiZ-o1g,7324
8
+ jmcomic/jm_entity.py,sha256=u5aJhIt2Q21re6moXfS0drVBmIJKjNQnRI2lVvbZ-nY,18671
9
+ jmcomic/jm_option.py,sha256=-_Obz2m_roZOAkb1hw62TKDeKIy_iow99z65fXdvX7I,19945
10
+ jmcomic/jm_plugin.py,sha256=ftL0iZbc1GWk75n6ZuP1j-7MaOTqK1mQA04E-rkNEPs,16198
11
+ jmcomic/jm_toolkit.py,sha256=I67hbdHBLVsmi8RFanKy2sOIaMDU5GlOzi7AxfK_8vA,28892
12
+ jmcomic-2.4.7.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
13
+ jmcomic-2.4.7.dist-info/METADATA,sha256=fqfirQgCGD85-12Vhf5hSo71eG3A3DSSSOjzzbi96Nc,5470
14
+ jmcomic-2.4.7.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
15
+ jmcomic-2.4.7.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
16
+ jmcomic-2.4.7.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
17
+ jmcomic-2.4.7.dist-info/RECORD,,
@@ -1,17 +0,0 @@
1
- jmcomic/__init__.py,sha256=Nt5kEmfeZBoVkg2wCrGNHoXCaB0PFmZMHZyiEg1rqsY,878
2
- jmcomic/api.py,sha256=yukYd5NCYYxP8K2Gj72iXu7vg9PHgaOvakQzQxEOcO8,2518
3
- jmcomic/cl.py,sha256=PBSh0JndNFZw3B7WJPj5Y8SeFdKzHE00jIwYo9An-K0,3475
4
- jmcomic/jm_client_impl.py,sha256=SoblBkIaXI-TVeQCpNmovgvlN9sknjV0xD_svN5vH8s,32067
5
- jmcomic/jm_client_interface.py,sha256=PaMxxsJvxtUkpq7pRavftMlas3gfC6BQ0ZnFaYiUarU,13886
6
- jmcomic/jm_config.py,sha256=SJmkJTeQe7PvNbZyq-D3HBHWuNTULcJH0p_jTCka8QI,12735
7
- jmcomic/jm_downloader.py,sha256=GjC3JU8-UPvnKd_XlAoW0X-Wt2zGaU5K2bm3PE5R3as,7000
8
- jmcomic/jm_entity.py,sha256=zHI5N3MPA93fbdq3Lv94NVYZOx9mEwjsxshvh-w90jQ,18565
9
- jmcomic/jm_option.py,sha256=l6YtLqL6Q90o5kI18Cmt5kGbfg9tl-pvFXcowDkc6dg,21070
10
- jmcomic/jm_plugin.py,sha256=Z-cVc9H3s0Pj91I5ngjx-LdeX2PqYYloOcvogXs4glc,16205
11
- jmcomic/jm_toolkit.py,sha256=TrddmLTH44iiHv9nwe0l7y14vAs23tDO2QfE6BkLSfc,28759
12
- jmcomic-2.4.6.dist-info/LICENSE,sha256=kz4coTxZxuGxisK3W00tjK57Zh3RcMGq-EnbXrK7-xA,1064
13
- jmcomic-2.4.6.dist-info/METADATA,sha256=NrHLNgvjgafu3geU7DXY9wFZ-a6W5eJfIJHoAXSKVyg,5470
14
- jmcomic-2.4.6.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
15
- jmcomic-2.4.6.dist-info/entry_points.txt,sha256=tRbQltaGSBjejI0c9jYt-4SXQMd5nSDHcMvHmuTy4ow,44
16
- jmcomic-2.4.6.dist-info/top_level.txt,sha256=puvVMFYJqIbd6NOTMEvOyugMTT8woBfSQyxEBan3zY4,8
17
- jmcomic-2.4.6.dist-info/RECORD,,