diff --git a/README.md b/README.md index a9353042..910323e0 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,26 @@ 本项目的核心功能是下载本子,基于此,设计了一套方便使用、便于扩展,能满足一些特殊下载需求的框架。 -除了下载功能以外,也实现了其他的一些禁漫接口,例如登录、搜索、收藏夹、分类、排行榜等等,按需实现。 +目前核心功能实现较为稳定,项目也处于维护阶段。 -目前核心功能实现较为稳定,项目也处于维护阶段(因为禁漫接口经常变动,需要经常维护)。 +除了下载功能以外,也实现了其他的一些禁漫接口,按需实现,具体如下。 + +### 已实现的禁漫API: + +- 登录 +- 搜本 +- 分类 (排行榜) +- 本子章节详情 +- 图片下载解码 +- 收藏夹 +- 移动端接口加解密 ## 安装教程 * 通过pip官方源安装(推荐,并且更新也是这个命令) ```shell - pip install jmcomic -i https://pypi.org/project --upgrade + pip install jmcomic -i https://pypi.org/project -U ``` * 通过源代码安装 @@ -47,6 +57,21 @@ jmcomic.download_album('422866') # 传入要下载的album的id,即可下载 $ jmcomic 422866 ``` +## 进阶使用 + +文档网站:[jmcomic.readthedocs.io](https://jmcomic.readthedocs.io/en/latest) + +进阶使用可以参考:[jmcomic常用类和方法演示](assets/docs/sources/tutorial/0_demo.md) + +下面列出的是一些常用的文档: + +* [jmcomic常用类和方法演示](assets/docs/sources/tutorial/0_demo.md) +* [option配置文件语法(包含插件配置)](./assets/docs/sources/option_file_syntax.md) +* [GitHub Actions使用教程](./assets/docs/sources/tutorial/1_github_actions.md) +* [命令行使用教程](assets/docs/sources/tutorial/2_command_line.md) +* [插件机制](assets/docs/sources/tutorial/6_plugin.md) +* [下载过滤器机制](assets/docs/sources/tutorial/5_filter.md) + ## 项目特点 - **绕过Cloudflare的反爬虫** @@ -83,19 +108,6 @@ $ jmcomic 422866 - `jpg图片合成为一个pdf插件` - `导出收藏夹为csv文件插件` -## 进阶使用 - -进阶使用请查阅文档:[文档](https://jmcomic.readthedocs.io/en/latest) - -下面列出一些常用的文档链接: - -* [option配置文件语法(包含插件配置)](./assets/docs/sources/option_file_syntax.md) -* [常用类和方法演示(下载本子、获取实体类、搜索本子)](assets/docs/sources/tutorial/3_demo.md) -* [命令行使用教程](assets/docs/sources/tutorial/2_command_line.md) -* [GitHub Actions使用教程](./assets/docs/sources/tutorial/1_github_actions.md) -* [插件机制](assets/docs/sources/tutorial/6_plugin.md) -* [下载过滤器机制](assets/docs/sources/tutorial/5_filter.md) - ## 使用小说明 * Python >= 3.7 @@ -103,10 +115,11 @@ $ jmcomic 422866 ## 项目文件夹介绍 +* .github:GitHub Actions配置文件 * assets:存放一些非代码的资源文件 - * config:存放配置文件 * docs:项目文档 + * option:存放配置文件 * src:存放源代码 diff --git a/assets/docs/sources/option_file_syntax.md b/assets/docs/sources/option_file_syntax.md index 66124426..568fe02c 100644 --- a/assets/docs/sources/option_file_syntax.md +++ b/assets/docs/sources/option_file_syntax.md @@ -90,10 +90,13 @@ dir_rule: # 本项只建议了解编程的朋友定制,实现在这个类: jmcomic.jm_option.DirRule # 写法: # 1. 以'Bd'开头,表示根目录 - # 2. 文件夹每增加一层,使用'_'区隔 - # 3. 文件夹名字表示为 Pxxx/Ayyy,意思是 JmPhotoDetail.xxx / JmAlbumDetail的.yyy。xxx和yyy可以写什么需要看源码。 - # 下面是示例,表示使用禁漫网站的默认下载方式 [根目录 / 本子id / 章节序号 / 图片文件] - # rule: Bd_Aid_Pindex + # 2. 文件夹每增加一层,使用 '_' 或者 '/' 区隔 + # 3. 用Pxxx或者Ayyy指代文件夹名,意思是 JmPhotoDetail.xxx / JmAlbumDetail的.yyy。xxx和yyy可以写什么需要看源码。 + # + # 下面演示如果要使用禁漫网站的默认下载方式,该怎么写: + # 规则: 根目录 / 本子id / 章节序号 / 图片文件 + # rule: 'Bd / Aid / Pindex' + # rule: 'Bd_Aid_Pindex' # 默认规则是: 根目录 / 章节标题 / 图片文件 rule: Bd_Ptitle diff --git a/assets/docs/sources/tutorial/0_demo.md b/assets/docs/sources/tutorial/0_demo.md new file mode 100644 index 00000000..ff09e484 --- /dev/null +++ b/assets/docs/sources/tutorial/0_demo.md @@ -0,0 +1,189 @@ +# jmcomic 常用类和方法演示 + +## 下载本子/章节 + +```python +from jmcomic import * + +# 下载id为438696的本子 (https://18comic.vip/album/438696) +download_album(438696) + +# 下载章节 (https://18comic.vip/photo/438696) +download_photo(438696) + +# 同时下载多个本子 +download_album([123, 456, 789]) +``` + +## 使用option定制化下载本子 + +如果你在下载本子时有一些定制化需求, + +例如指定禁漫域名,使用代理,登录禁漫,图片格式转换等等, + +那么,你可以试试看jmcomic提供的option机制 + +```python +from jmcomic import * + +# 1. 在调用下载api前,通过创建和使用option对象,可以定制化下载行为。 +# 推荐使用配置文件的方式来创建option对象, +# 你可以配置很多东西,比如代理、cookies、下载规则等等。 +# 配置文件的语法参考: https://jmcomic.readthedocs.io/en/latest/option_file_syntax/ +option = create_option_by_file('op.yml') # 通过配置文件来创建option对象 + +# 2. 调用下载api,把option作为参数传递 +download_album(123, option) +# 也可以使用下面这种面向对象的方式,是一样的 +option.download_album(123) +``` + +## 获取本子/章节/图片的实体类 + +```python +from jmcomic import * + +# 客户端 +client = JmOption.default().new_jm_client() + +# 本子实体类 +album: JmAlbumDetail = client.get_album_detail('427413') + + +def fetch(photo: JmPhotoDetail): + # 章节实体类 + photo = client.get_photo_detail(photo.photo_id, False) + + # 图片实体类 + image: JmImageDetail + for image in photo: + print(image.img_url) + + +# 多线程发起请求 +multi_thread_launcher( + iter_objs=album, + apply_each_obj_func=fetch +) +``` + +## 搜索本子 + +```python +from jmcomic import * + +client = JmOption.default().new_jm_client() + +# 分页查询,search_site就是禁漫网页上的【站内搜索】 +page: JmSearchPage = client.search_site(search_query='+MANA +无修正', page=1) +# page默认的迭代方式是page.iter_id_title(),每次迭代返回 albun_id, title +for album_id, title in page: + print(f'[{album_id}]: {title}') + +# 直接搜索禁漫车号 +page = client.search_site(search_query='427413') +album: JmAlbumDetail = page.single_album +print(album.tags) +``` + +## 搜索并下载本子 + +```python +from jmcomic import * + +option = JmOption.default() +client = option.new_jm_client() + +tag = '無修正' +# 搜索标签,可以使用search_tag。 +# 搜索第一页。 +page: JmSearchPage = client.search_tag(tag, page=1) + +aid_list = [] + +for aid, atitle, tag_list in page.iter_id_title_tag(): # 使用page的iter_id_title_tag迭代器 + if tag in tag_list: + print(f'[标签/{tag}] 发现目标: [{aid}]: [{atitle}]') + aid_list.append(aid) + +download_album(aid_list, option) +``` + +## 分类 / 排行榜 + +禁漫的分类是一个和搜索有些类似的功能。 + +搜索是按某一条件进行过滤。 + +分类没有过滤,就是把某一类别(category)下的本子全都调出来。 + +禁漫的排行榜就是分类的一种形式 + +下面演示调用分类api + +```python +from jmcomic import * + +# 创建客户端 +op = JmOption.default() +cl = op.new_jm_client() + +# 调用分类接口 +# 根据下面的参数,这个调用的意义就是: +# 在全部分类下,选择所有时间范围,按观看数排序后,获取第一页的本子 +page: JmCategoryPage = cl.categories_filter( + page=1, + time=JmMagicConstants.TIME_ALL, # 时间选择全部,具体可以写什么请见JmMagicConstants + category=JmMagicConstants.CATEGORY_ALL, # 分类选择全部,具体可以写什么请见JmMagicConstants + order_by=JmMagicConstants.ORDER_BY_LATEST, # 按照观看数排序,具体可以写什么请见JmMagicConstants +) + +# 月排行,底层实现也是调的categories_filter +page: JmCategoryPage = cl.month_ranking(1) +# 周排行 +page: JmCategoryPage = cl.week_ranking(1) + +# 循环获取分页,使用 cl.categories_filter_gen +for page in cl.categories_filter_gen(1, # 起始页码 + # 下面是分类参数 + JmMagicConstants.TIME_WEEK, + JmMagicConstants.CATEGORY_ALL, + JmMagicConstants.ORDER_BY_VIEW, + ): + for aid, atitle in page: + print(aid, atitle) + +``` + +## 手动创建Client + +```python +# 默认的使用方式是先创建option,option封装了所有配置,然后由option.new_jm_client() 创建客户端client,使用client可以访问禁漫接口 + +# 下面演示直接构造client的方式 +from jmcomic import * + +""" +创建JM客户端 + +:param postman: 负责实现HTTP请求的对象,持有cookies、headers、proxies等信息 +:param domain_list: 禁漫域名 +:param retry_times: 重试次数 +""" + +# 网页端 +cl = JmHtmlClient( + postman=JmModuleConfig.new_postman(), + domain_list=['18comic.vip'], + retry_times=1 +) + +# API端(APP) +cl = JmApiClient( + postman=JmModuleConfig.new_postman(), + domain_list=JmModuleConfig.DOMAIN_API_LIST, + retry_times=1 +) + + +``` diff --git a/assets/docs/sources/tutorial/3_demo.md b/assets/docs/sources/tutorial/3_demo.md deleted file mode 100644 index 92e60617..00000000 --- a/assets/docs/sources/tutorial/3_demo.md +++ /dev/null @@ -1,117 +0,0 @@ -# 使用jmcomic实现简单功能 - -## 下载本子 - -```python -from jmcomic import * - -ls = str_to_list(''' -438696 -https://18comic.vip/album/497896/ -''') - -download_album(ls) -``` - -## 获取实体类 - -```python -from jmcomic import * - -# 客户端 -client = JmOption.default().new_jm_client() - -# 本子实体类 -album: JmAlbumDetail = client.get_album_detail('427413') - - -def fetch(photo: JmPhotoDetail): - # 章节实体类 - photo = client.get_photo_detail(photo.photo_id, False) - - # 图片实体类 - image: JmImageDetail - for image in photo: - print(image.img_url) - -# 多线程发起请求 -multi_thread_launcher( - iter_objs=album, - apply_each_obj_func=fetch -) -``` - -## 搜索本子 - -```python -from jmcomic import * - -client = JmOption.default().new_jm_client() - -# 分页查询,search_site就是禁漫网页上的【站内搜索】 -page: JmSearchPage = client.search_site(search_query='+MANA +无修正', page=1) -# page默认的迭代方式是page.iter_id_title(),每次迭代返回 albun_id, title -for album_id, title in page: - print(f'[{album_id}]: {title}') - -# 直接搜索禁漫车号 -page = client.search_site(search_query='427413') -album: JmAlbumDetail = page.single_album -print(album.tags) -``` - -## 搜索并下载本子 - -```python -from jmcomic import * - -option = JmOption.default() -client = option.new_jm_client() - -tag = '無修正' -# 搜索标签,可以使用search_tag。 -# 搜索第一页。 -page: JmSearchPage = client.search_tag(tag, page=1) - -aid_list = [] - -for aid, atitle, tag_list in page.iter_id_title_tag(): # 使用page的iter_id_title_tag迭代器 - if tag in tag_list: - print(f'[标签/{tag}] 发现目标: [{aid}]: [{atitle}]') - aid_list.append(aid) - -download_album(aid_list, option) -``` - -## 手动创建Client - -```python -# 默认的使用方式是先创建option,option封装了所有配置,然后由option.new_jm_client() 创建客户端client,使用client可以访问禁漫接口 - -# 下面演示直接构造client的方式 -from jmcomic import * - -""" -创建JM客户端 - -:param postman: 负责实现HTTP请求的对象,持有cookies、headers、proxies等信息 -:param domain_list: 禁漫域名 -:param retry_times: 重试次数 -""" - -# 网页端 -cl = JmHtmlClient( - postman=JmModuleConfig.new_postman(), - domain_list=['18comic.vip'], - retry_times=1 -) - -# API端(APP) -cl = JmApiClient( - postman=JmModuleConfig.new_postman(), - domain_list=JmModuleConfig.DOMAIN_API_LIST, - retry_times=1 -) - - -``` diff --git a/assets/docs/sources/tutorial/8_pick_domain.md b/assets/docs/sources/tutorial/8_pick_domain.md index e703922c..0b8ab684 100644 --- a/assets/docs/sources/tutorial/8_pick_domain.md +++ b/assets/docs/sources/tutorial/8_pick_domain.md @@ -67,3 +67,15 @@ for domain, status in domain_status_dict.items(): ``` +# 程序输出示例 + +```text +获取到7个域名,开始测试 +18comic.vip: ok +18comic.org: ok +18comic-palworld.vip: ok +18comic-c.art: ok +jmcomic1.me: ok +jmcomic.me: ok +18comic-palworld.club: ok +``` \ No newline at end of file diff --git a/src/jmcomic/__init__.py b/src/jmcomic/__init__.py index ebf62ba7..db1b9f97 100644 --- a/src/jmcomic/__init__.py +++ b/src/jmcomic/__init__.py @@ -2,7 +2,7 @@ # 被依赖方 <--- 使用方 # config <--- entity <--- toolkit <--- client <--- option <--- downloader -__version__ = '2.5.6' +__version__ = '2.5.7' from .api import * from .jm_plugin import * diff --git a/src/jmcomic/api.py b/src/jmcomic/api.py index 34e826d3..c888b2a5 100644 --- a/src/jmcomic/api.py +++ b/src/jmcomic/api.py @@ -1,11 +1,12 @@ from .jm_downloader import * +__DOWNLOAD_API_RET = Tuple[JmAlbumDetail, JmDownloader] def download_batch(download_api, jm_id_iter: Union[Iterable, Generator], option=None, downloader=None, - ) -> Set[Tuple[JmAlbumDetail, JmDownloader]]: + ) -> Set[__DOWNLOAD_API_RET]: """ 批量下载 album / photo @@ -46,7 +47,7 @@ def download_album(jm_album_id, option=None, downloader=None, callback=None, - ): + ) -> Union[__DOWNLOAD_API_RET, Set[__DOWNLOAD_API_RET]]: """ 下载一个本子(album),包含其所有的章节(photo) diff --git a/src/jmcomic/jm_client_interface.py b/src/jmcomic/jm_client_interface.py index d3f64f2f..e9a0149b 100644 --- a/src/jmcomic/jm_client_interface.py +++ b/src/jmcomic/jm_client_interface.py @@ -6,8 +6,6 @@ """ -DictModel = AdvancedEasyAccessDict - class JmResp: @@ -87,11 +85,11 @@ class JmJsonResp(JmResp): def json(self) -> Dict: try: return self.resp.json() - except Exception: - ExceptionTool.raises_resp('json解析失败', self, JsonResolveFailException) + except Exception as e: + ExceptionTool.raises_resp(f'json解析失败: {e}', self, JsonResolveFailException) - def model(self) -> DictModel: - return DictModel(self.json()) + def model(self) -> AdvancedEasyAccessDict: + return AdvancedEasyAccessDict(self.json()) class JmApiResp(JmJsonResp): @@ -120,9 +118,9 @@ def res_data(self) -> Any: return loads(self.decoded_data) @property - def model_data(self) -> DictModel: + def model_data(self) -> AdvancedEasyAccessDict: self.require_success() - return DictModel(self.res_data) + return AdvancedEasyAccessDict(self.res_data) # album-comment diff --git a/src/jmcomic/jm_config.py b/src/jmcomic/jm_config.py index 479277ac..1cfe1fe9 100644 --- a/src/jmcomic/jm_config.py +++ b/src/jmcomic/jm_config.py @@ -2,8 +2,8 @@ def default_jm_logging(topic: str, msg: str): - from common import format_ts - print(f'{format_ts()}:【{topic}】{msg}') + from common import format_ts, current_thread + print('[{}] [{}]:【{}】{}'.format(format_ts(), current_thread().name, topic, msg)) # 禁漫常量 @@ -24,17 +24,18 @@ class JmMagicConstants: TIME_MONTH = 'm' TIME_ALL = 'a' - # 全部, 同人, 单本, 短篇, 其他, 韩漫, 美漫, cosplay, 3D - # category = ["0", "doujin", "single", "short", "another", "hanman", "meiman", "doujin_cosplay", "3D"] - CATEGORY_ALL = '0' - CATEGORY_DOUJIN = 'doujin' - CATEGORY_SINGLE = 'single' - CATEGORY_SHORT = 'short' - CATEGORY_ANOTHER = 'another' - CATEGORY_HANMAN = 'hanman' - CATEGORY_MEIMAN = 'meiman' - CATEGORY_DOUJIN_COSPLAY = 'doujin_cosplay' - CATEGORY_3D = '3D' + # 分类参数API接口的category + CATEGORY_ALL = '0' # 全部 + CATEGORY_DOUJIN = 'doujin' # 同人 + CATEGORY_SINGLE = 'single' # 单本 + CATEGORY_SHORT = 'short' # 短篇 + CATEGORY_ANOTHER = 'another' # 其他 + CATEGORY_HANMAN = 'hanman' # 韩漫 + CATEGORY_MEIMAN = 'meiman' # 美漫 + CATEGORY_DOUJIN_COSPLAY = 'doujin_cosplay' # cosplay + CATEGORY_3D = '3D' # 3D + CATEGORY_ENGLISH_SITE = 'english_site' # 英文站 + CATEGORY_JM_TEAM = '禁漫漢化組' # 分页大小 PAGE_SIZE_SEARCH = 80 @@ -52,10 +53,10 @@ class JmMagicConstants: APP_TOKEN_SECRET = '18comicAPP' APP_TOKEN_SECRET_2 = '18comicAPPContent' APP_DATA_SECRET = '185Hcomic3PAPP7R' - APP_VERSION = '1.6.6' + APP_VERSION = '1.6.7' APP_HEADERS_TEMPLATE = { 'Accept-Encoding': 'gzip', - 'user-agent': 'Mozilla/5.0 (Linux; Android 9; V1938CT Build/PQ3A.190705.09211555; wv) AppleWebKit/537.36 (KHTML, ' + 'user-agent': 'Mozilla/5.0 (Linux; Android 9; V1938CT Build/PQ3A.190705.11211812; wv) AppleWebKit/537.36 (KHTML, ' 'like Gecko) Version/4.0 Chrome/91.0.4472.114 Safari/537.36', } diff --git a/src/jmcomic/jm_downloader.py b/src/jmcomic/jm_downloader.py index 76fce3ee..7cbce784 100644 --- a/src/jmcomic/jm_downloader.py +++ b/src/jmcomic/jm_downloader.py @@ -50,8 +50,10 @@ class JmDownloader(DownloadCallback): def __init__(self, option: JmOption) -> None: self.option = option - # 收集所有下载的image,为plugin提供数据 - self.all_downloaded: Dict[JmAlbumDetail, Dict[JmPhotoDetail, List[Tuple[str, JmImageDetail]]]] = {} + # 下载成功的记录dict + self.download_success_dict: Dict[JmAlbumDetail, Dict[JmPhotoDetail, List[Tuple[str, JmImageDetail]]]] = {} + # 下载失败的记录list + self.download_failed_list: List[Tuple[JmImageDetail, BaseException]] = [] def download_album(self, album_id): client = self.client_for_album(album_id) @@ -101,11 +103,21 @@ def download_by_image_detail(self, image: JmImageDetail, client: JmcomicClient): if use_cache is True and image.is_exists: return - client.download_by_image_detail( - image, - img_save_path, - decode_image=decode_image, - ) + e = None + try: + client.download_by_image_detail( + image, + img_save_path, + decode_image=decode_image, + ) + except BaseException as e: + jm_log('image.failed', f'图片下载失败: [{image.download_url}], 异常: {e}') + # 保存失败记录 + self.download_failed_list.append((image, e)) + + if e is not None: + raise e + self.after_image(image, img_save_path) # noinspection PyMethodMayBeStatic @@ -164,11 +176,33 @@ def client_for_photo(self, jm_photo_id) -> JmcomicClient: """ return self.option.build_jm_client() + @property + def all_success(self) -> bool: + """ + 是否成功下载了全部图片 + + 该属性需要等到downloader的全部download_xxx方法完成后才有意义。 + + 注意!如果使用了filter机制,例如通过filter只下载3张图片,那么all_success也会为False + """ + if len(self.download_failed_list) != 0: + return False + + for album, photo_dict in self.download_success_dict.items(): + if len(album) != len(photo_dict): + return False + + for photo, image_list in photo_dict.items(): + if len(photo) != len(image_list): + return False + + return True + # 下面是回调方法 def before_album(self, album: JmAlbumDetail): super().before_album(album) - self.all_downloaded.setdefault(album, {}) + self.download_success_dict.setdefault(album, {}) self.option.call_all_plugin( 'before_album', album=album, @@ -185,8 +219,8 @@ def after_album(self, album: JmAlbumDetail): def before_photo(self, photo: JmPhotoDetail): super().before_photo(photo) - self.all_downloaded.setdefault(photo.from_album, {}) - self.all_downloaded[photo.from_album].setdefault(photo, []) + self.download_success_dict.setdefault(photo.from_album, {}) + self.download_success_dict[photo.from_album].setdefault(photo, []) self.option.call_all_plugin( 'before_photo', photo=photo, @@ -214,7 +248,7 @@ def after_image(self, image: JmImageDetail, img_save_path): photo = image.from_photo album = photo.from_album - self.all_downloaded.get(album).get(photo).append((img_save_path, image)) + self.download_success_dict.get(album).get(photo).append((img_save_path, image)) self.option.call_all_plugin( 'after_image', image=image, diff --git a/src/jmcomic/jm_option.py b/src/jmcomic/jm_option.py index 80bcf281..d2457e13 100644 --- a/src/jmcomic/jm_option.py +++ b/src/jmcomic/jm_option.py @@ -105,13 +105,11 @@ def get_role_solver_list(self, rule_dsl: str, base_dir: str) -> RuleSolverList: 解析下载路径dsl,得到一个路径规则解析列表 """ - if '_' not in rule_dsl and rule_dsl != 'Bd': - ExceptionTool.raises(f'不支持的dsl: "{rule_dsl}"') - - rule_list = rule_dsl.split('_') + rule_list = self.split_rule_dsl(rule_dsl) solver_ls: List[DirRule.RuleSolver] = [] for rule in rule_list: + rule = rule.strip() if rule == 'Bd': solver_ls.append((0, lambda _: base_dir, 'Bd')) continue @@ -124,6 +122,19 @@ def get_role_solver_list(self, rule_dsl: str, base_dir: str) -> RuleSolverList: return solver_ls + # noinspection PyMethodMayBeStatic + def split_rule_dsl(self, rule_dsl: str) -> List[str]: + if rule_dsl == 'Bd': + return [rule_dsl] + + if '/' in rule_dsl: + return rule_dsl.split('/') + + if '_' in rule_dsl: + return rule_dsl.split('_') + + ExceptionTool.raises(f'不支持的rule配置: "{rule_dsl}"') + @classmethod def get_rule_solver(cls, rule: str) -> Optional[RuleSolver]: # 查找缓存 @@ -181,6 +192,7 @@ def __init__(self, client: Dict, plugins: Dict, filepath=None, + call_after_init_plugin=True, ): # 路径规则配置 self.dir_rule = DirRule(**dir_rule) @@ -196,7 +208,21 @@ def __init__(self, # 需要主线程等待完成的插件 self.need_wait_plugins = [] - self.call_all_plugin('after_init', safe=True) + if call_after_init_plugin: + self.call_all_plugin('after_init', safe=True) + + def copy_option(self): + return self.__class__( + dir_rule={ + 'rule': self.dir_rule.rule_dsl, + 'base_dir': self.dir_rule.base_dir, + }, + download=self.download.src_dict, + client=self.client.src_dict, + plugins=self.plugins.src_dict, + filepath=self.filepath, + call_after_init_plugin=False + ) """ 下面是decide系列方法,为了支持重写和增加程序动态性。 diff --git a/src/jmcomic/jm_plugin.py b/src/jmcomic/jm_plugin.py index f1814199..4d1c49fe 100644 --- a/src/jmcomic/jm_plugin.py +++ b/src/jmcomic/jm_plugin.py @@ -298,7 +298,7 @@ def invoke(self, # 原文件夹 -> zip文件 dir_zip_dict: Dict[str, Optional[str]] = {} - photo_dict = downloader.all_downloaded[album] + photo_dict = downloader.download_success_dict[album] if level == 'album': zip_path = self.get_zip_path(album, None, filename_rule, suffix, zip_dir) @@ -383,7 +383,7 @@ def after_zip(self, dir_zip_dict: Dict[str, Optional[str]]): dirs = sorted(dir_zip_dict.keys(), reverse=True) image_paths = [ path - for photo_dict in self.downloader.all_downloaded.values() + for photo_dict in self.downloader.download_success_dict.values() for image_list in photo_dict.values() for path, image in image_list ] @@ -752,7 +752,7 @@ def generate_cmd(): paths = [ path - for path, image in downloader.all_downloaded[photo.from_album][photo] + for path, image in downloader.download_success_dict[photo.from_album][photo] ] paths.append(self.option.decide_image_save_dir(photo, ensure_exists=False)) diff --git a/src/jmcomic/jm_toolkit.py b/src/jmcomic/jm_toolkit.py index 62c3c84c..849534a4 100644 --- a/src/jmcomic/jm_toolkit.py +++ b/src/jmcomic/jm_toolkit.py @@ -472,7 +472,7 @@ def parse_html_to_favorite_page(cls, html: str) -> JmFavoritePage: return JmFavoritePage(content, folder_list, total) @classmethod - def parse_api_to_search_page(cls, data: DictModel) -> JmSearchPage: + def parse_api_to_search_page(cls, data: AdvancedEasyAccessDict) -> JmSearchPage: """ model_data: { "search_query": "MANA", @@ -501,7 +501,7 @@ def parse_api_to_search_page(cls, data: DictModel) -> JmSearchPage: return JmSearchPage(content, total) @classmethod - def parse_api_to_favorite_page(cls, data: DictModel) -> JmFavoritePage: + def parse_api_to_favorite_page(cls, data: AdvancedEasyAccessDict) -> JmFavoritePage: """ { "list": [ @@ -546,7 +546,7 @@ def parse_api_to_favorite_page(cls, data: DictModel) -> JmFavoritePage: @classmethod def adapt_content(cls, content): - def adapt_item(item: DictModel): + def adapt_item(item: AdvancedEasyAccessDict): item: dict = item.src_dict item.setdefault('tags', []) return item @@ -673,7 +673,7 @@ def post_adapt_album(cls, data: dict, _clazz: type, fields: dict): series = data['series'] episode_list = [] for chapter in series: - chapter = DictModel(chapter) + chapter = AdvancedEasyAccessDict(chapter) # photo_id, photo_index, photo_title, photo_pub_date episode_list.append( (chapter.id, chapter.sort, chapter.name, None) @@ -688,7 +688,7 @@ def post_adapt_photo(cls, data: dict, _clazz: type, fields: dict): sort = 1 series: list = data['series'] # series中的sort从1开始 for chapter in series: - chapter = DictModel(chapter) + chapter = AdvancedEasyAccessDict(chapter) if int(chapter.id) == int(data['id']): sort = chapter.sort break