plex

package
v1.1.12 Latest Latest
Warning

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

Go to latest
Published: Jun 10, 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 inviolate item 9. 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 TLS-skip semantics, 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 TLS verification regardless of the client's SKIP_TLS_VERIFICATION setting — 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. Runtime-types-p1 split this 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 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 (runtime-types-p2). 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 (inviolate item 9).

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 pre-extraction strconv.Atoi+fmt.Errorf stanzas it replaces in library.go (Episode, ShowEpisodes, SeasonEpisodes, ShowMetadata, RecentlyAdded). The inviolate contract item 5 (WARN/ERROR log-key stability) includes error messages that scrapers may grep for; keeping the exact text means no Loki query or dashboard breaks on the collapse.

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. Runtime-types-p1 split this 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. Runtime-types-p1 split this 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