mirror of
https://github.com/truewhile/MeBox.git
synced 2026-09-29 19:36:36 +08:00
125 lines
3.9 KiB
Go
125 lines
3.9 KiB
Go
package service
|
|
|
|
import (
|
|
"sort"
|
|
|
|
"github.com/ShukeBta/MediaStationGo/internal/model"
|
|
)
|
|
|
|
func selectPreparedSubscriptionCandidates(candidates []siteSearchCandidate, sub *model.Subscription, local LocalAvailability) []siteSearchCandidate {
|
|
return selectPreparedSubscriptionCandidatesWithStats(candidates, sub, local, nil)
|
|
}
|
|
|
|
func selectPreparedSubscriptionCandidatesWithStats(candidates []siteSearchCandidate, sub *model.Subscription, local LocalAvailability, stats *siteSearchSelectionStats) []siteSearchCandidate {
|
|
if len(candidates) > 1 {
|
|
sort.SliceStable(candidates, func(i, j int) bool {
|
|
if candidates[i].Score != candidates[j].Score {
|
|
return candidates[i].Score > candidates[j].Score
|
|
}
|
|
if candidates[i].Item.Seeders != candidates[j].Item.Seeders {
|
|
return candidates[i].Item.Seeders > candidates[j].Item.Seeders
|
|
}
|
|
return candidates[i].Item.Size > candidates[j].Item.Size
|
|
})
|
|
}
|
|
if len(candidates) == 0 {
|
|
return recordPreparedSelection(nil, stats)
|
|
}
|
|
|
|
mediaType := normalizeMediaType(sub.MediaType, sub.Name+" "+sub.Filter, "")
|
|
if !isSubscriptionSeriesType(mediaType) {
|
|
// 非洗版订阅成功下载一次即满足,媒体库/下载中已存在则不再重复下载。
|
|
if (sub == nil || !sub.WashEnabled) && local.LocalMediaCount > 0 {
|
|
if stats != nil {
|
|
stats.LocalAlreadySatisfied = true
|
|
}
|
|
return recordPreparedSelection(nil, stats)
|
|
}
|
|
return recordPreparedSelection(candidates[:1], stats)
|
|
}
|
|
|
|
if local.HasSeriesPack {
|
|
if stats != nil {
|
|
stats.LocalSeriesPackPresent = true
|
|
}
|
|
return recordPreparedSelection(nil, stats)
|
|
}
|
|
if local.LocalMediaCount > 0 {
|
|
if local.TotalEpisodes > 0 && len(local.MissingEpisodes) == 0 {
|
|
if stats != nil {
|
|
stats.SeriesComplete = true
|
|
}
|
|
return recordPreparedSelection(nil, stats)
|
|
}
|
|
missingSet := missingEpisodeSet(local)
|
|
onlyMissing := make([]siteSearchCandidate, 0, len(candidates))
|
|
var packFallback *siteSearchCandidate
|
|
for i := range candidates {
|
|
candidate := candidates[i]
|
|
if candidate.Episode <= 0 {
|
|
// 整季/全集包(无单集号)。剧集完结后站点常只挂全集包,
|
|
// 这里记下来作兜底:当单集候选不足以补齐缺失集时启用,
|
|
// 否则"补全缺失集"在站点只有全集包时永远匹配为空。
|
|
if stats != nil {
|
|
stats.NoEpisodeSkipped++
|
|
}
|
|
if candidate.Pack && packFallback == nil {
|
|
packFallback = &candidates[i]
|
|
if stats != nil {
|
|
stats.PackFallbackAvailable = true
|
|
}
|
|
}
|
|
continue
|
|
}
|
|
season := candidate.Season
|
|
if season <= 0 {
|
|
season = 1
|
|
}
|
|
if _, exists := local.ExistingEpisodeKeys[episodeKey(season, candidate.Episode)]; exists {
|
|
if stats != nil {
|
|
stats.ExistingEpisodeSkipped++
|
|
}
|
|
continue
|
|
}
|
|
if local.TotalEpisodes > 0 {
|
|
if _, missing := missingSet[candidate.Episode]; !missing {
|
|
if stats != nil {
|
|
stats.NotMissingEpisodeSkipped++
|
|
}
|
|
continue
|
|
}
|
|
}
|
|
onlyMissing = append(onlyMissing, candidate)
|
|
}
|
|
selected := sortedEpisodeCandidates(onlyMissing)
|
|
if len(selected) == 0 && packFallback != nil {
|
|
// 没有可用的单集候选,但站点有整季/全集包 → 用包兜底补缺集。
|
|
// 代价是会重下已有集,但用户主动触发补全时这是可接受的。
|
|
if stats != nil {
|
|
stats.PackFallbackUsed = true
|
|
}
|
|
return recordPreparedSelection([]siteSearchCandidate{*packFallback}, stats)
|
|
}
|
|
return recordPreparedSelection(selected, stats)
|
|
}
|
|
|
|
for _, candidate := range candidates {
|
|
if candidate.Pack {
|
|
return recordPreparedSelection([]siteSearchCandidate{candidate}, stats)
|
|
}
|
|
}
|
|
|
|
selected := sortedEpisodeCandidates(candidates)
|
|
if len(selected) == 0 {
|
|
return recordPreparedSelection(candidates[:1], stats)
|
|
}
|
|
return recordPreparedSelection(selected, stats)
|
|
}
|
|
|
|
func recordPreparedSelection(candidates []siteSearchCandidate, stats *siteSearchSelectionStats) []siteSearchCandidate {
|
|
if stats != nil {
|
|
stats.Selected = len(candidates)
|
|
}
|
|
return candidates
|
|
}
|