Documentation
¶
Overview ¶
Package plex is Ether's Plex Media Server front end: the HTTP API that official Plex apps (Web, iOS, Apple TV, Android, TVs) talk to. Everything behind it is reached through internal/core interfaces.
Index ¶
- Constants
- type AccessPolicy
- type CollectionArtworker
- type Deps
- type Directive
- type DiscoveryFeatures
- type ExtrasProvider
- type Hooks
- type Identity
- type MarkerProvider
- type Request
- type Section
- type Server
- func (s *Server) Close() error
- func (s *Server) LibrarySections() []Section
- func (s *Server) RecoverTranscode(ctx context.Context, id, inputURL string, at time.Duration) error
- func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
- func (s *Server) StopPlayback(id, reason string)
- func (s *Server) TranscodeFor(playSessionID string) (core.HLSSession, bool)
- func (s *Server) WatchStateChanged(userID int64, key core.RatingKey)
- type SessionToucher
- type SubtitleCatalog
- type SubtitleOffer
- type SubtitleSearch
- type SubtitleSource
- type SubtitleTimeline
- type TrackPreferences
Constants ¶
const APIVersion = "1.2.3"
APIVersion is the PMS API version Ether implements (X-Plex-Pms-Api-Version).
const DefaultPMSVersion = "1.43.4.10903-e5521bd8c"
DefaultPMSVersion is reported when Identity.Version is empty. Clients gate features on the server version, so it must look like a current PMS build.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type AccessPolicy ¶
AccessPolicy adds owner-defined restrictions to the mandatory title guard.
type CollectionArtworker ¶
type CollectionArtworker interface {
CollectionArtwork(ctx context.Context, user *core.User, key core.RatingKey, element string, width int) (data []byte, contentType string, ok bool, err error)
}
CollectionArtworker is optionally implemented by Deps.Collections to serve generated collection posters (internal/collections renders them with internal/artwork). ok=false falls back to the TMDB artwork path.
type Deps ¶
type Deps struct {
FilterAvailable func(context.Context, []core.Title) []core.Title
PrioritizeAvailable func(context.Context, []core.Title) []core.Title
EpisodeOrder *episodeorder.Service
PlexGUID *plexguid.Service
Discovery *DiscoveryFeatures
LiveTV *livetv.Service
AccessPolicy AccessPolicy
Catalog core.Catalog
Collections core.Collections
VibeSearch core.VibeSearcher
Recommender core.Recommender
State core.State
Playlists core.Playlists
Auth core.Auth
Playback core.Playback
Transcoder core.Transcoder
// Variants lists distinct release versions for "Play Version" detail
// pages (optional: without it, detail pages stay single-Media).
Variants core.VariantResolver
// Downloads remuxes resolved sources to temp MP4s for the Download
// Queue API; nil disables downloads (allowSync stays "0").
Downloads core.DownloadRemuxer
TrackPreferences TrackPreferences
Markers MarkerProvider
Subtitles SubtitleSource
Extras ExtrasProvider
Trickplay core.TrickplayProvider
// Config returns the current settings snapshot.
Config func() config.Config
// OwnerSubscription returns the current entitlement snapshot from plex.tv.
OwnerSubscription func() (active bool, features []string)
// ImageURL builds TMDB image URLs; defaults to image.tmdb.org.
ImageURL core.ImageURLFunc
Logger *slog.Logger
Identity Identity
Hooks Hooks
// Sections overrides the default Movies (1) and TV Shows (2) sections.
Sections []Section
// HTTPClient fetches artwork for the image proxy; defaults to a client
// with a 20 s timeout.
HTTPClient *http.Client
// ImageCacheBytes bounds the in-memory artwork cache (default 128 MiB).
ImageCacheBytes int64
// DB persists derived artwork data (UltraBlurColors) in plex_* tables.
// Optional: without it, colours are kept in memory only.
DB *sql.DB
// DisableEnrichment turns off the background title-detail and
// UltraBlurColors work (the spike test library has nothing to fetch).
DisableEnrichment bool
// Cluster, when set (clustered nodes only; requires DB), shares play
// sessions, play queues, terminations and notifications with the other
// nodes. Nil keeps everything in this process.
Cluster clusterbus.Node
// SessionHeartbeat is how often a clustered node refreshes its shared
// play sessions (default 10s).
SessionHeartbeat time.Duration
// Now is the clock (tests).
Now func() time.Time
// Support records neutral request and playback facts. Nil leaves playback unchanged.
Support *diagnostics.Recorder
}
Deps are the server's dependencies. Catalog, State, Auth and Playback are required; the rest degrade gracefully when nil.
type Directive ¶
Directive is one parsed X-Plex-Client-Profile-Extra directive, e.g. add-limitation(scope=videoCodec&scopeName=h264&...).
func ParseProfileExtra ¶
ParseProfileExtra splits a profile-extra string into directives. The value may arrive URL-encoded; directives are separated by "+".
type DiscoveryFeatures ¶
type DiscoveryFeatures struct {
Watchlist *watchlist.Service
Ratings *ratings.Service
Overlays *overlays.Service
Personal *personalize.Discovery
LLM *llm.Service
Localize func(context.Context, *core.Title, string) (*core.Title, error)
// contains filtered or unexported fields
}
DiscoveryFeatures is optional. Viewers use these features through ordinary Plex metadata, Home, search and continue-watching endpoints.
func (*DiscoveryFeatures) Run ¶
func (d *DiscoveryFeatures) Run(ctx context.Context)
Run is the sole metadata background worker, bounded and stopped with the app.
type ExtrasProvider ¶
type ExtrasProvider interface {
Enabled() bool
List(ctx context.Context, parent *core.Title, lang string) ([]extras.Extra, error)
Lookup(key core.RatingKey) (extras.Extra, bool)
Resolve(ctx context.Context, e extras.Extra) (extras.Resolved, error)
PrewarmBytes() int64
}
ExtrasProvider is the extras service surface the front end needs (*extras.Service satisfies it).
type Hooks ¶
type Hooks struct {
// OnTimeline is called for every timeline update (prefetch uses it).
OnTimeline func(user *core.User, key core.RatingKey, offset, duration time.Duration, state string)
// OnScrobble is called when a user marks an item watched.
OnScrobble func(user *core.User, key core.RatingKey)
}
Hooks are optional callbacks into other components. They run on their own goroutine and must be safe for concurrent use.
type Identity ¶
type Identity struct {
MachineIdentifier string
FriendlyName string
Version string // PMS-style version string
Platform string // "MacOSX", "Windows", "Linux"
PlatformVersion string
// MyPlexSubscription reports whether the owner has Plex Pass; Ether
// reports this honestly from plex.tv.
MyPlexSubscription bool
OwnerFeatures []string
}
Identity is how the server presents itself. Empty fields fall back to the config snapshot (friendly name, machine identifier) or sensible defaults.
type MarkerProvider ¶
type Request ¶
type Request struct {
Token string
ClientID string // X-Plex-Client-Identifier
Product string // X-Plex-Product
Version string // X-Plex-Version
Platform string // X-Plex-Platform
PlatformVersion string // X-Plex-Platform-Version
Device string // X-Plex-Device
DeviceName string // X-Plex-Device-Name
Model string // X-Plex-Model
Vendor string // X-Plex-Device-Vendor
Language string // X-Plex-Language
Marketplace string // X-Plex-Marketplace
Provides string // X-Plex-Provides
Features string // X-Plex-Features
ProfileExtra string // X-Plex-Client-Profile-Extra
ProfileName string // X-Plex-Client-Profile-Name
ClientCapabilities string // X-Plex-Client-Capabilities (legacy)
SessionID string // X-Plex-Session-Identifier
PMSAPIVersion string // X-Plex-Pms-Api-Version
// Paging (X-Plex-Container-Start/Size); HasPage is false when the client
// did not ask for a window.
Start int
Size int
HasPage bool
Format model.Format
RemoteIP netip.Addr
Remote bool // not on a private/loopback network
User *core.User
}
Request is the parsed Plex request context: every X-Plex-* header (or its query-string equivalent), paging, the output format and the remote address.
func FromContext ¶
FromContext returns the request context attached by the middleware.
func ParseRequest ¶
ParseRequest builds the request context from an HTTP request. Forwarded addresses are considered only for a loopback peer (a local reverse proxy).
func (*Request) ClientCaps ¶
func (pr *Request) ClientCaps(remoteMaxKbps int) core.ClientCaps
ClientCaps derives core.ClientCaps for the request. remoteMaxKbps caps the bitrate of remote clients (0 = unlimited).
type Section ¶
type Section struct {
ID int
Type core.MediaType // movie or show
Title string
UUID string // stable; derived from the machine identifier when empty
Language string
}
Section is a library section exposed to clients.
type Server ¶
type Server struct {
// contains filtered or unexported fields
}
Server is the PMS API handler. It is an http.Handler; call Close on shutdown to stop background work and notification streams.
func (*Server) LibrarySections ¶ added in v0.2.14
LibrarySections returns the canonical section identities for account registration. Titles follow the live config so renames publish to plex.tv. The copy prevents publishers from changing local libraries.
func (*Server) RecoverTranscode ¶ added in v0.2.4
RecoverTranscode maps the client's encoder ID to its playback session. Playback rechecks the input generation before attempting recovery.
func (*Server) ServeHTTP ¶
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)
ServeHTTP implements http.Handler.
func (*Server) StopPlayback ¶
StopPlayback ends an owner-selected source and tells the official app why. On a clustered node a session this node does not serve (a playback or live TV session ID from the cluster-wide status) is stopped by the node that does.
func (*Server) TranscodeFor ¶
func (s *Server) TranscodeFor(playSessionID string) (core.HLSSession, bool)
TranscodeFor returns the running transcode session fed by a playback session. Transcode sessions are keyed by the client's session id, so playback needs this to move ffmpeg to a new input on mid-stream failover.
func (*Server) WatchStateChanged ¶ added in v0.2.11
WatchStateChanged invalidates client library metadata after a committed watch update. A playing notification only updates session status; clients can keep their cached Continue Watching shelf until a library timeline event arrives.
type SessionToucher ¶
type SessionToucher interface {
Touch(sessionID string)
}
SessionToucher is optionally implemented by core.Playback to keep a play session alive on timeline updates.
type SubtitleCatalog ¶ added in v0.2.21
type SubtitleCatalog interface {
CachedSidecars(ctx context.Context, t *core.Title, u *core.User, embedded []core.StreamInfo) []core.StreamInfo
}
SubtitleCatalog is optionally implemented by Deps.Subtitles: the sidecars already cached for a title and viewer, without network access, skipping streams embedded already lists (by ExternalURL) or covers (by language).
type SubtitleOffer ¶ added in v0.2.21
type SubtitleOffer struct {
ID int64 // provider file id, passed back to DownloadSubtitle
Language string // ISO 639-1
Title string // release or file name
Provider string // "OpenSubtitles"
Score int
HearingImpaired bool
Forced bool
PerfectMatch bool // matched the playing file's hash or release
}
SubtitleOffer is one subtitle search result.
type SubtitleSearch ¶ added in v0.2.21
type SubtitleSearch interface {
SearchSubtitles(ctx context.Context, t *core.Title, u *core.User, lang, release string) ([]SubtitleOffer, error)
// DownloadSubtitle fetches an offer returned by SearchSubtitles for t
// and returns its sidecar stream; core.ErrNotFound for unknown offers.
DownloadSubtitle(ctx context.Context, t *core.Title, u *core.User, id int64) (core.StreamInfo, error)
}
SubtitleSearch is optionally implemented by Deps.Subtitles: Plex's on-demand subtitle search and pick.
type SubtitleSource ¶
SubtitleSource resolves cached OpenSubtitles and synchronized sidecars.
type SubtitleTimeline ¶ added in v0.2.21
type SubtitleTimeline interface {
OpenFormatAt(id, format string, offset time.Duration) (io.ReadCloser, string, error)
}
SubtitleTimeline is optionally implemented by Deps.Subtitles: a sidecar with its cues moved back by offset, for a transcode that starts there.
type TrackPreferences ¶
type TrackPreferences interface {
Select(context.Context, int64, core.RatingKey, core.MediaInfo, string) (trackprefs.Selection, error)
Remember(context.Context, int64, core.RatingKey, string, *core.StreamInfo) error
GetRules(context.Context, int64) (trackprefs.Rules, error)
}
TrackPreferences is optional. Selections are stream slice positions; saved show choices match language/flags so they survive changes in release order.
Source Files
¶
- artwork_policy.go
- background.go
- caps.go
- cluster.go
- collection_artwork.go
- continue_next.go
- convert.go
- discovery_features.go
- enrich.go
- handlers_dash.go
- handlers_downloads.go
- handlers_extras.go
- handlers_hubs.go
- handlers_indexes.go
- handlers_library.go
- handlers_metadata.go
- handlers_playlists.go
- handlers_server.go
- handlers_state.go
- home_layout.go
- images.go
- library_guid.go
- livetv_api.go
- livetv_native.go
- livetv_queue.go
- metadata_features.go
- middleware.go
- notify.go
- personal_hooks.go
- playback.go
- playback_lifecycle.go
- playqueue.go
- request.go
- routes.go
- safety.go
- scheduled.go
- server.go
- slug.go
- stop.go
- stores.go
- stream_auth.go
- streams_features.go
- subtitles.go
- support_observe.go
- transcode_failure.go
- ultrablur.go
- variants.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package model holds the Plex Media Server response models and the encoder that renders one model as either PMS-style XML or PMS-style JSON.
|
Package model holds the Plex Media Server response models and the encoder that renders one model as either PMS-style XML or PMS-style JSON. |