feat(collections): add tmdb_discover genre templates
Append the Phase-2 catalog from the collection-templates expansion plan: - 18 Popular by Genre (sort_order 5001..5018, daily 0 4 * * *, popularity.desc with vote_count_gte=300) - 18 Top Rated by Genre (sort_order 6001..6018, weekly 0 5 * * 0, vote_average.desc with vote_count_gte=1000) - 1 Kids Movies (sort_order 9050, weekly, Family genre with certification_lte=PG) Adds TestPhase2DiscoverTemplatesUseExpectedBands to pin the band ranges and the TMDB query parameters that define each section. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
committed by
Silo Server Migration
co-authored by
Claude Opus 4.7
parent
c085b12fd1
commit
df5e427232
@@ -829,6 +829,689 @@ var builtinTemplates = []Template{
|
||||
DefaultSyncSchedule: "0 6 * * *",
|
||||
MDBList: &MDBListSpec{URL: ""},
|
||||
},
|
||||
|
||||
// ── Popular by Genre (TMDB Discover) ─────────────────────────────────────
|
||||
// 5000s band. Each entry runs TMDB's /discover/movie endpoint sorted by
|
||||
// popularity.desc with a 300-vote floor to keep emerging-but-thin titles
|
||||
// from polluting the top of the list. Daily refresh at 04:00 matches the
|
||||
// existing tmdb_popular_* cadence.
|
||||
{
|
||||
ID: "tmdb_discover_popular_action",
|
||||
Title: "Popular Action",
|
||||
Description: "Crowd-pleasing action films sorted by current TMDB popularity.",
|
||||
Icon: "💥",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5001,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{28},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_adventure",
|
||||
Title: "Popular Adventure",
|
||||
Description: "Trending adventure movies driving the most TMDB attention right now.",
|
||||
Icon: "🗺️",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5002,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{12},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_animation",
|
||||
Title: "Popular Animation",
|
||||
Description: "Animated features riding high on TMDB popularity, from family fare to adult animation.",
|
||||
Icon: "🎨",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5003,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{16},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_comedy",
|
||||
Title: "Popular Comedy",
|
||||
Description: "Comedies pulling the most viewers across TMDB this week.",
|
||||
Icon: "😂",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5004,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{35},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_crime",
|
||||
Title: "Popular Crime",
|
||||
Description: "Heists, mobsters, and procedurals dominating TMDB's crime charts.",
|
||||
Icon: "🕵️",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5005,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{80},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_documentary",
|
||||
Title: "Popular Documentary",
|
||||
Description: "Most-watched documentary features on TMDB right now.",
|
||||
Icon: "🎥",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5006,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{99},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_drama",
|
||||
Title: "Popular Drama",
|
||||
Description: "Drama films riding the top of TMDB's popularity rankings.",
|
||||
Icon: "🎭",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5007,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{18},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_family",
|
||||
Title: "Popular Family",
|
||||
Description: "Family-friendly hits with the biggest current TMDB audience.",
|
||||
Icon: "👨👩👧",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5008,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10751},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_fantasy",
|
||||
Title: "Popular Fantasy",
|
||||
Description: "Magic, myths, and quests — the fantasy slate trending on TMDB.",
|
||||
Icon: "🧙",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5009,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{14},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_history",
|
||||
Title: "Popular History",
|
||||
Description: "Historical dramas and period pieces ranked by TMDB popularity.",
|
||||
Icon: "🏛️",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5010,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{36},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_horror",
|
||||
Title: "Popular Horror",
|
||||
Description: "The horror titles drawing the biggest TMDB crowds right now.",
|
||||
Icon: "👻",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5011,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{27},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_music",
|
||||
Title: "Popular Music",
|
||||
Description: "Music biopics, concert films, and musicals climbing TMDB's charts.",
|
||||
Icon: "🎵",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5012,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10402},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_mystery",
|
||||
Title: "Popular Mystery",
|
||||
Description: "Whodunits and puzzlers with the most active TMDB audience.",
|
||||
Icon: "🔍",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5013,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{9648},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_romance",
|
||||
Title: "Popular Romance",
|
||||
Description: "Love stories pulling the most viewers across TMDB's romance shelf.",
|
||||
Icon: "💞",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5014,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10749},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_science_fiction",
|
||||
Title: "Popular Science Fiction",
|
||||
Description: "Sci-fi blockbusters and cult favourites sorted by TMDB heat.",
|
||||
Icon: "🚀",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5015,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{878},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_thriller",
|
||||
Title: "Popular Thriller",
|
||||
Description: "Tense, fast-moving thrillers ranked by current TMDB popularity.",
|
||||
Icon: "🗡️",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5016,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{53},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_war",
|
||||
Title: "Popular War",
|
||||
Description: "War films and combat dramas trending on TMDB this week.",
|
||||
Icon: "⚔️",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5017,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10752},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_popular_western",
|
||||
Title: "Popular Western",
|
||||
Description: "Westerns drawing the most TMDB attention, from classics to revisionist tales.",
|
||||
Icon: "🤠",
|
||||
Category: CategoryPopular,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 5018,
|
||||
DefaultSyncSchedule: "0 4 * * *",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{37},
|
||||
SortBy: "popularity.desc",
|
||||
VoteCountGte: 300,
|
||||
},
|
||||
},
|
||||
|
||||
// ── Top Rated by Genre (TMDB Discover) ───────────────────────────────────
|
||||
// 6000s band. Sorted by vote_average.desc with a 1000-vote floor — high
|
||||
// enough to filter out fluke perfect scores while still leaving room for
|
||||
// well-regarded mid-tier titles. Refresh weekly on Sunday at 05:00.
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_action",
|
||||
Title: "Top Rated Action",
|
||||
Description: "The highest-scoring action films on TMDB with enough votes to count.",
|
||||
Icon: "💥",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6001,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{28},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_adventure",
|
||||
Title: "Top Rated Adventure",
|
||||
Description: "Best-reviewed adventure films across TMDB, weighted by user votes.",
|
||||
Icon: "🗺️",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6002,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{12},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_animation",
|
||||
Title: "Top Rated Animation",
|
||||
Description: "The animated films TMDB users score highest, from Pixar to anime.",
|
||||
Icon: "🎨",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6003,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{16},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_comedy",
|
||||
Title: "Top Rated Comedy",
|
||||
Description: "The best-rated comedies on TMDB, surfacing classics over flash-in-the-pan hits.",
|
||||
Icon: "😂",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6004,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{35},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_crime",
|
||||
Title: "Top Rated Crime",
|
||||
Description: "The most acclaimed crime films on TMDB, gathered by user vote.",
|
||||
Icon: "🕵️",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6005,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{80},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_documentary",
|
||||
Title: "Top Rated Documentary",
|
||||
Description: "Documentaries with the strongest TMDB scores and a solid vote count.",
|
||||
Icon: "🎥",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6006,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{99},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_drama",
|
||||
Title: "Top Rated Drama",
|
||||
Description: "TMDB's best-rated dramas — character-led, story-first cinema.",
|
||||
Icon: "🎭",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6007,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{18},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_family",
|
||||
Title: "Top Rated Family",
|
||||
Description: "Family films that earn TMDB's highest user scores.",
|
||||
Icon: "👨👩👧",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6008,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10751},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_fantasy",
|
||||
Title: "Top Rated Fantasy",
|
||||
Description: "Fantasy films with the best TMDB ratings across the genre.",
|
||||
Icon: "🧙",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6009,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{14},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_history",
|
||||
Title: "Top Rated History",
|
||||
Description: "The most acclaimed historical films on TMDB, sorted by vote average.",
|
||||
Icon: "🏛️",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6010,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{36},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_horror",
|
||||
Title: "Top Rated Horror",
|
||||
Description: "The best-rated horror films on TMDB, vote-weighted to keep the bar honest.",
|
||||
Icon: "👻",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6011,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{27},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_music",
|
||||
Title: "Top Rated Music",
|
||||
Description: "Music films that earn TMDB's strongest user reception, from biopics to musicals.",
|
||||
Icon: "🎵",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6012,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10402},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_mystery",
|
||||
Title: "Top Rated Mystery",
|
||||
Description: "Mystery films with the highest TMDB scores and a healthy vote base.",
|
||||
Icon: "🔍",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6013,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{9648},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_romance",
|
||||
Title: "Top Rated Romance",
|
||||
Description: "Romance films with TMDB's best-loved ratings and a real audience behind them.",
|
||||
Icon: "💞",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6014,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10749},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_science_fiction",
|
||||
Title: "Top Rated Science Fiction",
|
||||
Description: "Science fiction films at the very top of TMDB's vote averages.",
|
||||
Icon: "🚀",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6015,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{878},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_thriller",
|
||||
Title: "Top Rated Thriller",
|
||||
Description: "Thrillers that crowd the upper end of TMDB's vote averages.",
|
||||
Icon: "🗡️",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6016,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{53},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_war",
|
||||
Title: "Top Rated War",
|
||||
Description: "The most acclaimed war films on TMDB, sorted by user vote average.",
|
||||
Icon: "⚔️",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6017,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10752},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "tmdb_discover_top_rated_western",
|
||||
Title: "Top Rated Western",
|
||||
Description: "Westerns with the best TMDB scores, from classic horse operas to modern revisions.",
|
||||
Icon: "🤠",
|
||||
Category: CategoryTopRated,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 6018,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{37},
|
||||
SortBy: "vote_average.desc",
|
||||
VoteCountGte: 1000,
|
||||
},
|
||||
},
|
||||
|
||||
// ── Kids Movies (TMDB Discover) ──────────────────────────────────────────
|
||||
// 9000s band (Misc/Kids slot). Combines TMDB's Family genre with a PG
|
||||
// certification ceiling so the result tracks something an actual kid can
|
||||
// watch, not just a soft-PG-13 family-marketed action film.
|
||||
{
|
||||
ID: "tmdb_discover_kids_movies",
|
||||
Title: "Kids Movies",
|
||||
Description: "Family-genre films capped at a PG certification — safe picks for younger viewers.",
|
||||
Icon: "🧸",
|
||||
Category: CategoryEditorial,
|
||||
Source: SourceTMDBDiscover,
|
||||
MediaKind: MediaMovie,
|
||||
DefaultLimit: builtinDefaultLimit,
|
||||
DefaultSortOrder: 9050,
|
||||
DefaultSyncSchedule: "0 5 * * 0",
|
||||
TMDBDiscover: &TMDBDiscoverSpec{
|
||||
MediaType: "movie",
|
||||
WithGenres: []int{10751},
|
||||
SortBy: "popularity.desc",
|
||||
CertificationLte: "PG",
|
||||
VoteCountGte: 100,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
var builtinBundles = []Bundle{
|
||||
|
||||
@@ -455,6 +455,82 @@ func TestCategoryLabelKnowsAllBuiltinCategories(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestPhase2DiscoverTemplatesUseExpectedBands pins the Phase-2 TMDB Discover
|
||||
// genre matrix to its documented sort-order bands and TMDB query parameters.
|
||||
// Drift here would either reorder the gallery in surprising ways (band
|
||||
// regressions) or change what a "Popular Action" / "Top Rated Action" template
|
||||
// actually returns from TMDB (filter regressions) — both silent failures from
|
||||
// the operator's perspective, so make them loud.
|
||||
func TestPhase2DiscoverTemplatesUseExpectedBands(t *testing.T) {
|
||||
const (
|
||||
popularPrefix = "tmdb_discover_popular_"
|
||||
topRatedPrefix = "tmdb_discover_top_rated_"
|
||||
kidsPrefix = "tmdb_discover_kids_"
|
||||
)
|
||||
var popularCount, topRatedCount, kidsCount int
|
||||
for _, tmpl := range List() {
|
||||
switch {
|
||||
case strings.HasPrefix(tmpl.ID, popularPrefix):
|
||||
popularCount++
|
||||
if tmpl.Source != SourceTMDBDiscover {
|
||||
t.Errorf("%s: Source = %q, want %q", tmpl.ID, tmpl.Source, SourceTMDBDiscover)
|
||||
}
|
||||
if tmpl.TMDBDiscover == nil {
|
||||
t.Fatalf("%s: TMDBDiscover spec is nil", tmpl.ID)
|
||||
}
|
||||
if tmpl.DefaultSortOrder < 5000 || tmpl.DefaultSortOrder > 5999 {
|
||||
t.Errorf("%s: DefaultSortOrder %d outside Popular band [5000, 5999]", tmpl.ID, tmpl.DefaultSortOrder)
|
||||
}
|
||||
if tmpl.TMDBDiscover.SortBy != "popularity.desc" {
|
||||
t.Errorf("%s: SortBy = %q, want popularity.desc", tmpl.ID, tmpl.TMDBDiscover.SortBy)
|
||||
}
|
||||
if tmpl.TMDBDiscover.VoteCountGte != 300 {
|
||||
t.Errorf("%s: VoteCountGte = %d, want 300", tmpl.ID, tmpl.TMDBDiscover.VoteCountGte)
|
||||
}
|
||||
case strings.HasPrefix(tmpl.ID, topRatedPrefix):
|
||||
topRatedCount++
|
||||
if tmpl.Source != SourceTMDBDiscover {
|
||||
t.Errorf("%s: Source = %q, want %q", tmpl.ID, tmpl.Source, SourceTMDBDiscover)
|
||||
}
|
||||
if tmpl.TMDBDiscover == nil {
|
||||
t.Fatalf("%s: TMDBDiscover spec is nil", tmpl.ID)
|
||||
}
|
||||
if tmpl.DefaultSortOrder < 6000 || tmpl.DefaultSortOrder > 6999 {
|
||||
t.Errorf("%s: DefaultSortOrder %d outside Top Rated band [6000, 6999]", tmpl.ID, tmpl.DefaultSortOrder)
|
||||
}
|
||||
if tmpl.TMDBDiscover.SortBy != "vote_average.desc" {
|
||||
t.Errorf("%s: SortBy = %q, want vote_average.desc", tmpl.ID, tmpl.TMDBDiscover.SortBy)
|
||||
}
|
||||
if tmpl.TMDBDiscover.VoteCountGte != 1000 {
|
||||
t.Errorf("%s: VoteCountGte = %d, want 1000", tmpl.ID, tmpl.TMDBDiscover.VoteCountGte)
|
||||
}
|
||||
case strings.HasPrefix(tmpl.ID, kidsPrefix):
|
||||
kidsCount++
|
||||
if tmpl.Source != SourceTMDBDiscover {
|
||||
t.Errorf("%s: Source = %q, want %q", tmpl.ID, tmpl.Source, SourceTMDBDiscover)
|
||||
}
|
||||
if tmpl.TMDBDiscover == nil {
|
||||
t.Fatalf("%s: TMDBDiscover spec is nil", tmpl.ID)
|
||||
}
|
||||
if tmpl.DefaultSortOrder < 9000 || tmpl.DefaultSortOrder > 9999 {
|
||||
t.Errorf("%s: DefaultSortOrder %d outside Misc/Kids band [9000, 9999]", tmpl.ID, tmpl.DefaultSortOrder)
|
||||
}
|
||||
if tmpl.TMDBDiscover.CertificationLte != "PG" {
|
||||
t.Errorf("%s: CertificationLte = %q, want PG", tmpl.ID, tmpl.TMDBDiscover.CertificationLte)
|
||||
}
|
||||
}
|
||||
}
|
||||
if popularCount != 18 {
|
||||
t.Errorf("Popular by Genre count = %d, want 18", popularCount)
|
||||
}
|
||||
if topRatedCount != 18 {
|
||||
t.Errorf("Top Rated by Genre count = %d, want 18", topRatedCount)
|
||||
}
|
||||
if kidsCount != 1 {
|
||||
t.Errorf("Kids count = %d, want 1", kidsCount)
|
||||
}
|
||||
}
|
||||
|
||||
// TestPhase1MDBListTemplatesHaveSortOrderInExpectedBands verifies that the
|
||||
// Phase-1 MDBList-backed templates land in the sort-order bands documented in
|
||||
// docs/superpowers/plans/2026-05-22-collection-templates-expansion.md. The
|
||||
|
||||
Reference in New Issue
Block a user