plex

package
v0.2.7 Latest Latest
Warning

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

Go to latest
Published: Oct 22, 2026 License: GPL-3.0 Imports: 61 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

This section is empty.

Types

type AccessPolicy

type AccessPolicy interface {
	Allowed(*core.User, *core.Title) bool
}

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 {
	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
	// 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
}

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 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 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
}

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

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) RecoverTranscode added in v0.2.4

func (s *Server) RecoverTranscode(ctx context.Context, id, inputURL string, at time.Duration) error

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

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

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.

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 SubtitleSource

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

SubtitleSource resolves cached OpenSubtitles and synchronized sidecars.

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