fix(subscribe): stop best-version per-episode redownload loop (#5781)

This commit is contained in:
InfinityPacer
2026-05-18 06:56:29 +08:00
committed by GitHub
parent 6685bd0e0e
commit 23d6ba0466
5 changed files with 201 additions and 19 deletions
+25 -3
View File
@@ -511,6 +511,20 @@ class DownloadChain(ChainBase):
return 9999
return no_exist[season].total_episode
def __apply_allowed_episodes(_need_episodes, _context: Context) -> Set[int]:
"""
根据候选携带的允许集裁剪 need_episodes,返回真正可下载的剧集集合。
语义:allowed_episodes 为 None 表示调用方未约束,沿用 need_episodes
非空集合则与 need_episodes 取交集;空集合(显式拒绝)会被交集自然消解为空。
调用方根据返回集合是否为空决定是否跳过当前候选。
"""
effective = set(_need_episodes)
allowed = _context.allowed_episodes
if allowed is not None:
effective &= set(allowed)
return effective
# 发送资源选择事件,允许外部修改上下文数据
logger.debug(f"Initial contexts: {len(contexts)} items, Downloader: {downloader}")
event_data = ResourceSelectionEventData(
@@ -695,8 +709,12 @@ class DownloadChain(ChainBase):
# 整季的不处理
if not torrent_episodes:
continue
# 上游对本候选施加的允许集(如洗版按集允许列表)裁剪本季缺集,得到真正可下载范围。
effective_need = __apply_allowed_episodes(need_episodes, context)
if not effective_need:
continue
# 为需要集的子集则下载
if torrent_episodes.issubset(set(need_episodes)):
if torrent_episodes.issubset(effective_need):
# 下载
logger.info(f"开始下载 {meta.title} ...")
download_id = self.download_single(context, save_path=save_path,
@@ -756,10 +774,14 @@ class DownloadChain(ChainBase):
# 没有需要集后退出
if not need_episodes:
break
# 上游对本候选施加的允许集(如洗版按集允许列表)裁剪本季缺集,得到真正可下载范围。
effective_need = __apply_allowed_episodes(need_episodes, context)
if not effective_need:
continue
# 选中一个单季整季的或单季包括需要的所有集的
if (media.tmdb_id == need_mid or media.douban_id == need_mid) \
and (not meta.episode_list
or set(meta.episode_list).intersection(set(need_episodes))) \
or set(meta.episode_list).intersection(effective_need)) \
and len(meta.season_list) == 1 \
and meta.season_list[0] == need_season:
# 检查种子看是否有需要的集
@@ -775,7 +797,7 @@ class DownloadChain(ChainBase):
torrent_episodes = TorrentHelper().get_torrent_episodes(torrent_files)
logger.info(f"{torrent.site_name} - {meta.org_string} 解析种子文件集数:{torrent_episodes}")
# 选中的集
selected_episodes = set(torrent_episodes).intersection(set(need_episodes))
selected_episodes = set(torrent_episodes).intersection(effective_need)
if not selected_episodes:
logger.info(f"{torrent.site_name} - {torrent.title} 没有需要的集,跳过...")
continue
+18 -14
View File
@@ -1027,17 +1027,19 @@ class SubscribeChain(ChainBase):
)
continue
# 洗版时,只保留至少能提升一集优先级的资源
if (
torrent_mediainfo.type == MediaType.TV
and not self.__get_best_version_interested_episodes(
if torrent_mediainfo.type == MediaType.TV:
interested_episodes = self.__get_best_version_interested_episodes(
subscribe=subscribe,
context=context,
priority=torrent_info.pri_order,
)
):
logger.info(
f'{subscribe.name} 正在洗版,{torrent_info.title} 不包含可提升优先级的剧集')
continue
if not interested_episodes:
logger.info(
f'{subscribe.name} 正在洗版,{torrent_info.title} 不包含可提升优先级的剧集')
continue
# 将"本候选实际能升级到的集"作为允许下载集合下传到下载层,
# 防止标题元数据与实际种子文件错位导致同优先级集被重复下载。
context.allowed_episodes = set(interested_episodes)
if (
torrent_mediainfo.type != MediaType.TV
and subscribe.current_priority
@@ -1554,17 +1556,19 @@ class SubscribeChain(ChainBase):
# 洗版时,优先级小于已下载优先级的不要
if subscribe.best_version:
if (
meta.type == MediaType.TV
and not self.__get_best_version_interested_episodes(
if meta.type == MediaType.TV:
interested_episodes = self.__get_best_version_interested_episodes(
subscribe=subscribe,
context=_context,
priority=torrent_info.pri_order,
)
):
logger.info(
f'{subscribe.name} 正在洗版,{torrent_info.title} 不包含可提升优先级的剧集')
continue
if not interested_episodes:
logger.info(
f'{subscribe.name} 正在洗版,{torrent_info.title} 不包含可提升优先级的剧集')
continue
# 与 search() 路径对称:把"本候选实际能升级到的集"作为允许下载集合下传到下载层,
# 避免 RSS / 订阅刷新场景下标题元数据与种子文件错位导致同优先级集重复下载。
_context.allowed_episodes = set(interested_episodes)
if (
meta.type != MediaType.TV
and subscribe.current_priority