Help us shape the future of Go! Take the 2026 Go Developer Survey

plex

package
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: GPL-3.0 Imports: 74 Imported by: 0

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

View Source
const APIVersion = "1.2.3"

APIVersion is the PMS API version Ether implements (X-Plex-Pms-Api-Version).

View Source
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

func RouteInventory added in v0.3.0

func RouteInventory() conform.RouteInventory

RouteInventory enumerates the same registration tree used by the server, without starting background workers or needing runtime dependencies.

Types

type AccessPolicy

type AccessPolicy = experience.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 {
	ArtworkImages       *artworkservice.RemoteCache
	ArtworkPalettes     *artworkservice.PaletteCache
	SessionCoordination *sessions.Coordination
	FavoriteShows       func(context.Context, *core.User) (map[core.RatingKey]bool, error)
	FilterAvailable     func(context.Context, []core.Title) []core.Title
	PrioritizeAvailable func(context.Context, []core.Title) []core.Title
	EpisodeOrder        *episodeorder.Service
	PlexGUID            *plexguid.Service
	PlexMeta            *plexmeta.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
	// DecisionTraces is the latest resolution for a title, copied into a
	// support capture. Nil leaves playback unchanged.
	DecisionTraces core.DecisionTraceSource
	// 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

	// ApplyClientRules adjusts caps for the owner's quality rules. Nil leaves
	// the request caps unchanged. The app wires resolver.ApplyClientRules so
	// this package stays outside the resolver.
	ApplyClientRules func(config.Quality, core.ClientCaps, *core.User) core.ClientCaps
	// 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. The app wires the metadata route so this package
	// does not import the egress policy.
	HTTPClient *http.Client
	// DirectHTTP proxies trailer bytes. Nil uses the default transport.
	// The app wires the direct route so this package does not import egress.
	DirectHTTP *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
	// Dashboard is this node's in-memory Plex Web Dashboard store. Nil is
	// replaced with a process-local store at NewServer. Statistics are not
	// clustered; a client reads the node it connected to.
	Dashboard *stats.Dashboard
	// Resources is this node's host sample ring for /statistics/resources.
	Resources *hoststat.Resources
	// Support records neutral request and playback facts. Nil leaves playback unchanged.
	Support *diagnostics.Recorder
	// TracePlayback logs HLS/transcode requests when ETHER_TRACE_PLAYBACK=1.
	// It does not change responses.
	TracePlayback bool
}

Deps are the server's dependencies. Catalog, State, Auth and Playback are required; the rest degrade gracefully when nil.

type Directive

type Directive struct {
	Verb string
	Args map[string]string
}

Directive is one parsed X-Plex-Client-Profile-Extra directive, e.g. add-limitation(scope=videoCodec&scopeName=h264&...).

func ParseProfileExtra

func ParseProfileExtra(s string) []Directive

ParseProfileExtra splits a profile-extra string into directives. The value may arrive URL-encoded; directives are separated by "+".

type DiscoveryFeatures

type DiscoveryFeatures = discovery.Features

DiscoveryFeatures is the shared discovery service adapted by Plex.

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 Frontend added in v0.3.0

type Frontend struct {
	NewServer  func() (*Server, error)
	Server     *Server
	WatchState *state.State
	// ExplicitWatchOnly preserves spike mode: only cross-surface scrobbles refresh.
	ExplicitWatchOnly bool
	StatusFunc        func(context.Context) frontend.Status
	ListenersFunc     func() []frontend.ListenerSpec
}

Frontend adapts the existing PMS handler to the frontend registry. Unmount stops this mount's broker sessions, encoders, trickplay, and downloads, and drops its watch subscription. The process-owned server stays up so an in-flight request can finish.

func (Frontend) Describe added in v0.3.0

func (f Frontend) Describe() frontend.Descriptor

func (Frontend) Mount added in v0.3.0

func (f Frontend) Mount(ctx context.Context, host frontend.Host) (frontend.Instance, error)

type FrontendArtwork added in v0.3.0

type FrontendArtwork struct {
	Server        *Server
	Variants      func(*core.Title, string) (*tmdb.Images, bool)
	Metadata      func(context.Context, frontend.ArtworkRequest, frontend.Image) frontend.Image
	VirtualSeason func(context.Context, *core.User, core.RatingKey) (*core.Title, error)
	URLImages     interface {
		GetUntrustedURL(context.Context, string) ([]byte, string, error)
	}
	Raster *artwork.SVGRasterizer
}

FrontendArtwork is a compatibility adapter for callers already holding a Plex server. Shared runtime constructs artworkservice.Source directly.

func (FrontendArtwork) ChannelImage added in v0.3.0

func (a FrontendArtwork) ChannelImage(v *core.Viewer, c livetv.Channel) frontend.Image

func (FrontendArtwork) List added in v0.3.0

func (FrontendArtwork) Read added in v0.3.0

func (FrontendArtwork) Warm added in v0.3.0

func (a FrontendArtwork) Warm(t core.Title, d core.Device)

type Hooks

type Hooks struct {
	// OnClientSeen receives the client identifier after authentication.
	OnClientSeen func(clientID string)
	// 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 MarkerProvider interface {
	Markers(context.Context, core.RatingKey, core.MediaInfo) ([]markers.Marker, error)
}

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

	// Capability is set when authentication used a stream grant or other
	// session-scoped credential, not a user token. Only transcode
	// session/segment handlers may serve a capability-scoped request.
	Capability bool
}

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

func FromContext(ctx context.Context) *Request

FromContext returns the request context attached by the middleware.

func ParseRequest

func ParseRequest(r *http.Request, trusted ...netip.Prefix) *Request

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).

func (*Request) ClientCapsWith added in v0.3.0

func (pr *Request) ClientCapsWith(remoteMaxKbps int, overrides []core.ClientCapabilityOverride) core.ClientCaps

ClientCapsWith is ClientCaps with owner registry overrides applied before the request's own profile and capability headers.

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 NewServer

func NewServer(d Deps) *Server

NewServer builds the PMS API handler.

func (*Server) Close

func (s *Server) Close() error

Close stops background goroutines and disconnects notification clients.

func (*Server) Closed added in v0.3.0

func (s *Server) Closed() bool

Closed reports whether Close has begun.

func (*Server) DownloadsAllowed added in v0.3.0

func (s *Server) DownloadsAllowed(u *core.User) bool

DownloadsAllowed exposes the same admission decision for informational frontend capability reporting; the download handler still enforces it.

func (*Server) LibrarySections added in v0.2.14

func (s *Server) LibrarySections() []Section

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) NoteOwnerStop added in v0.3.0

func (s *Server) NoteOwnerStop(id, reason string)

NoteOwnerStop tells the Plex client why a stream is ending. The shared broker stops the source.

func (*Server) NotifyLiveLineup added in v0.3.0

func (s *Server) NotifyLiveLineup()

NotifyLiveLineup tells connected Plex clients to reload the DVR lineup and guide. Channel create and delete call it through LiveTV.SetOnChange.

func (*Server) ServeHTTP

func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP implements http.Handler.

func (*Server) UsePlaybackBroker added in v0.3.0

func (s *Server) UsePlaybackBroker(b frontend.Sessions)

UsePlaybackBroker attaches the shared session broker. Mounted Plex playback publishes through it. Timeline progress and stops are recorded only there.

func (*Server) UsePlexStreams added in v0.3.0

func (s *Server) UsePlexStreams(api sessions.PlexStreamAPI)

UsePlexStreams binds visible stream ids and sidecar reads to the broker. Pass sessions.BindPlexStreams(broker).

func (*Server) WatchStateChanged added in v0.2.11

func (s *Server) WatchStateChanged(userID int64, key core.RatingKey)

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

type SubtitleSource interface {
	OpenFormat(string, string) (io.ReadCloser, string, error)
}

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 SubtitleUpload added in v0.3.0

type SubtitleUpload interface {
	UploadSubtitle(ctx context.Context, t *core.Title, u *core.User, filename, format, language string, body []byte) (core.StreamInfo, error)
}

SubtitleUpload is optionally implemented by Deps.Subtitles: Plex Web's "Upload Subtitles" (POST /library/metadata/{key}/subtitles).

type TrackPreferences

TrackPreferences is optional. Selections are stream slice positions; saved show choices match language/flags so they survive changes in release order.

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.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL