22
33from .jm_downloader import *
44
5- __DOWNLOAD_API_RET = Tuple [ JmAlbumDetail , JmDownloader ]
5+ __DOWNLOAD_API_RET = DownloadResult
66
77
88def download_batch (download_api ,
99 jm_id_iter : Union [Iterable , Generator ],
1010 option = None ,
1111 downloader = None ,
1212 ** kwargs ,
13- ) -> Set [ __DOWNLOAD_API_RET ] :
13+ ) -> BatchResult :
1414 """
1515 批量下载 album / photo
1616
17- 一个album/photo,对应一个线程,对应一个option
17+ 一个album/photo,对应一个线程,对应一个option。
18+ 返回 BatchResult(set),支持 for album, dler in result 遍历。
19+ 失败项收集在 result.failed 中,不会静默丢失。
1820
1921 :param download_api: 下载api
2022 :param jm_id_iter: jmid (album_id, photo_id) 的迭代器
@@ -26,22 +28,23 @@ def download_batch(download_api,
2628 if option is None :
2729 option = JmModuleConfig .option_class ().default ()
2830
29- result = set ()
31+ result = BatchResult ()
3032
31- def callback (* ret ):
32- result .add (ret )
33+ def _safe_download (aid ):
34+ """batch 内部的单任务包装:确保异常被收集而非静默丢失"""
35+ try :
36+ ret = download_api (aid , option , downloader , ** kwargs )
37+ result .add (ret )
38+ except Exception as e :
39+ jm_log ('batch.failed' , f'批量下载失败: [{ aid } ], 异常: [{ e } ]' , e )
40+ result .failed [str (aid )] = e
3341
3442 multi_thread_launcher (
3543 iter_objs = set (
3644 JmcomicText .parse_to_jm_id (jmid )
3745 for jmid in jm_id_iter
3846 ),
39- apply_each_obj_func = lambda aid : download_api (aid ,
40- option ,
41- downloader ,
42- callback = callback ,
43- ** kwargs ,
44- ),
47+ apply_each_obj_func = _safe_download ,
4548 wait_finish = True
4649 )
4750
@@ -81,7 +84,7 @@ def download_album(jm_album_id,
8184 callback (album , dler )
8285 if check_exception :
8386 dler .raise_if_has_exception ()
84- return album , dler
87+ return DownloadResult ( album , dler )
8588
8689
8790def download_photo (jm_photo_id ,
@@ -106,7 +109,7 @@ def download_photo(jm_photo_id,
106109 callback (photo , dler )
107110 if check_exception :
108111 dler .raise_if_has_exception ()
109- return photo , dler
112+ return DownloadResult ( photo , dler )
110113
111114
112115def new_downloader (option = None , downloader = None ) -> JmDownloader :
@@ -183,7 +186,7 @@ async def download_album_async(jm_album_id,
183186 if check_exception :
184187 dler .raise_if_has_exception ()
185188
186- return album , dler
189+ return DownloadResult ( album , dler )
187190
188191
189192async def download_photo_async (jm_photo_id ,
@@ -213,18 +216,19 @@ async def download_photo_async(jm_photo_id,
213216 if check_exception :
214217 dler .raise_if_has_exception ()
215218
216- return photo , dler
219+ return DownloadResult ( photo , dler )
217220
218221
219222async def download_batch_async (download_api ,
220223 jm_id_iter ,
221224 option = None ,
222225 downloader = None ,
223226 ** kwargs ,
224- ):
227+ ) -> BatchResult :
225228 """
226229 异步批量下载 album / photo。
227230 - 容错机制:单个 album/photo 失败不会中止整批,也不会丢失其它已完成结果。
231+ - 返回 BatchResult(set),失败项收集在 result.failed 中。
228232 """
229233 if option is None :
230234 option = JmModuleConfig .option_class ().default ()
@@ -236,12 +240,13 @@ async def download_batch_async(download_api,
236240 return_exceptions = True ,
237241 )
238242
239- # 失败不抛出,但要记录,便于排查
240- result_set = set ()
243+ # 失败不抛出,但要记录到 result.failed,便于调用者排查
244+ result = BatchResult ()
241245 for jmid , r in zip (jm_ids , results ):
242246 if isinstance (r , BaseException ):
243247 jm_log ('async.batch.failed' , f'批量下载失败: [{ jmid } ], 异常: [{ r } ]' , r )
248+ result .failed [str (jmid )] = r
244249 else :
245- result_set .add (r )
250+ result .add (r )
246251
247- return result_set
252+ return result
0 commit comments