package recipes import ( "encoding/json" "errors" "time" ) // HiddenGemsParams configures the hidden_gems resolver. type HiddenGemsParams struct { MinRating float64 `json:"min_rating,omitempty"` MaxPlayCount int `json:"max_play_count,omitempty"` } type hiddenGemsRecipe struct{} func (hiddenGemsRecipe) Type() string { return "hidden_gems" } func (hiddenGemsRecipe) NewParams() any { return &HiddenGemsParams{} } func (hiddenGemsRecipe) DefaultCacheTTL() time.Duration { return 6 * time.Hour } func (hiddenGemsRecipe) Resolve(rc ResolverContext) (ResolvedItems, error) { return delegateResolve("hidden_gems", rc) } func (hiddenGemsRecipe) Validate(raw json.RawMessage) error { if len(raw) == 0 { return nil } var p HiddenGemsParams return json.Unmarshal(raw, &p) } func (hiddenGemsRecipe) Definition() RecipeDefinition { return RecipeDefinition{ Type: "hidden_gems", Category: CategoryDiscovery, AvoidDuplicates: true, Presets: []GalleryPreset{ { Key: "hidden_gems_default", DisplayName: "Hidden Gems", Icon: "💎", DescriptionShort: "Highly rated titles in your library that no one's watched.", DefaultParams: json.RawMessage(`{"min_rating":7.5,"max_play_count":2}`), }, }, } } // CriticallyAcclaimedParams configures the critically_acclaimed resolver. type CriticallyAcclaimedParams struct { MinScore float64 `json:"min_score,omitempty"` Source string `json:"source,omitempty"` } type criticallyAcclaimedRecipe struct{} func (criticallyAcclaimedRecipe) Type() string { return "critically_acclaimed" } func (criticallyAcclaimedRecipe) NewParams() any { return &CriticallyAcclaimedParams{} } func (criticallyAcclaimedRecipe) DefaultCacheTTL() time.Duration { return 6 * time.Hour } func (criticallyAcclaimedRecipe) Resolve(rc ResolverContext) (ResolvedItems, error) { return delegateResolve("critically_acclaimed", rc) } func (criticallyAcclaimedRecipe) Validate(raw json.RawMessage) error { if len(raw) == 0 { return nil } var p CriticallyAcclaimedParams return json.Unmarshal(raw, &p) } func (criticallyAcclaimedRecipe) Definition() RecipeDefinition { return RecipeDefinition{ Type: "critically_acclaimed", Category: CategoryDiscovery, AvoidDuplicates: true, Presets: []GalleryPreset{ { Key: "ca_imdb", DisplayName: "Critically Acclaimed", Icon: "🏆", DescriptionShort: "8.0+ rated by IMDb.", DefaultParams: json.RawMessage(`{"min_score":8.0,"source":"imdb"}`), }, }, } } // AwardWinnersParams configures the award_winners resolver. type AwardWinnersParams struct { AwardType string `json:"award_type,omitempty"` Limit int `json:"limit,omitempty"` } type awardWinnersRecipe struct{} func (awardWinnersRecipe) Type() string { return "award_winners" } func (awardWinnersRecipe) NewParams() any { return &AwardWinnersParams{} } func (awardWinnersRecipe) DefaultCacheTTL() time.Duration { return 6 * time.Hour } func (awardWinnersRecipe) Resolve(rc ResolverContext) (ResolvedItems, error) { return delegateResolve("award_winners", rc) } func (awardWinnersRecipe) Validate(raw json.RawMessage) error { if len(raw) == 0 { return nil } var p AwardWinnersParams return json.Unmarshal(raw, &p) } func (awardWinnersRecipe) Definition() RecipeDefinition { return RecipeDefinition{ Type: "award_winners", Category: CategoryDiscovery, AvoidDuplicates: true, Presets: []GalleryPreset{ { Key: "aw_oscar", DisplayName: "Oscar Winners", Icon: "🏅", DescriptionShort: "Academy Award winners in your library.", DefaultParams: json.RawMessage(`{"award_type":"oscar"}`), }, { Key: "aw_emmy", DisplayName: "Emmy Winners", Icon: "📺", DescriptionShort: "Emmy-winning shows.", DefaultParams: json.RawMessage(`{"award_type":"emmy"}`), }, { Key: "aw_cannes", DisplayName: "Cannes Selections", Icon: "🎞️", DescriptionShort: "Cannes Festival selections.", DefaultParams: json.RawMessage(`{"award_type":"cannes"}`), }, }, } } // ForgottenFavoritesParams configures the forgotten_favorites resolver. type ForgottenFavoritesParams struct { LookbackDays int `json:"lookback_days,omitempty"` } type forgottenFavoritesRecipe struct{} func (forgottenFavoritesRecipe) Type() string { return "forgotten_favorites" } func (forgottenFavoritesRecipe) NewParams() any { return &ForgottenFavoritesParams{} } func (forgottenFavoritesRecipe) DefaultCacheTTL() time.Duration { return 6 * time.Hour } func (forgottenFavoritesRecipe) Resolve(rc ResolverContext) (ResolvedItems, error) { return delegateResolve("forgotten_favorites", rc) } func (forgottenFavoritesRecipe) Validate(raw json.RawMessage) error { if len(raw) == 0 { return nil } var p ForgottenFavoritesParams return json.Unmarshal(raw, &p) } func (forgottenFavoritesRecipe) Definition() RecipeDefinition { return RecipeDefinition{ Type: "forgotten_favorites", Category: CategoryDiscovery, AvoidDuplicates: true, Presets: []GalleryPreset{ { Key: "ff_default", DisplayName: "Forgotten Favorites", Icon: "🕰️", DescriptionShort: "In your library, haven't been watched in a year.", DefaultParams: json.RawMessage(`{"lookback_days":365}`), }, }, } } // FormatShowcaseParams configures the format_showcase resolver. type FormatShowcaseParams struct { Format string `json:"format"` // 4k | dolby_vision | hdr } type formatShowcaseRecipe struct{} func (formatShowcaseRecipe) Type() string { return "format_showcase" } func (formatShowcaseRecipe) NewParams() any { return &FormatShowcaseParams{} } func (formatShowcaseRecipe) DefaultCacheTTL() time.Duration { return 6 * time.Hour } func (formatShowcaseRecipe) Resolve(rc ResolverContext) (ResolvedItems, error) { return delegateResolve("format_showcase", rc) } func (formatShowcaseRecipe) Validate(raw json.RawMessage) error { if len(raw) == 0 { return nil } var p FormatShowcaseParams if err := json.Unmarshal(raw, &p); err != nil { return err } switch p.Format { case "", "4k", "dolby_vision", "hdr": return nil default: return errors.New("format_showcase: unknown format") } } func (formatShowcaseRecipe) Definition() RecipeDefinition { return RecipeDefinition{ Type: "format_showcase", Category: CategoryDiscovery, AvoidDuplicates: false, Presets: []GalleryPreset{ {Key: "fs_4k", DisplayName: "4K Showcase", Icon: "🎥", DescriptionShort: "Titles available in 4K UHD.", DefaultParams: json.RawMessage(`{"format":"4k"}`)}, {Key: "fs_dv", DisplayName: "Dolby Vision Picks", Icon: "🌈", DescriptionShort: "Dolby Vision titles.", DefaultParams: json.RawMessage(`{"format":"dolby_vision"}`)}, {Key: "fs_hdr", DisplayName: "HDR Highlights", Icon: "✨", DescriptionShort: "HDR-mastered titles.", DefaultParams: json.RawMessage(`{"format":"hdr"}`)}, }, } } func init() { Register(hiddenGemsRecipe{}) Register(criticallyAcclaimedRecipe{}) Register(awardWinnersRecipe{}) Register(forgottenFavoritesRecipe{}) Register(formatShowcaseRecipe{}) }