Documentation
¶
Overview ¶
Package mediaserver: Manager owns connection testing + Plex PIN auth for Plex / Jellyfin / Emby entries. CRUD over the entries lives in the YAML config (config.AddMediaServer etc.); handlers call those directly. The Dispatcher (this package) owns runtime fan-out.
Index ¶
- Variables
- type DeepLinker
- type Dispatcher
- type Jellyfin
- func (j *Jellyfin) MovieDeepLink(ctx context.Context, _ string, tmdbID uint32, title string, year uint16) (string, error)
- func (j *Jellyfin) RefreshLibrary(ctx context.Context, _, _ string) error
- func (j *Jellyfin) TVShowDeepLink(ctx context.Context, _ string, tvdbID uint32, title string, year uint16) (string, error)
- func (j *Jellyfin) TestConnection(ctx context.Context) error
- type Manager
- type PlayOnResult
- type PlayOnStatus
- type Plex
- func (p *Plex) ListSections(ctx context.Context) ([]Section, error)
- func (p *Plex) MovieDeepLink(ctx context.Context, hintSection string, tmdbID uint32, title string, ...) (string, error)
- func (p *Plex) RefreshLibrary(ctx context.Context, libraryPath, sectionKey string) error
- func (p *Plex) TVShowDeepLink(ctx context.Context, hintSection string, tvdbID uint32, title string, ...) (string, error)
- func (p *Plex) TestConnection(ctx context.Context) error
- type PlexClientCreds
- type PlexPin
- type PlexPinResult
- type Section
- type Server
- type TestParams
Constants ¶
This section is empty.
Variables ¶
var ( ErrServerNotFound = errors.New("media server not found") ErrInvalidServerType = errors.New("invalid server type") ErrTestFailed = errors.New("connection test failed") ErrMovieNotFound = errors.New("movie not found on media server") ErrShowNotFound = errors.New("series not found on media server") )
Functions ¶
This section is empty.
Types ¶
type DeepLinker ¶
type DeepLinker struct {
// contains filtered or unexported fields
}
DeepLinker resolves per-server deep links for a movie. Used by GET /movies/{id}/play-on. The enabled-server set is read live from config.
func NewDeepLinker ¶
func NewDeepLinker( builder func(config.MediaServerEntry) (Server, error), ) *DeepLinker
func (*DeepLinker) Resolve ¶
func (l *DeepLinker) Resolve( ctx context.Context, tmdbID uint32, title string, year uint16, ) []PlayOnResult
Resolve fans out to every enabled media server in parallel, resolving a movie deep link per server. Per-server errors never propagate; they become PlayOnResult entries with Status = unavailable so the UI can render them.
func (*DeepLinker) ResolveTV ¶
func (l *DeepLinker) ResolveTV( ctx context.Context, tvdbID uint32, title string, year uint16, ) []PlayOnResult
ResolveTV is the series counterpart of Resolve.
type Dispatcher ¶
type Dispatcher struct{}
Dispatcher fans RefreshLibrary across all enabled media servers, read live from config per invocation.
func NewDispatcher ¶
func NewDispatcher() *Dispatcher
func (*Dispatcher) RefreshAll ¶
func (d *Dispatcher) RefreshAll(ctx context.Context, libraryPath string) error
type Jellyfin ¶
type Jellyfin struct {
// contains filtered or unexported fields
}
func NewJellyfin ¶
func (*Jellyfin) MovieDeepLink ¶
func (j *Jellyfin) MovieDeepLink( ctx context.Context, _ string, tmdbID uint32, title string, year uint16, ) (string, error)
MovieDeepLink returns a Jellyfin/Emby web URL pointing at the movie's details page. Tries TMDB-provider-id match first (exact), falls back to title + year. Both Jellyfin and Emby share this URL hash route. Returns ErrMovieNotFound when no item matches.
func (*Jellyfin) RefreshLibrary ¶
type Manager ¶
type Manager interface {
Test(ctx context.Context, p TestParams) error
TestByName(ctx context.Context, name string) error
DiscoverSections(ctx context.Context, p TestParams) ([]Section, error)
// BeginPlexPin starts a Plex PIN OAuth flow. Caller opens PlexPin.AuthURL
// in a browser popup; admin authenticates with Plex; caller polls
// PollPlexPin(pin.ID) until AuthToken is non-empty (5-minute window).
BeginPlexPin(ctx context.Context) (PlexPin, error)
PollPlexPin(ctx context.Context, pinID uint64) (PlexPinResult, error)
}
Manager is the consumer-facing surface used by HTTP handlers for behavioral operations. Persistence of media-server entries is via config mutate.
type PlayOnResult ¶
type PlayOnResult struct {
Name string
ServerType string
URL string
Fallback bool
Status PlayOnStatus
}
PlayOnResult is one server's resolved link or fallback for a single movie.
type PlayOnStatus ¶
type PlayOnStatus string
PlayOnStatus describes the resolution outcome for one media server.
const ( StatusResolved PlayOnStatus = "resolved" StatusFallback PlayOnStatus = "fallback" )
type Plex ¶
type Plex struct {
// contains filtered or unexported fields
}
func (*Plex) MovieDeepLink ¶
func (p *Plex) MovieDeepLink( ctx context.Context, hintSection string, tmdbID uint32, title string, year uint16, ) (string, error)
MovieDeepLink returns a Plex Web URL pointing at the movie's details page. Enumerates all movie-type sections on the server (Plex commonly splits movies across "Movies", "4K", "Documentaries", etc.) and queries each in turn — `hintSection`, if set and present in the list, is checked first to minimise round-trips on the happy path. Within each section it tries TMDB-GUID match first (exact), then title+year (fuzzy). Returns ErrMovieNotFound when no section yields a match.
func (*Plex) RefreshLibrary ¶
func (*Plex) TVShowDeepLink ¶
func (p *Plex) TVShowDeepLink( ctx context.Context, hintSection string, tvdbID uint32, title string, year uint16, ) (string, error)
TVShowDeepLink mirrors MovieDeepLink for TV-type sections: matches on the TVDB guid first, then title+year, and builds the same details URL.
type PlexClientCreds ¶
PlexClientCreds carries the per-install identity Plex requires on every PIN request. Stored once-per-install in config (PlexClientID) and used as X-Plex-Client-Identifier; X-Plex-Product/Version identify Streamline.
type PlexPin ¶
type PlexPin struct {
ID uint64
Code string
AuthURL string
// ClientID is the X-Plex-Client-Identifier the flow used. Surfaced so a
// read-only deploy operator can commit it to media_server.plex_client_id.
ClientID string
}
PlexPin is the result of starting a PIN-based OAuth flow. AuthURL is the URL the admin's browser must open (popup); ID is then polled until Plex fills in authToken.
type PlexPinResult ¶
PlexPinResult is the polled state of a PIN. AuthToken is empty until the user completes the auth flow on app.plex.tv. Expired is true when Plex returns 404 or the recorded ExpiresAt has passed.
type Section ¶
Section is a Plex library section: the unit RefreshLibrary targets when given a non-empty sectionKey. Locations are filesystem paths Plex itself sees (which may differ from Streamline's own mounts).
type Server ¶
type Server interface {
TestConnection(ctx context.Context) error
// RefreshLibrary triggers a re-scan on the server. sectionKey is the
// Plex-internal section identifier when targeting a specific library;
// pass "" to fall back to legacy behavior (path-match for Plex, full
// refresh for Jellyfin/Emby).
RefreshLibrary(ctx context.Context, libraryPath, sectionKey string) error
// MovieDeepLink returns a web URL pointing at the movie's details page on
// this server. Returns ErrMovieNotFound when no item matches. hintSection
// is the configured Plex library section (key) to check first; Jellyfin
// and Emby ignore it.
MovieDeepLink(
ctx context.Context,
hintSection string,
tmdbID uint32,
title string,
year uint16,
) (string, error)
// TVShowDeepLink returns a web URL pointing at the series' details page on
// this server. Returns ErrShowNotFound when no item matches. hintSection
// is the configured Plex TV library section (key) to check first; Jellyfin
// and Emby ignore it.
TVShowDeepLink(
ctx context.Context,
hintSection string,
tvdbID uint32,
title string,
year uint16,
) (string, error)
}
func BuildServer ¶
func BuildServer(ms config.MediaServerEntry) (Server, error)