Documentation
¶
Overview ¶
Package catalog implements core.Catalog: a SQLite mirror of a filtered TMDB slice plus on-demand fetches for anything else.
Index ¶
- Constants
- Variables
- func EstimateTitles(minPopularity float64, minVotes int) int
- func MeetsThreshold(cfg config.Catalog, t core.Title, now time.Time) bool
- func RatingExceeds(rating, max string) bool
- func RatingRank(rating string) int
- func WithinRatingLimit(rating, max string) bool
- type Catalog
- func (c *Catalog) Browse(ctx context.Context, q core.BrowseQuery) (core.Page, error)
- func (c *Catalog) ByExternalID(ctx context.Context, source, id string) (*core.Title, error)
- func (c *Catalog) CachedTitle(ctx context.Context, key core.RatingKey) (*core.Title, error)
- func (c *Catalog) Children(ctx context.Context, key core.RatingKey) ([]core.Title, error)
- func (c *Catalog) Collection(ctx context.Context, tmdbCollection int64) (string, []core.Title, error)
- func (c *Catalog) CrowdRecommendations(ctx context.Context, key core.RatingKey, pages int, fetch bool) (titles []core.Title, fetched bool, err error)
- func (c *Catalog) Facet(ctx context.Context, t core.MediaType, facet string) ([]core.FacetValue, error)
- func (c *Catalog) Get(ctx context.Context, key core.RatingKey) (*core.Title, error)
- func (c *Catalog) Grandchildren(ctx context.Context, key core.RatingKey) ([]core.Title, error)
- func (c *Catalog) List(ctx context.Context, list string, t core.MediaType, limit int) ([]core.Title, error)
- func (c *Catalog) NextEpisode(ctx context.Context, episode core.RatingKey) (*core.Title, error)
- func (c *Catalog) RecentEpisodes(ctx context.Context, show core.RatingKey, since time.Time) ([]core.Title, error)
- func (c *Catalog) Run(ctx context.Context)
- func (c *Catalog) Search(ctx context.Context, query string, types []core.MediaType, limit int) ([]core.Title, error)
- func (c *Catalog) SeedGenres(mediaType string, m map[int]string)
- func (c *Catalog) Similar(ctx context.Context, key core.RatingKey, limit int) ([]core.Title, error)
- func (c *Catalog) Stats(ctx context.Context) (Stats, error)
- func (c *Catalog) Sync(ctx context.Context) error
- func (c *Catalog) SyncProgress() SyncProgress
- func (c *Catalog) UpdateConfig(cfg config.Catalog)
- func (c *Catalog) UpsertTitle(ctx context.Context, t core.Title, browsable bool) error
- type Estimate
- type Mirror
- func (m *Mirror) CollectionArt(ctx context.Context, id int64) (core.Collection, error)
- func (m *Mirror) Fingerprint(ctx context.Context) (MirrorFingerprint, error)
- func (m *Mirror) Franchises(ctx context.Context) ([]core.Collection, error)
- func (m *Mirror) Snapshot(ctx context.Context) ([]MirrorItem, error)
- func (m *Mirror) Titles(ctx context.Context, keys []core.RatingKey) ([]core.Title, error)
- type MirrorFingerprint
- type MirrorItem
- type Option
- type Stats
- type SyncProgress
- type TMDB
Constants ¶
const DefaultCrowdTTL = 72 * time.Hour
DefaultCrowdTTL is how long a stored co-engagement list is fresh.
Variables ¶
var ErrSyncInProgress = fmt.Errorf("catalog: sync already in progress")
Sync (re)builds the browsable set from TMDB discover. A second call while one is running returns ErrSyncInProgress; use SyncProgress to poll.
Functions ¶
func EstimateTitles ¶
EstimateTitles is a convenience wrapper returning only the total.
func MeetsThreshold ¶
MeetsThreshold reports whether a title qualifies for the browsable set under cfg: popularity >= MinPopularity OR votes >= MinVotes, and released.
func RatingExceeds ¶
RatingExceeds reports whether rating is stricter than max ("" max = unrestricted).
func RatingRank ¶
Content-rating ordering. All scales map onto a unified severity rank:
1 everyone G, TV-G, TV-Y, U 2 parental PG, TV-PG, TV-Y7 3 teens PG-13, TV-14, 12/15-ish, M 4 adults R, TV-MA, MA15+ 5 adults-only NC-17, 18/R18+
Unknown / unrated ratings rank 0. Restricted viewers cannot access them.
func WithinRatingLimit ¶
WithinRatingLimit is the negation, for readability at call sites.
Types ¶
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog implements core.Catalog.
func New ¶
func New(db *sql.DB, client TMDB, cfg config.Catalog, log *slog.Logger, opts ...Option) (*Catalog, error)
New creates a catalogue. client may be nil (mirror-only / offline mode).
func (*Catalog) ByExternalID ¶
ByExternalID looks up by imdb ("tt123") or tvdb id.
func (*Catalog) CachedTitle ¶
CachedTitle returns a mirrored title without contacting TMDB.
func (*Catalog) Collection ¶
func (c *Catalog) Collection(ctx context.Context, tmdbCollection int64) (string, []core.Title, error)
Collection returns a TMDB franchise and its parts sorted by release date.
func (*Catalog) CrowdRecommendations ¶
func (c *Catalog) CrowdRecommendations(ctx context.Context, key core.RatingKey, pages int, fetch bool) (titles []core.Title, fetched bool, err error)
CrowdRecommendations returns TMDB's crowd co-engagement list for a title (/recommendations only: never metadata similarity), best first, from up to pages pages (1–2). A stored list younger than the crowd TTL with enough pages is served from the local mirror. Otherwise, with fetch set, TMDB is asked and fetched reports it (callers budget those calls); without fetch, or when TMDB fails, a stale list is served when there is one and nil otherwise. Titles not yet released are dropped.
func (*Catalog) Facet ¶
func (c *Catalog) Facet(ctx context.Context, t core.MediaType, facet string) ([]core.FacetValue, error)
Facet returns value counts over the browsable set.
func (*Catalog) Grandchildren ¶
Grandchildren: all episodes of a show.
func (*Catalog) List ¶
func (c *Catalog) List(ctx context.Context, list string, t core.MediaType, limit int) ([]core.Title, error)
List returns TMDB curated/trending lists with a short in-memory TTL.
func (*Catalog) NextEpisode ¶
NextEpisode returns the next regular episode (specials, season 0, are skipped as a target; calling it on a special jumps to S1E1-order sequence).
func (*Catalog) RecentEpisodes ¶
func (c *Catalog) RecentEpisodes(ctx context.Context, show core.RatingKey, since time.Time) ([]core.Title, error)
RecentEpisodes returns only local, released episode identities for artwork badges. Callers apply viewer state through core.State instead of a SQL join.
func (*Catalog) Run ¶
Run performs an initial sync and then refreshes on RefreshInterval until ctx ends. Intended to be run in its own goroutine by the app wiring. With WithResumeSchedule the initial sync waits until the interval has passed since the last recorded sync.
func (*Catalog) Search ¶
func (c *Catalog) Search(ctx context.Context, query string, types []core.MediaType, limit int) ([]core.Title, error)
Search reaches all of TMDB; matched titles join the browsable set.
func (*Catalog) SeedGenres ¶
SeedGenres pre-populates the genre id->name cache (tests, offline warm-up).
func (*Catalog) SyncProgress ¶
func (c *Catalog) SyncProgress() SyncProgress
SyncProgress returns the current sync progress snapshot.
func (*Catalog) UpdateConfig ¶
UpdateConfig swaps the catalogue config (wire to config.Store.Subscribe).
type Estimate ¶
type Estimate struct {
Movies int `json:"movies"`
Shows int `json:"shows"`
Total int `json:"total"`
}
Estimate is a rough catalogue-size prediction for given thresholds. It is a heuristic from TMDB's documented popularity behaviour (a daily- recomputed, heavily right-skewed score) and public catalogue counts. Treat it as order-of-magnitude guidance for the setup UI, not a measurement.
func EstimateCatalogSize ¶
EstimateCatalogSize estimates browsable titles with MeetsThreshold's OR rule. The union of the popularity set and vote set overlaps substantially; the estimate uses max + 40% of the smaller set as the non-overlapping remainder.
type Mirror ¶
type Mirror struct {
// contains filtered or unexported fields
}
Mirror exposes bounded local reads for catalogue consumers. It owns schema knowledge; callers never compose SQL against catalog_* tables.
func (*Mirror) CollectionArt ¶
func (*Mirror) Fingerprint ¶
func (m *Mirror) Fingerprint(ctx context.Context) (MirrorFingerprint, error)
func (*Mirror) Franchises ¶
type MirrorFingerprint ¶
type Option ¶
type Option func(*Catalog)
Option customises a Catalog.
func WithCrowdTTL ¶
WithCrowdTTL overrides how long co-engagement lists stay fresh.
func WithListTTL ¶
func WithResumeSchedule ¶
func WithResumeSchedule() Option
WithResumeSchedule makes Run continue the refresh schedule recorded in the database instead of syncing as soon as it starts: the first sync waits until RefreshInterval has passed since the last successful sync (by any node). A cluster uses it because Run restarts on every leader handoff; with no recorded sync Run still syncs at once.
func WithStaleAfter ¶
func WithSyncYears ¶
WithSyncYears bounds the year slices used when discover exceeds 500 pages.
type Stats ¶
type Stats struct {
Movies int `json:"movies"`
Shows int `json:"shows"`
Seasons int `json:"seasons"`
Episodes int `json:"episodes"`
BrowsableMovies int `json:"browsableMovies"`
BrowsableShows int `json:"browsableShows"`
Collections int `json:"collections"`
LastSync time.Time `json:"lastSync,omitempty"`
Sync SyncProgress `json:"sync"`
}
Stats is the admin-UI snapshot of the mirror.
type SyncProgress ¶
type SyncProgress struct {
Running bool `json:"running"`
Phase string `json:"phase,omitempty"` // e.g. "movie/popularity", "tv/votes/1994"
PagesDone int `json:"pagesDone"`
TitlesSeen int `json:"titlesSeen"`
TitlesAdded int `json:"titlesAdded"`
StartedAt time.Time `json:"startedAt,omitempty"`
FinishedAt time.Time `json:"finishedAt,omitempty"`
LastError string `json:"lastError,omitempty"`
}
SyncProgress describes a running or last-finished catalogue sync.
type TMDB ¶
type TMDB interface {
MovieDetails(ctx context.Context, id int64) (*tmdb.MovieDetails, error)
TVDetails(ctx context.Context, id int64) (*tmdb.TVDetails, error)
SeasonDetails(ctx context.Context, tvID int64, season int) (*tmdb.SeasonDetails, error)
EpisodeExternalIDs(ctx context.Context, tvID int64, season, episode int) (*tmdb.ExternalIDs, error)
CollectionDetails(ctx context.Context, id int64) (*tmdb.CollectionDetails, error)
DiscoverMovies(ctx context.Context, p tmdb.DiscoverParams) (*tmdb.Paged[tmdb.Movie], error)
DiscoverTV(ctx context.Context, p tmdb.DiscoverParams) (*tmdb.Paged[tmdb.TVShow], error)
SearchMovies(ctx context.Context, q string, page int) (*tmdb.Paged[tmdb.Movie], error)
SearchTV(ctx context.Context, q string, page int) (*tmdb.Paged[tmdb.TVShow], error)
SearchMulti(ctx context.Context, q string, page int) (*tmdb.Paged[tmdb.MultiResult], error)
TrendingMovies(ctx context.Context, window string, page int) (*tmdb.Paged[tmdb.Movie], error)
TrendingTV(ctx context.Context, window string, page int) (*tmdb.Paged[tmdb.TVShow], error)
TrendingAll(ctx context.Context, window string, page int) (*tmdb.Paged[tmdb.MultiResult], error)
MovieList(ctx context.Context, list string, page int) (*tmdb.Paged[tmdb.Movie], error)
TVList(ctx context.Context, list string, page int) (*tmdb.Paged[tmdb.TVShow], error)
MovieSimilar(ctx context.Context, id int64, page int) (*tmdb.Paged[tmdb.Movie], error)
MovieRecommendations(ctx context.Context, id int64, page int) (*tmdb.Paged[tmdb.Movie], error)
TVSimilar(ctx context.Context, id int64, page int) (*tmdb.Paged[tmdb.TVShow], error)
TVRecommendations(ctx context.Context, id int64, page int) (*tmdb.Paged[tmdb.TVShow], error)
FindByExternalID(ctx context.Context, source, id string) (*tmdb.FindResult, error)
Genres(ctx context.Context, mediaType string) ([]tmdb.Genre, error)
}
TMDB is the subset of the TMDB client the catalogue needs. *tmdb.Client satisfies it.