Files
MeBox/internal/service/subscription_candidate_defaults_test.go
T
2026-06-30 20:18:02 +08:00

300 lines
14 KiB
Go

package service
import (
"testing"
"github.com/ShukeBta/MediaStationGo/internal/model"
)
func TestSelectSiteSearchCandidatesRejectsKeywordOriginWithConflictingYear(t *testing.T) {
sub := &model.Subscription{
Name: "玩具总动员 5 自动订阅",
Filter: "玩具总动员 5 2026",
MediaType: "movie",
Year: 2026,
}
results := []SearchResult{{
Title: "Toy Story 4 2019 2160p DSNP WEB-DL",
DownloadURL: "https://pt/download/toy-story-4",
SearchKeyword: "玩具总动员 5",
Seeders: 90,
}}
got, stats := selectSiteSearchCandidatesWithStats(results, sub, map[string]struct{}{}, LocalAvailability{})
if len(got) != 0 {
t.Fatalf("selected %#v, want conflicting-year keyword-origin result rejected", got)
}
if stats.QueryMismatch != 1 || stats.Prepared != 0 {
t.Fatalf("stats = %#v, want query mismatch for conflicting year", stats)
}
}
func TestSelectSiteSearchCandidatesDoesNotWashByDefault(t *testing.T) {
sub := &model.Subscription{Name: "Inception 自动订阅", Filter: "Inception 2010", MediaType: "movie", WashPriority: "resolution"}
results := []SearchResult{
{Title: "Inception 2010 1080p", DownloadURL: "https://pt/download/1080", Seeders: 90},
{Title: "Inception 2010 2160p", DownloadURL: "https://pt/download/2160", Seeders: 80},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/2160" {
t.Fatalf("selected %#v, want default best single result when wash disabled", got)
}
}
func TestSelectSiteSearchCandidatesWashNeedsExplicitUpgradeCriteria(t *testing.T) {
sub := &model.Subscription{Name: "Inception 自动订阅", Filter: "Inception 2010", MediaType: "movie", WashEnabled: true, WashPriority: "resolution"}
local := LocalAvailability{LocalMediaCount: 1, InLibrary: true}
results := []SearchResult{
{Title: "Inception 2010 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/1080", Seeders: 90},
{Title: "Inception 2010 2160p WEB-DL H264 AAC", DownloadURL: "https://pt/download/2160", Seeders: 80},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{}, local)
if len(got) != 0 {
t.Fatalf("selected %#v, want no wash download without explicit upgrade criteria", got)
}
sub.Resolution = "2160p"
got = selectSiteSearchCandidates(results, sub, map[string]struct{}{}, local)
if len(got) != 1 || got[0].Download != "https://pt/download/2160" {
t.Fatalf("selected %#v, want explicit 2160p wash candidate", got)
}
}
func TestSelectSiteSearchCandidatesWashWithoutCriteriaUsesDefaultQuality(t *testing.T) {
sub := &model.Subscription{Name: "Dune 自动订阅", Filter: "Dune 2021", MediaType: "movie", WashEnabled: true, WashPriority: "quality"}
results := []SearchResult{
{Title: "Dune 2021 2160p REMUX H264 AAC", DownloadURL: "https://pt/download/remux", Seeders: 80},
{Title: "Dune 2021 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/webdl", Seeders: 60},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/webdl" {
t.Fatalf("selected %#v, want default compatible WEB-DL when wash has no explicit criteria", got)
}
}
func TestSelectSiteSearchCandidatesDefaultsToOnePreferredVersionPerEpisode(t *testing.T) {
sub := &model.Subscription{Name: "House of the Dragon 自动订阅", Filter: "House of the Dragon", MediaType: "tv"}
results := []SearchResult{
{Title: "House of the Dragon S03E01 1080p HDTV", DownloadURL: "https://pt/download/e01-hdtv", Seeders: 50000},
{Title: "House of the Dragon S03E01 1080p WEB-DL", DownloadURL: "https://pt/download/e01-webdl-1080", Seeders: 100},
{Title: "House of the Dragon S03E01 2160p WEB-DL", DownloadURL: "https://pt/download/e01-webdl-2160", Seeders: 80},
{Title: "House of the Dragon S03E02 720p HDTV", DownloadURL: "https://pt/download/e02-hdtv", Seeders: 500},
{Title: "House of the Dragon S03E02 1080p WEBRip", DownloadURL: "https://pt/download/e02-webrip", Seeders: 60},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 2 {
t.Fatalf("selected %d candidates, want one per episode", len(got))
}
if got[0].Download != "https://pt/download/e01-webdl-2160" {
t.Fatalf("episode 1 selected %q, want best WEB-DL version", got[0].Download)
}
if got[1].Download != "https://pt/download/e02-webrip" {
t.Fatalf("episode 2 selected %q, want WEBRip over high-seeder HDTV", got[1].Download)
}
}
func TestSelectSiteSearchCandidatesDefaultQualityRecognizesWebDLVariants(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show S01E01 1080p BluRay H264 AAC", DownloadURL: "https://pt/download/e01-bluray", Seeders: 900},
{Title: "Some Show S01E01 2160p WEB.DL H264 AAC", DownloadURL: "https://pt/download/e01-webdotdl", Seeders: 40},
{Title: "Some Show S01E01 1080p WEB DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl", Seeders: 50},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-webdotdl" {
t.Fatalf("selected %#v, want one best WEB-DL variant", got)
}
}
func TestSelectSiteSearchCandidatesDefaultPrefersWebDLBeforeResolution(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show S01E01 2160p BluRay H264 AAC", DownloadURL: "https://pt/download/e01-bluray-2160", Seeders: 900},
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl-1080", Seeders: 50},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-webdl-1080" {
t.Fatalf("selected %#v, want one compatible WEB-DL version before higher-resolution BluRay", got)
}
}
func TestSelectSiteSearchCandidatesDefaultPrefersFreeWithinSameQualityBand(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-nonfree", Seeders: 5000},
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-free", Seeders: 80, Free: true},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-free" {
t.Fatalf("selected %#v, want free candidate within same quality/resolution band", got)
}
}
func TestSelectSiteSearchCandidatesDefaultDoesNotLetFreeOverrideBetterQuality(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show S01E01 1080p HDTV H264 AAC", DownloadURL: "https://pt/download/e01-free-hdtv", Seeders: 80, Free: true},
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl", Seeders: 50},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-webdl" {
t.Fatalf("selected %#v, want WEB-DL quality to stay ahead of free HDTV", got)
}
}
func TestSelectSiteSearchCandidatesDefaultDoesNotLetFreeOverrideBetterResolution(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-free-1080", Seeders: 80, Free: true},
{Title: "Some Show S01E01 2160p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-2160", Seeders: 50},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-2160" {
t.Fatalf("selected %#v, want better resolution to stay ahead of free lower-resolution release", got)
}
}
func TestSelectSiteSearchCandidatesDefaultsToOneLooseNumberedEpisode(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show 01 1080p HDTV H264 AAC", DownloadURL: "https://pt/download/e01-hdtv", Seeders: 5000},
{Title: "Some Show 01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl-1080", Seeders: 100},
{Title: "Some Show 01 2160p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl-2160", Seeders: 80},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 {
t.Fatalf("selected %d candidates, want one preferred loose-numbered episode", len(got))
}
if got[0].Download != "https://pt/download/e01-webdl-2160" || got[0].Episode != 1 {
t.Fatalf("selected %#v, want episode 1 best WEB-DL version", got)
}
}
func TestSelectSiteSearchCandidatesDoesNotTreatTitleNumberAsLooseEpisode(t *testing.T) {
sub := &model.Subscription{Name: "问心2 自动订阅", Filter: "问心2 2023", MediaType: "tv"}
results := []SearchResult{
{Title: "问心2 2023 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/season", Seeders: 100},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 {
t.Fatalf("selected %#v, want one fallback candidate", got)
}
if got[0].Episode != 0 {
t.Fatalf("episode = %d, want title number not treated as episode", got[0].Episode)
}
}
func TestSelectSiteSearchCandidatesRejectsRiskyLabelsFromSiteResult(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv"}
results := []SearchResult{
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", Labels: "HR", DownloadURL: "https://pt/download/e01-hr", Seeders: 900},
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-safe", Seeders: 80},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-safe" {
t.Fatalf("selected %#v, want non-HR candidate only", got)
}
}
func TestSelectSiteSearchCandidatesWashPriorityDoesNotLetFreeOverrideResolution(t *testing.T) {
sub := &model.Subscription{Name: "Some Show 自动订阅", Filter: "Some Show", MediaType: "tv", WashEnabled: true, WashPriority: "resolution"}
results := []SearchResult{
{Title: "Some Show S01E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-free-1080", Seeders: 80, Free: true},
{Title: "Some Show S01E01 2160p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-2160", Seeders: 50},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-2160" {
t.Fatalf("selected %#v, want wash resolution priority to stay ahead of free lower-resolution release", got)
}
}
func TestSelectSiteSearchCandidatesRejectsDefaultCompatibilityVersions(t *testing.T) {
sub := &model.Subscription{Name: "House of the Dragon 自动订阅", Filter: "House of the Dragon", MediaType: "tv"}
results := []SearchResult{
{Title: "House of the Dragon S03E01 2160p WEB-DL HEVC 10bit DoVi Atmos", DownloadURL: "https://pt/download/e01-dovi", Seeders: 900},
{Title: "House of the Dragon S03E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl", Seeders: 80},
{Title: "House of the Dragon S03E01 1080p HDTV H264 AAC", DownloadURL: "https://pt/download/e01-hdtv", Seeders: 5000},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-webdl" {
t.Fatalf("selected %#v, want compatible WEB-DL only", got)
}
}
func TestSelectSiteSearchCandidatesKeepsCompatibilityExcludesWithCustomExcludeWords(t *testing.T) {
sub := &model.Subscription{
Name: "House of the Dragon 自动订阅",
Filter: "House of the Dragon",
MediaType: "tv",
ExcludeWords: "官中,无字幕",
}
results := []SearchResult{
{Title: "House of the Dragon S03E01 2160p WEB-DL HEVC 10bit DoVi Atmos", DownloadURL: "https://pt/download/e01-dovi", Seeders: 900},
{Title: "House of the Dragon S03E01 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-webdl", Seeders: 80},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/e01-webdl" {
t.Fatalf("selected %#v, want custom exclude words to keep default compatible WEB-DL guard", got)
}
}
func TestSelectSiteSearchCandidatesAvoidsOverlappingEpisodeRanges(t *testing.T) {
sub := &model.Subscription{Name: "House of the Dragon 自动订阅", Filter: "House of the Dragon", MediaType: "tv", WashEnabled: true, WashPriority: "quality"}
availability := LocalAvailability{
LocalMediaCount: 1,
TotalEpisodes: 3,
MissingEpisodes: []int{1, 2, 3},
ExistingEpisodeKeys: map[string]struct{}{},
}
results := []SearchResult{
{Title: "House of the Dragon S03E01-E02 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e01-e02-pack", Seeders: 90},
{Title: "House of the Dragon S03E02 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e02-duplicate", Seeders: 80},
{Title: "House of the Dragon S03E03 1080p WEB-DL H264 AAC", DownloadURL: "https://pt/download/e03", Seeders: 70},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{}, availability)
if len(got) != 2 {
t.Fatalf("selected %d candidates, want pack plus non-overlapping episode", len(got))
}
if got[0].Download != "https://pt/download/e01-e02-pack" || got[1].Download != "https://pt/download/e03" {
t.Fatalf("selected %#v, want overlapping E02 duplicate skipped", got)
}
}
func TestSelectSiteSearchCandidatesAppliesQualityRules(t *testing.T) {
sub := &model.Subscription{
Name: "Dune 自动订阅",
Filter: "Dune 2021",
MediaType: "movie",
Resolution: "2160p",
Quality: "remux",
Effects: "hdr",
ExcludeWords: "cam,ts",
}
results := []SearchResult{
{Title: "Dune 2021 2160p WEB-DL HDR", DownloadURL: "https://pt/download/web", Seeders: 100},
{Title: "Dune 2021 2160p UHD BluRay REMUX HDR", DownloadURL: "https://pt/download/remux", Seeders: 30},
{Title: "Dune 2021 2160p REMUX HDR CAM", DownloadURL: "https://pt/download/cam", Seeders: 200},
}
got := selectSiteSearchCandidates(results, sub, map[string]struct{}{})
if len(got) != 1 || got[0].Download != "https://pt/download/remux" {
t.Fatalf("selected %#v, want filtered remux", got)
}
}