plex

package
v1.5.8 Latest Latest
Warning

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

Go to latest
Published: Jul 14, 2026 License: GPL-2.0, GPL-3.0 Imports: 16 Imported by: 0

Documentation

Overview

Package plex holds the HTTP client and response types for the Plex Media Server API. Consumers get a typed *Client with library, history, identity, stream-selection, and shared-server methods. Value types (Episode, Stream, Media, Part, Label) live in plex-language-sync/internal/streams; this package owns the container + admin-facing types (Account, User, Section, Session, HistoryItem, Show, Season) and the MediaContainer wrapper.

Index

Constants

View Source
const (
	// TypeEpisode is the Plex metadata "type" string for episode items,
	// used when filtering MediaContainer responses by item type.
	TypeEpisode = "episode"

	// MetadataTypeEpisode is the numeric type ID for episode items used
	// in /library/sections/{id}/all?type=... URL parameters.
	MetadataTypeEpisode = 4

	// SectionTypeShow is the Plex library-section "type" string for TV
	// show sections, used when filtering library sections to TV shows
	// only.
	SectionTypeShow = "show"
)

Plex wire-protocol constants. These strings/numbers appear in the Plex HTTP API and are a frozen wire contract. Consumers (main, config, scheduler, notify, sync, this package's own library.go) import these rather than redeclaring them locally.

Variables

View Source
var ErrNotFound = errors.New("not found")

ErrNotFound is returned when Plex responds with 404 (missing metadata / session / etc.). Callers detect it with errors.Is(err, plex.ErrNotFound).

Functions

func SwapTVClient

func SwapTVClient(replacement *http.Client) (restore func())

SwapTVClient replaces the package-level plex.tv HTTP client with the supplied one and returns a function that restores the original. Intended for tests that need to point shared-server lookups at a local httptest server; production code never calls this.

func WarnIfPlaintextURL

func WarnIfPlaintextURL(u *url.URL)

WarnIfPlaintextURL emits a startup warning when the Plex URL is http:// to a non-loopback, non-docker-DNS host. In that case the X-Plex-Token header transits the network unencrypted. Trusted on a LAN-only proxy bridge, but dangerous when the published image is pointed at a remote Plex server without a TLS proxy.

Types

type Account

type Account struct {
	Name string `json:"name"`
	ID   int    `json:"id"`
}

Account is a Plex system account returned by GET /accounts.

type Client

type Client struct {
	// contains filtered or unexported fields
}

Client is an HTTP client for a single Plex Media Server base URL + auth token. Use NewClient or NewClientForUser.

func NewClient

func NewClient(serverURL, token, caCertPath string) (*Client, error)

NewClient parses serverURL, validates scheme, and returns a Client configured with the given token and TLS behaviour. When caCertPath is non-empty, the PEM file at that path is loaded into the TLS RootCAs pool so verification stays ON, pinned to that CA — recommended for users with self-signed Plex certificates. Empty caCertPath uses the OS trust store (works for plex.direct + any publicly-issued cert; works as a no-op for plain http:// URLs). Returns an error on invalid URL, unsupported scheme, missing cert file, or unparseable PEM; the caller (main.go) is responsible for logging and exiting.

func NewClientForUser

func NewClientForUser(baseURL *url.URL, token, caCertPath string) (*Client, error)

NewClientForUser creates a Client using a different token but the same server base URL and TLS settings as an existing client. Same caCertPath semantics as NewClient.

func NewClientFromHTTP

func NewClientFromHTTP(baseURL *url.URL, token string, hc *http.Client) *Client

NewClientFromHTTP builds a Client from an already-parsed base URL and a caller-supplied http.Client. Intended for tests that want to point a Client at an httptest.Server — production code should use NewClient.

func (*Client) BaseURL

func (c *Client) BaseURL() *url.URL

BaseURL returns the server's base URL. Used by callers that need to derive a websocket URL or log the host.

func (*Client) DisableSubtitles

func (c *Client) DisableSubtitles(ctx context.Context, partID int) error

DisableSubtitles turns subtitles off for a media part.

func (*Client) Episode

func (c *Client) Episode(ctx context.Context, rk RatingKey) (*streams.Episode, error)

Episode fetches episode (or any library item) metadata by rating key. Returns ErrNotFound when the item is missing. /library/metadata/{key} is type-agnostic; ShowMetadata wraps this variant for show-level lookups.

func (*Client) HTTPClient

func (c *Client) HTTPClient() *http.Client

HTTPClient returns the underlying *http.Client. Exposed so the WebSocket listener can dial the notifications endpoint with the same transport (matching CA-trust, timeouts, and redirect policy) rather than spinning up a second client.

func (*Client) History

func (c *Client) History(ctx context.Context, sinceUnix int64) ([]HistoryItem, error)

History fetches recent play history since the given unix timestamp.

Plex supports filter operators on many fields; the documented syntax for "viewedAt >= X" is literally `viewedAt>=X` with a single `>` and a literal (unencoded) operator. A prior version used `viewedAt>>=` (double `>`), which Plex silently ignores — the server returned the full history (21k+ entries on a long-lived server), overflowed the 10 MB read cap in doJSON, and surfaced as a daily WARN ("unexpected end of JSON input") in Loki. Go's url.Parse preserves `>=` as-is, so the single-char fix correctly reaches the server and the response is filtered server-side.

func (*Client) LoggedUser

func (c *Client) LoggedUser(ctx context.Context) (*User, error)

LoggedUser resolves the admin user by looking up the myplex account username and matching it against the system accounts list.

func (*Client) RecentlyAdded

func (c *Client) RecentlyAdded(ctx context.Context, sectionKey RatingKey, sinceUnix int64) ([]streams.Episode, error)

RecentlyAdded fetches recently added episodes from a library section, filtered server-side by addedAt >= sinceUnix.

func (*Client) SeasonEpisodes

func (c *Client) SeasonEpisodes(ctx context.Context, rk RatingKey) ([]streams.Episode, error)

SeasonEpisodes returns the episodes of a single season (children).

func (*Client) ServerIdentity

func (c *Client) ServerIdentity(ctx context.Context) (*ServerIdentity, error)

ServerIdentity returns the Plex server's identity (friendly name, machine ID, version) from GET /.

func (*Client) SetAudioStream

func (c *Client) SetAudioStream(ctx context.Context, partID, streamID int) error

SetAudioStream selects the audio stream for a media part.

func (*Client) SetSubtitleStream

func (c *Client) SetSubtitleStream(ctx context.Context, partID, streamID int) error

SetSubtitleStream selects the subtitle stream for a media part.

func (*Client) SharedUserTokens

func (c *Client) SharedUserTokens(ctx context.Context, machineIdentifier string) ([]SharedServerXML, error)

SharedUserTokens fetches shared user tokens from the plex.tv shared_servers endpoint. This calls the plex.tv API (not the local server) and always uses full TLS verification (there is no skip option) — plex.tv is a public endpoint and the admin token must never be forwarded through a skipped-verification transport or a redirect.

func (*Client) ShowEpisodes

func (c *Client) ShowEpisodes(ctx context.Context, rk RatingKey) ([]streams.Episode, error)

ShowEpisodes returns every episode in a show (allLeaves).

func (*Client) ShowMetadata

func (c *Client) ShowMetadata(ctx context.Context, rk RatingKey) (*Show, error)

ShowMetadata fetches the show-level metadata (labels, library) for a show. /library/metadata/{key} returns whatever type the key points to, so this delegates to the same endpoint as Episode but decodes into *Show. Split off from Episode: a show response does not have Media/Part/Stream, so typing it as *Show instead of *Episode keeps the field set honest for callers (e.g. shouldIgnoreShow reads only LibraryTitle + Label).

func (*Client) ShowSections

func (c *Client) ShowSections(ctx context.Context) ([]Section, error)

ShowSections returns the TV-show library sections.

func (*Client) Token

func (c *Client) Token() string

Token returns the token the client uses. Exposed for the user-manager eviction path, which compares a cached client's token against a freshly refreshed user-info entry.

func (*Client) UserFromSession

func (c *Client) UserFromSession(ctx context.Context, clientIdentifier string) (userID, username string, err error)

UserFromSession finds the user associated with a clientIdentifier by querying active sessions. Returns the user ID and username.

type HTTPStatusError added in v1.5.7

type HTTPStatusError struct {
	Method string
	Path   string
	Status string
	Code   int
}

HTTPStatusError is returned for a non-200, non-404 Plex response. It carries the status code so callers can classify the failure: a 4xx (bad token / auth / wrong endpoint) will not self-heal, while a 5xx (Plex up but not ready) may recover. The startup connect classifier in package main uses errors.As to distinguish fatal (4xx) from transient (5xx) initial-connection failures.

func (*HTTPStatusError) Error added in v1.5.7

func (e *HTTPStatusError) Error() string

type HistoryItem

type HistoryItem struct {
	RatingKey        string          `json:"ratingKey"`
	Type             string          `json:"type"`
	LibraryTitle     string          `json:"librarySectionTitle"`
	AccountID        streams.FlexInt `json:"accountID"`
	LibrarySectionID streams.FlexInt `json:"librarySectionID"`
}

HistoryItem is one entry from GET /status/sessions/history/all.

type RatingKey

type RatingKey string

RatingKey is a typed Plex ratingKey — the opaque numeric string Plex uses to address episodes, seasons, shows, and other library items. The on-disk and wire representation is always a string; this type exists to prevent ratingKey values from being conflated with other string keys (userID, sessionKey) at module boundaries and to give callers a single place to validate that a value is a well-formed numeric key.

Methods on RatingKey intentionally avoid allocation: String returns the underlying string, and Validate parses without copying. The api.PlexReader interface and the *plex.Client methods (Episode, ShowEpisodes, SeasonEpisodes, ShowMetadata, RecentlyAdded) take RatingKey at the boundary so validation happens once via RatingKey.Validate rather than being repeated per-method with strconv.Atoi. Wire-origin strings (streams.Episode.RatingKey, plex.Section.Key, plex.HistoryItem.RatingKey) stay typed as string in their struct definitions — the plex.RatingKey wrap happens at the call site, which preserves the Plex JSON wire format.

func (RatingKey) String

func (r RatingKey) String() string

String returns the ratingKey as a plain string for APIs that accept strings (HTTP path interpolation, log values, cache keys).

func (RatingKey) Validate

func (r RatingKey) Validate() error

Validate reports whether the ratingKey is a non-empty numeric string. Plex ratingKeys are always numeric strings in practice; a malformed key indicates a programming error (e.g., a userID leaked into a ratingKey slot) that is worth surfacing rather than forwarding to the Plex API as a malformed URL path.

The error format is deliberately `invalid rating key %q` — byte-for- byte identical to the five strconv.Atoi+fmt.Errorf stanzas it replaces in library.go (Episode, ShowEpisodes, SeasonEpisodes, ShowMetadata, RecentlyAdded). That error text is a stable log-key contract that scrapers may grep for; keeping it byte-for-byte means no Loki query or dashboard breaks.

type Season

type Season struct {
	RatingKey       string          `json:"ratingKey"`
	ParentRatingKey string          `json:"parentRatingKey"`
	Title           string          `json:"title"`
	Index           streams.FlexInt `json:"index"`
}

Season is the season-level metadata returned by GET /library/metadata/{key} when the key points to a season. Split off from Episode for callers that only need the navigational spine (parent key, season index) without the whole media/part/stream graph.

type Section

type Section struct {
	Key   string `json:"key"`
	Title string `json:"title"`
	Type  string `json:"type"`
}

Section is a library section returned by GET /library/sections.

type ServerIdentity

type ServerIdentity struct {
	FriendlyName      string `json:"friendlyName"`
	MachineIdentifier string `json:"machineIdentifier"`
	Version           string `json:"version"`
}

ServerIdentity is returned by GET /.

type Session

type Session struct {
	User struct {
		ID    string `json:"id"`
		Title string `json:"title"`
	} `json:"User"`
	Player struct {
		MachineIdentifier string `json:"machineIdentifier"`
	} `json:"Player"`
}

Session represents a single active session from GET /status/sessions.

type SharedServerXML

type SharedServerXML struct {
	UserID      string `xml:"userID,attr"`
	Username    string `xml:"username,attr"`
	AccessToken string `xml:"accessToken,attr"`
}

SharedServerXML is one <SharedServer> element from shared_servers.

type SharedServersXML

type SharedServersXML struct {
	XMLName      xml.Name          `xml:"MediaContainer"`
	SharedServer []SharedServerXML `xml:"SharedServer"`
}

SharedServersXML is the XML response from plex.tv shared_servers.

type Show

type Show struct {
	RatingKey        string          `json:"ratingKey"`
	Title            string          `json:"title"`
	LibraryTitle     string          `json:"librarySectionTitle"`
	Label            []streams.Label `json:"Label"`
	LibrarySectionID streams.FlexInt `json:"librarySectionID"`
}

Show is the show-level metadata returned by GET /library/metadata/{key} when the key points to a TV show. Split off from Episode so callers asking "what are the show's labels?" don't receive an Episode-typed value.

type User

type User struct {
	ID   string
	Name string
}

User represents the resolved admin (or any) Plex user.

Jump to

Keyboard shortcuts

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