Documentation
¶
Overview ¶
Package core holds the domain types and the interfaces between Ether's components. It has no dependencies on other Ether packages, so every component can import it. Changing a type here is a contract change: keep edits additive.
Index ¶
- Constants
- Variables
- func CheckReleaseHealth(ctx context.Context, hc HealthChecker, releaseID string, nzb []byte) (bool, error)
- func ClassifyDevice(product, platform, device string) string
- func DaypartAt(t time.Time) string
- func DefaultRanking(rules []ReleaseRule) []string
- func ForegroundReserve(ctx context.Context) int
- func InheritBackground(dst, src context.Context) context.Context
- func IsBackgroundCheck(ctx context.Context) bool
- func IsGrantCredential(s string) bool
- func IsWeekend(t time.Time) bool
- func PlexSaferRating(ctx context.Context) bool
- func SourceRevision(s *PlaySession) string
- func SpendBackground(ctx context.Context, resource, source string, amount int64) error
- func StreamKey(ctx context.Context) any
- func TargetReleaseID(releaseID string, t ReleaseTarget) string
- func ValidateRanking(ranking []string, rules []ReleaseRule) error
- func WithBackgroundBudget(ctx context.Context, budget BackgroundBudget) context.Context
- func WithForegroundReserve(ctx context.Context, percent int) context.Context
- func WithPlexSaferRating(ctx context.Context) context.Context
- func WithReadRetirement(ctx context.Context, tracker *ReadRetirement) context.Context
- func WithStreamKey(ctx context.Context, key any) context.Context
- type ActiveUserSource
- type ActivityDay
- type AlignRequest
- type ArticleFetcher
- type ArticlePart
- type ArtworkAccessPolicy
- type Auth
- type AuthoritativeTitleRefresher
- type AvailabilitySource
- type BackgroundBudget
- type BatchWatchState
- type BitrateAccessPolicy
- type BrowseQuery
- type BufferedInputSwapper
- type BurstArticleFetcher
- type CachePlayRecorder
- type CachedTitleSource
- type Catalog
- type CatalogSchedule
- type ChannelPreparer
- type Chapter
- type ClientCapabilityOverride
- type ClientCapabilityProfiles
- type ClientCaps
- type ClientCodecProfile
- type ClientContainerProfile
- type ClientDirectPlayProfile
- type ClientProfileCondition
- type ClientSubtitleProfile
- type ClientTranscodeProfile
- type Collection
- type CollectionArtwork
- type CollectionArtworkSource
- type CollectionLayoutSource
- type CollectionPlaceholder
- type CollectionPreview
- type CollectionRotate
- type CollectionRow
- type CollectionRows
- type CollectionRule
- type CollectionSchedule
- type CollectionSource
- type CollectionSpec
- type CollectionSpecSource
- type CollectionTargets
- type CollectionTemplate
- type Collections
- type ContextReaderAt
- type ContextualRecommender
- type CreditFilter
- type CustomFormat
- type DASHSession
- type DamageReporter
- type DateFilter
- type DecideOptions
- type Decision
- type DecisionCandidate
- type DecisionKind
- type DecisionTrace
- type DecisionTraceSource
- type DelegationAuth
- type Device
- type DirectPlayRetrier
- type DownloadAccessPolicy
- type DownloadRemuxRequest
- type DownloadRemuxer
- type DurablePrefetcher
- type EncoderInputLease
- type EncoderRetirement
- type Engine
- type ExactVariantPlayback
- type FacetValue
- type Filter
- type FormatSpecification
- type GoodputSession
- type HLSIndependentSegments
- type HLSLadderSession
- type HLSRequest
- type HLSRung
- type HLSSession
- type HTTPSession
- type HWAccel
- type HealthChecker
- type HistoryEntry
- type HomeCandidateSource
- type HomeLayout
- type HomeLayoutSource
- type HomePreview
- type HomeRow
- type HomeSituation
- type Hub
- type HubContext
- type HubImpression
- type HubItemSource
- type IDs
- type Identity
- type ImageURLFunc
- type ImpressionSink
- type Indexer
- type IntentTracker
- type KeyKind
- type KeyframePoint
- type LayoutPage
- type LayoutTuning
- type LayoutWhen
- type LibraryExclusion
- type LikesState
- type LocalFileSource
- type LookupResult
- type MarkedPlaylists
- type MediaInfo
- type MediaSource
- type MediaType
- type MetadataReaderAt
- type MicroReason
- type MicroReasoner
- type NeutralEntryRef
- type NeutralHomeLayoutSource
- type NeutralHomeRow
- type NeutralImpression
- type NeutralImpressionSink
- type OriginSource
- type OwnedEncoderSession
- type OwnedSourcePlayback
- type OwnedTranscoder
- type Page
- type Person
- type PersonalScorer
- type PlaySession
- type Playback
- type PlaybackAccessPolicy
- type PlaybackEncoderInputs
- type PlaybackPosition
- type PlaybackPreparer
- type PlaybackRevisionPin
- type PlaybackSourceHistory
- type PlaybackSourceObservation
- type PlaybackSourceSnapshot
- type PlaybackTimeline
- type Playlist
- type Playlists
- type PolicyHomeCandidateSource
- type PostPlayPick
- type PostPlayer
- type PrefetchReaderAt
- type PrewarmOptions
- type Prewarmer
- type Priority
- type ProcessCPUTime
- type ProcessIdentity
- type ProcessPeakMemory
- type Protocol
- type QualityProfile
- type RankerFeature
- type RankerInsight
- type RatingKey
- func CollectionKey(id int64) RatingKey
- func EphemeralSmartKey(seq int64) RatingKey
- func EpisodeKey(show int64, season, episode int) RatingKey
- func ExtraKey(id int64) RatingKey
- func LocalKey(id int64) RatingKey
- func MovieKey(tmdb int64) RatingKey
- func ParseRatingKey(s string) (RatingKey, error)
- func PlaylistKey(id int64) RatingKey
- func SeasonKey(show int64, season int) RatingKey
- func ShowKey(tmdb int64) RatingKey
- func SmartKey(id int64) RatingKey
- func (k RatingKey) Episode() int
- func (k RatingKey) ExtraID() int64
- func (k RatingKey) IsEphemeral() bool
- func (k RatingKey) Kind() KeyKind
- func (k RatingKey) Parent() RatingKey
- func (k RatingKey) Season() int
- func (k RatingKey) String() string
- func (k RatingKey) TMDB() int64
- func (k RatingKey) Valid() bool
- type ReadRetirement
- type Recommender
- type RecoveryBuffer
- type RecoveryBufferSource
- type Release
- type ReleaseBlockChecker
- type ReleaseCondition
- type ReleaseFeed
- type ReleaseHealthChecker
- type ReleaseInfo
- type ReleaseRule
- type ReleaseSizeSource
- type ReleaseTarget
- type ReleaseVariant
- type RemuxRequirer
- type RepairEvent
- type RepairReporter
- type RepairWindow
- type RescueIndexer
- type Resolution
- type ResolveRequest
- type Resolver
- type RowDescriptor
- type RowInsight
- type RowPolicy
- type RowPurpose
- type SearchCacheRefiller
- type SearchRequest
- type SectionCandidateSource
- type SegmentCache
- type SegmentPresence
- type SessionActivity
- type ShowTrajectory
- type SortOrder
- type SortSpec
- type Source
- type SourceDeliveryObserver
- type SourceRetirement
- type State
- type StoredTitleLookup
- type StreamInfo
- type StreamingIndexer
- type StreamingRescueIndexer
- type StringFilter
- type SubtitleExtractor
- type SurfaceScopedPlayback
- type TasteDecade
- type TasteHabits
- type TasteLanguage
- type TasteOverride
- type TastePerson
- type TasteProfile
- type TasteWeight
- type TimelineAligner
- type Title
- type TransactionalMarkedPlaylists
- type Transcoder
- type TrickplayCanceler
- type TrickplayLease
- type TrickplayLeaser
- type TrickplayProvider
- type TrickplaySource
- type User
- type UserPolicySource
- type UserTargets
- type VariantPlayback
- type VariantResolver
- type VibeQuery
- type VibeRefiner
- type VibeSearcher
- type VideoEnhancement
- type VideoEnhancementSupport
- type Viewer
- type ViewerActivity
- type ViewerInvalidator
- type ViewerLayout
- type ViewerStats
- type WarmProbeWaiter
- type WarmProber
- type WatchStatus
Constants ¶
const ( ProtocolUsenet = "" // the zero value: an NZB from a Newznab indexer ProtocolTorrent = "torrent" // a Torznab result streamed through a debrid service // ProtocolUnstated is a filename preview with no protocol fact. // Live releases keep the empty-string Usenet default; this value // exists so a preview cannot report that default as evidence. ProtocolUnstated = "unstated" // ProtocolHTTP is a stream URL a Stremio addon resolved itself (often // through the addon owner's own debrid account), read with HTTP range // requests. It needs no debrid account in Ether (additive). The same // name is Plex for Mac / Desktop's protocol=http conversion (a chunked // Matroska stream on /video/:/transcode/universal/start). ProtocolHTTP = "http" )
Release protocols (Release.Protocol).
const ( DeviceTV = "tv" DeviceMobile = "mobile" DeviceWeb = "web" DeviceDesktop = "desktop" )
Device classes for HubContext.Device.
const ( DaypartMorning = "morning" // 05:00–11:59 DaypartAfternoon = "afternoon" // 12:00–16:59 DaypartEvening = "evening" // 17:00–21:59 DaypartLate = "late" // 22:00–04:59 )
Dayparts for HubContext.Daypart, in the server's local time.
const ( RowSourceEngine = "engine" // generated by the personalization engine RowSourceOwner = "owner" // an owner-designed collection RowSourcePlex = "plex" // built by the Plex front end (Continue Watching, playlists) )
Row sources for HomeRow.Source.
const ( ProtocolHLS = "hls" ProtocolDASH = "dash" )
Streaming protocols of HLSRequest.Protocol.
const ( PrewarmDetail = "detail" // a detail page was opened PrewarmTrailer = "trailer" // a trailer or Cinema Trailer for the title is playing PrewarmPostPlay = "postplay" // the viewer is near the end of something and this is up next PrewarmBrowse = "browse" // a home/section row is on screen; open the debrid link only )
Reasons for PrewarmOptions.Reason.
const ( EphemeralSmartBase int64 = 800_000_000_000_000 EphemeralSmartEnd int64 = 900_000_000_000_000 )
EphemeralSmartBase and EphemeralSmartEnd bound the KindSmart payloads reserved for ephemeral generated collections. The range stops where personalize's Year in Review collections begin (payload 9*10^14 and up), and database smart-collection ids stay far below it.
const ( RankRulePrefix = "rule:" RankLanguage = "language" RankConnection = "connection" RankResolution = "resolution" RankReleaseType = "releaseType" RankHDR = "hdr" RankVerified = "verified" RankVideoCodec = "videoCodec" RankAudioFormat = "audioFormat" RankSize = "size" )
Ranking ladder step keys for QualityProfile.Ranking.
const EncoderInputScopeHeader = "X-Ether-Encoder-Input"
EncoderInputScopeHeader is reserved for a manager-issued input lease. It is never provider metadata, client authorization, a source lease or a URL token.
const GrantCredentialPrefix = "eg1_"
GrantCredentialPrefix reserves Ether-issued credentials from external providers.
const MaxVariants = 7
MaxVariants caps the Play Version picker: Auto, up to three same-quality alternatives (the owner's setting), and up to three tiers and cuts. The resolver and the Plex front end both read it so the two caps move together.
const PausedSessionRetention = 30 * time.Minute
PausedSessionRetention bounds a silent pause without treating it as an abandoned stream. Explicit stop still closes immediately.
const ProbeFactsVersion = 2
ProbeFactsVersion is the generation of facts a probe is expected to carry, including H.264/HEVC reference frames and descriptive audio handler titles. Persisted probes from an older generation are cache misses.
const RowSourcePrecomposed = "precomposed"
RowSourcePrecomposed identifies utility rows already assembled by a host service. Their ordering and items are not generated by the recommendation engine. RowSourcePlex remains supported for existing data and clients.
Variables ¶
var ( ErrNotFound = errors.New("not found") ErrNotAvailable = errors.New("not available yet") // no acceptable release exists ErrUnreleased = errors.New("title has not been released") ErrArticleMissing = errors.New("article missing on all providers") ErrArticleCorrupt = errors.New("corrupt article or media data") ErrReleaseRejected = errors.New("release cannot be streamed") ErrBudgetExhausted = errors.New("indexer daily budget exhausted") ErrStreamLimit = errors.New("stream limit reached") // ErrPolicyUnconfirmed means the durable policy store could not be read. // Callers may keep an unrestricted cached decision. Restricted viewers fail closed. ErrPolicyUnconfirmed = errors.New("policy store unavailable") )
var DefaultRankingSteps = []string{ RankLanguage, RankConnection, RankResolution, RankReleaseType, RankHDR, RankVerified, RankVideoCodec, RankAudioFormat, RankSize, }
DefaultRankingSteps is the built-in ranking ladder order after any Prefer rules.
var ErrDebridAuth = errors.New("debrid: authentication failed")
ErrDebridAuth is a debrid service rejecting the configured API key (or an account that cannot use the API). A configuration problem, never a release failure.
var ErrDownloadBudget = errors.New("download: temporary disk budget exceeded")
ErrDownloadBudget is returned when a download would exceed the temporary disk budget for remuxed files.
var ErrDownloadNeedsTranscode = errors.New("download: source codecs cannot be copied to MP4")
ErrDownloadNeedsTranscode is returned by DownloadRemuxer when the resolved streams cannot be copied or converted into an MP4 the requesting client's download profile plays.
var ErrDownloadQueued = fmt.Errorf("sent to the debrid service to download: %w", ErrNotCached)
ErrDownloadQueued reports that an uncached torrent was handed to a debrid account to download (cached-only off): not playable yet, but it will be.
var ErrEncoderInputPending = errors.New("encoder input producers are pending")
var ErrEncoderInputUnverified = errors.New("encoder input producer retirement is unverified")
var ErrEncoderPending = errors.New("encoder retirement is pending")
var ErrForegroundOnly = errors.New("background check cannot decide this source")
ErrForegroundOnly reports a speculative check that could not decide a source without work only a foreground attempt may do (adding a torrent to a debrid account, say). Like ErrBudgetExhausted it is never evidence of source absence: a foreground caller tries the source itself.
var ErrNoSources = fmt.Errorf("no indexers to search: %w", ErrNotAvailable)
ErrNoSources reports that there is nothing to search: no enabled indexer at all. A configuration problem, not proof a title has no release, so callers must not record the title as unavailable.
var ErrNoTorrentSources = fmt.Errorf("debrid has no torrent indexer to search: %w", ErrNoSources)
ErrNoTorrentSources reports that debrid is the only way to play (no Usenet provider) but no enabled indexer returns torrents (Torznab, a Stremio addon or a torrent built-in site).
var ErrNotCached = fmt.Errorf("not cached by any debrid provider: %w", ErrNotAvailable)
ErrNotCached reports that no debrid provider can serve a torrent release instantly. It is a per-release skip, never proof the release is broken, so it wraps ErrNotAvailable and is not a permanent failure.
var ErrSourceChanged = errors.New("playback: source revision changed")
ErrSourceChanged signals an absent or different source revision.
Functions ¶
func CheckReleaseHealth ¶
func CheckReleaseHealth(ctx context.Context, hc HealthChecker, releaseID string, nzb []byte) (bool, error)
CheckReleaseHealth runs hc.CheckRelease when hc implements it, else hc.Check.
func ClassifyDevice ¶
ClassifyDevice maps a Plex client's X-Plex-Product, X-Plex-Platform and X-Plex-Device headers onto a hub form factor (DeviceTV, DeviceMobile, DeviceWeb, DeviceDesktop). Playback codecs, HDR and subtitle support are not decided here; those come from the client capability registry.
- TV: Apple TV, Android TV / Google TV / Fire TV / Shield, Roku, smart TVs (Samsung Tizen, LG webOS, Vizio, Hisense, Sony...), game consoles (Xbox, PlayStation) and set-top boxes.
- Desktop: Plex HTPC, Plex for Windows/Mac/Linux, Plex Media Player.
- Web: Plex Web in any browser.
- Mobile: Plex for iOS / Android phones and tablets.
Unknown clients fall back on their platform, then on DeviceWeb.
func DaypartAt ¶
DaypartAt returns the daypart of t in t's own location: morning 05:00–11:59, afternoon 12:00–16:59, evening 17:00–21:59, late 22:00–04:59.
func DefaultRanking ¶ added in v0.3.0
func DefaultRanking(rules []ReleaseRule) []string
DefaultRanking returns today's default ladder order: each Prefer rule in rules (in slice order), followed by DefaultRankingSteps.
func ForegroundReserve ¶ added in v0.2.8
func InheritBackground ¶ added in v0.2.8
InheritBackground carries admission policy into a shared worker whose lifetime belongs to the engine, without tying that worker to one waiter's cancellation.
func IsBackgroundCheck ¶ added in v0.2.8
func IsGrantCredential ¶ added in v0.3.0
IsGrantCredential reports whether a credential uses Ether's reserved prefix.
func IsWeekend ¶
IsWeekend reports whether t (in its own location) falls in the weekend viewing window: Friday from 17:00 through Sunday. Friday night behaves like a weekend night (films, longer sessions), Sunday daytime does too.
func PlexSaferRating ¶ added in v0.3.0
PlexSaferRating reports that catalogue queries on ctx should hide titles whose cached Plex rating exceeds the viewer's limit.
func SourceRevision ¶ added in v0.3.0
func SourceRevision(s *PlaySession) string
SourceRevision identifies a release/file without exposing its name or upstream identifiers. Local revisions detect filesystem changes; they do not claim content immutability. Unsupported or unknown sources are empty.
func SpendBackground ¶ added in v0.2.8
func TargetReleaseID ¶
func TargetReleaseID(releaseID string, t ReleaseTarget) string
TargetReleaseID derives a stable release ID for one episode of a multi-file release, so health, pins, cache and bad marks apply to the episode file rather than the whole pack.
func ValidateRanking ¶ added in v0.3.0
func ValidateRanking(ranking []string, rules []ReleaseRule) error
ValidateRanking checks an explicit ranking ladder against a profile's rules. An empty ladder is valid and means DefaultRanking(rules).
func WithBackgroundBudget ¶ added in v0.2.8
func WithBackgroundBudget(ctx context.Context, budget BackgroundBudget) context.Context
func WithForegroundReserve ¶ added in v0.2.8
func WithPlexSaferRating ¶ added in v0.3.0
WithPlexSaferRating marks a request so catalogue SQL also applies cached Plex content-rating levels. Other frontends leave the context unset.
func WithReadRetirement ¶ added in v0.3.0
func WithReadRetirement(ctx context.Context, tracker *ReadRetirement) context.Context
WithReadRetirement attaches request-scoped retirement tracking.
func WithStreamKey ¶ added in v0.3.0
WithStreamKey tags ctx with the playback stream its reads serve, so the Usenet fetcher can tell a stalled read from ordinary variance between concurrent viewers. key must be comparable (a pointer, typically); nil leaves ctx unchanged.
Types ¶
type ActiveUserSource ¶ added in v0.2.7
ActiveUserSource checks current server membership for delegated stream access.
type ActivityDay ¶
type ActivityDay struct {
Date string `json:"date"` // YYYY-MM-DD, server local time
Plays int `json:"plays"`
Hours float64 `json:"hours"`
UniqueViewers int `json:"uniqueViewers"`
}
ActivityDay is one day of server-wide viewing.
type AlignRequest ¶
type AlignRequest struct {
Key RatingKey `json:"key"`
From Release `json:"from"`
To Release `json:"to"`
FromDuration time.Duration `json:"fromDuration,omitempty"`
ToDuration time.Duration `json:"toDuration,omitempty"`
}
AlignRequest names two releases of the same title whose timelines should be matched (for example the failing and the replacement release of a mid-stream failover, or a marker source's reference cut and the release being played).
type ArticleFetcher ¶
type ArticleFetcher interface {
// Body returns the decoded payload of one article (one NZB segment).
// Returns ErrArticleMissing when no provider has it.
Body(ctx context.Context, messageID string, groups []string, prio Priority) ([]byte, error)
// BodyPart is Body plus the article's yEnc =ybegin/=ypart header, which
// gives the segment's exact byte range inside the posted file.
BodyPart(ctx context.Context, messageID string, groups []string, prio Priority) ([]byte, ArticlePart, error)
// Stat reports whether any provider has the article.
Stat(ctx context.Context, messageID string) (bool, error)
}
ArticleFetcher fetches and yEnc-decodes articles across the configured providers, primary first, backfilling from block accounts.
type ArticlePart ¶
type ArticlePart struct {
Name string `json:"name"`
FileSize int64 `json:"fileSize"`
Part int `json:"part"`
Total int `json:"total"`
Begin int64 `json:"begin"`
End int64 `json:"end"`
}
ArticlePart is the yEnc header of one article. Begin and End are 1-based inclusive offsets in the posted file, as in =ypart; for single-part posts Begin is 1 and End is FileSize.
type ArtworkAccessPolicy ¶ added in v0.2.7
ArtworkAccessPolicy exposes the optional Restricted capability.
type AuthoritativeTitleRefresher ¶ added in v0.2.37
type AuthoritativeTitleRefresher interface {
RefreshTitle(ctx context.Context, key RatingKey, persist bool) (*Title, error)
}
AuthoritativeTitleRefresher fetches current movie or show details and optionally persists them. It never falls back to cached data on failure and does not apply release visibility.
type AvailabilitySource ¶ added in v0.2.7
AvailabilitySource exposes the optional Available capability.
type BackgroundBudget ¶ added in v0.2.8
BackgroundBudget is an optional admission hook for speculative work. Ordinary playback has no hook. Implementations must be concurrency safe; denied work returns ErrBudgetExhausted and is never evidence of source absence.
type BatchWatchState ¶ added in v0.3.0
type BatchWatchState interface {
ScrobbleMany(context.Context, int64, []RatingKey) error
UnscrobbleMany(context.Context, int64, []RatingKey) error
}
BatchWatchState updates a collection of watched states atomically.
type BitrateAccessPolicy ¶ added in v0.2.7
BitrateAccessPolicy exposes the optional BitrateLimit capability.
type BrowseQuery ¶
type BufferedInputSwapper ¶ added in v0.2.8
type BufferedInputSwapper interface {
SwapInputBuffered(context.Context, string, MediaInfo, time.Duration) error
}
BufferedInputSwapper preserves published media before starting replacement input at the contiguous buffer boundary. The caller must verify identity timeline alignment at the playhead and buffer boundary; differing trailing durations alone do not prevent reuse.
type BurstArticleFetcher ¶ added in v0.2.8
type BurstArticleFetcher interface {
BodyPartBurst(ctx context.Context, messageID string, groups []string, prio Priority, until time.Time) ([]byte, ArticlePart, error)
}
BurstArticleFetcher optionally borrows idle live-reserved capacity for a short, explicitly bounded bulk-read burst. Live waiters retain precedence. The deadline limits new burst admission, not already transmitted bytes.
type CachePlayRecorder ¶ added in v0.2.7
CachePlayRecorder exposes the optional RecordPlay capability.
type CachedTitleSource ¶ added in v0.2.7
CachedTitleSource exposes the optional CachedTitles capability.
type Catalog ¶
type Catalog interface {
Get(ctx context.Context, key RatingKey) (*Title, error)
// Children: seasons of a show, episodes of a season.
Children(ctx context.Context, key RatingKey) ([]Title, error)
// Grandchildren: all episodes of a show.
Grandchildren(ctx context.Context, key RatingKey) ([]Title, error)
Browse(ctx context.Context, q BrowseQuery) (Page, error)
// Search reaches all of TMDB; matched titles join the browsable set.
Search(ctx context.Context, query string, types []MediaType, limit int) ([]Title, error)
// Lists from TMDB: "trending_day", "trending_week", "top_rated", "now_playing", "popular", "airing_today", "upcoming".
List(ctx context.Context, list string, t MediaType, limit int) ([]Title, error)
Similar(ctx context.Context, key RatingKey, limit int) ([]Title, error)
Collection(ctx context.Context, tmdbCollection int64) (name string, items []Title, err error)
// Facets for filter UIs: "genre", "year", "decade", "contentRating", "studio", "country".
Facet(ctx context.Context, t MediaType, facet string) ([]FacetValue, error)
// NextEpisode returns the episode after the given one, or ErrNotFound.
NextEpisode(ctx context.Context, episode RatingKey) (*Title, error)
// ByExternalID looks up a title by imdb ("tt123") or tvdb id.
ByExternalID(ctx context.Context, source, id string) (*Title, error)
}
Catalog is Ether's library: a local mirror of a TMDB slice plus on-demand fetches for anything else.
type CatalogSchedule ¶ added in v0.2.45
CatalogSchedule exposes metadata-only placeholders when the owner opts in. Only dated, unaired episodes of an already airing regular season are returned. Callers must authorize the parent season and each episode for the viewer, render no media/playback links, and use the same scope for artwork. Ordinary Catalog methods remain released-only; this interface never authorizes playback.
type ChannelPreparer ¶ added in v0.2.7
type ChannelPreparer interface {
PrepareChannel(context.Context, *User, RatingKey, ClientCaps, string) (*PlaySession, error)
}
ChannelPreparer exposes the optional PrepareChannel capability.
type ClientCapabilityOverride ¶ added in v0.3.0
type ClientCapabilityOverride struct {
ID string `json:"id,omitempty"`
Product string `json:"product,omitempty"`
Platform string `json:"platform,omitempty"`
Device string `json:"device,omitempty"`
// Version is the minimum client version (dotted numbers) this override requires.
Version string `json:"version,omitempty"`
VideoCodecs []string `json:"videoCodecs,omitempty"`
AudioCodecs []string `json:"audioCodecs,omitempty"`
Containers []string `json:"containers,omitempty"`
SubtitleCodecs []string `json:"subtitleCodecs,omitempty"`
DolbyVisionProfiles []int `json:"dolbyVisionProfiles,omitempty"`
MaxHeight int `json:"maxHeight,omitempty"`
MaxBitrateKbps int `json:"maxBitrateKbps,omitempty"`
HDR10 *bool `json:"hdr10,omitempty"`
DolbyVision *bool `json:"dolbyVision,omitempty"`
Notes string `json:"notes,omitempty"`
}
ClientCapabilityOverride is an owner edit of one registry client. Nil slices and zero numbers leave the registry value in place. A client that declares the same fact at runtime still wins.
type ClientCapabilityProfiles ¶ added in v0.3.0
type ClientCapabilityProfiles struct {
DirectPlay []ClientDirectPlayProfile
Transcoding []ClientTranscodeProfile
Subtitles []ClientSubtitleProfile
Containers []ClientContainerProfile
Codecs []ClientCodecProfile
MaxStaticBitrate, MusicStreamingTranscodingBitrate, MaxStaticMusicBitrate int
}
ClientCapabilityProfiles are declared together by a single client. Nil profile collections mean omitted; an explicit empty collection remains empty. A nil pointer on ClientCaps preserves legacy protocol behavior.
type ClientCaps ¶
type ClientCaps struct {
Profiles *ClientCapabilityProfiles `json:"profiles,omitempty"`
Protocol Protocol `json:"protocol,omitempty"`
Product string `json:"product"` // X-Plex-Product: "Plex Web", "Plex for iOS", "Plex for Apple TV"
Platform string `json:"platform"` // X-Plex-Platform
PlatformVersion string `json:"platformVersion"`
Device string `json:"device"`
DeviceName string `json:"deviceName"`
ClientID string `json:"clientId"` // X-Plex-Client-Identifier
Version string `json:"version"`
MaxHeight int `json:"maxHeight"` // 2160, 1080, 720...
ExplicitMaxHeight bool `json:"explicitMaxHeight,omitempty"` // true when MaxHeight came from a request header/query limitation rather than a product default
HDR10 bool `json:"hdr10"`
ExplicitNoHDR bool `json:"explicitNoHdr,omitempty"` // true when HDR was explicitly denied by profile-extra limitations
DolbyVision bool `json:"dolbyVision"`
VideoCodecs []string `json:"videoCodecs"` // h264, hevc, av1, vp9
AudioCodecs []string `json:"audioCodecs"` // aac, ac3, eac3, truehd, dts, opus, flac
Containers []string `json:"containers"` // mp4, mkv, mpegts
HLSContainers []string `json:"hlsContainers,omitempty"` // explicit segmented output targets; distinct from direct-play containers
MaxBitrateKbps int `json:"maxBitrateKbps"` // 0 = unlimited
DefaultRemoteBitrate bool `json:"defaultRemoteBitrate,omitempty"` // true when MaxBitrateKbps came from the server's default remote cap rather than a client limitation
SubtitleCodecs []string `json:"subtitleCodecs,omitempty"` // native image/text subtitle rendering
DVProfiles []int `json:"dvProfiles,omitempty"` // explicit Dolby Vision profiles; empty uses product defaults
VideoProfiles map[string][]string `json:"videoProfiles,omitempty"`
VideoLevels map[string]int `json:"videoLevels,omitempty"` // codec level in ffprobe units (H.264 51 = 5.1)
Remote bool `json:"remote"` // not on the server's LAN
// TranscodeAudioCodecs is the explicit audio target for the current
// streaming protocol. It constrains remux/transcode output only; source
// selection and direct play continue to use AudioCodecs.
TranscodeAudioCodecs []string `json:"transcodeAudioCodecs,omitempty"`
// Download marks a request for an offline download (Plex Downloads /
// Sync) rather than live playback: the resolver prefers compact,
// mobile-native releases and the whole file is remuxed (additive).
Download bool `json:"download,omitempty"`
}
ClientCaps is what a Plex client can play, derived from X-Plex-* headers, the client profile and its declared limits.
func (ClientCaps) SupportsAudio ¶
func (c ClientCaps) SupportsAudio(codec string) bool
func (ClientCaps) SupportsContainer ¶
func (c ClientCaps) SupportsContainer(ct string) bool
func (ClientCaps) SupportsVideo ¶
func (c ClientCaps) SupportsVideo(codec string) bool
type ClientCodecProfile ¶ added in v0.3.0
type ClientCodecProfile struct {
MediaType string
Codecs, Containers, SubContainers []string
Conditions, ApplyConditions []ClientProfileCondition
}
type ClientContainerProfile ¶ added in v0.3.0
type ClientContainerProfile struct {
MediaType string
Containers, SubContainers []string
Conditions []ClientProfileCondition
}
type ClientDirectPlayProfile ¶ added in v0.3.0
type ClientDirectPlayProfile struct {
MediaType string `json:"mediaType"`
Containers []string `json:"containers"`
VideoCodecs []string `json:"videoCodecs"`
AudioCodecs []string `json:"audioCodecs"`
}
ClientDirectPlayProfile keeps container and codec alternatives paired. Empty alternatives represent an unconstrained field, not another profile.
type ClientProfileCondition ¶ added in v0.3.0
type ClientProfileCondition struct {
Operator string `json:"operator"`
Property string `json:"property"`
Value string `json:"value"`
Required bool `json:"required"`
}
ClientProfileCondition preserves a client-declared condition for the broker. Required conditions unknown to an evaluator must not be silently accepted.
type ClientSubtitleProfile ¶ added in v0.3.0
type ClientSubtitleProfile struct{ Format, Method, DIDLMode, Language, Container string }
type ClientTranscodeProfile ¶ added in v0.3.0
type ClientTranscodeProfile struct {
MediaType, Delivery, Context string
Containers, VideoCodecs, AudioCodecs []string
EstimateContentLength, MPEGTSM2TS, CopyTimestamps, SubtitlesInManifest bool
SeekInfo, MaxAudioChannels string
MinSegments, SegmentLength int
BreakOnNonKeyFrames, AudioVBR *bool
Conditions []ClientProfileCondition
}
type Collection ¶
type Collection struct {
Key RatingKey `json:"key"`
Title string `json:"title"`
Summary string `json:"summary,omitempty"`
Kind string `json:"kind"` // "franchise", "trending", "smart", "user"
Type MediaType `json:"type"`
Filter *Filter `json:"filter,omitempty"` // smart
Sort SortOrder `json:"sort,omitempty"`
OwnerUserID int64 `json:"ownerUserId,omitempty"` // 0 = server-wide
PosterPath string `json:"posterPath,omitempty"`
BackdropPath string `json:"backdropPath,omitempty"`
ChildCount int `json:"childCount"`
Upcoming bool `json:"upcoming,omitempty"` // admits scoped future placeholders
// UpdatedAt changes when the collection's members or artwork change, so
// Plex clients refetch artwork (additive).
UpdatedAt time.Time `json:"updatedAt,omitempty"`
}
type CollectionArtwork ¶
type CollectionArtwork struct {
Mode string `json:"mode"` // auto | collage | backdrop | tmdb | custom
URL string `json:"url,omitempty"`
Accent string `json:"accent,omitempty"` // "#rrggbb"
}
CollectionArtwork selects the poster Plex shows for the collection.
type CollectionArtworkSource ¶ added in v0.2.7
type CollectionArtworkSource interface {
CollectionArtwork(context.Context, *User, RatingKey, string, int) ([]byte, string, bool, error)
}
CollectionArtworkSource exposes the optional CollectionArtwork capability.
type CollectionLayoutSource ¶ added in v0.2.7
type CollectionLayoutSource interface {
LayoutRow(context.Context, *User, HubContext, string) (*CollectionRow, error)
}
CollectionLayoutSource exposes the optional LayoutRow capability.
type CollectionPlaceholder ¶ added in v0.2.37
type CollectionPlaceholder interface {
AllowsPlaceholders(context.Context, *User, RatingKey, string) bool
Placeholder(context.Context, *User, RatingKey, RatingKey, string) (*Title, error)
FindPlaceholder(context.Context, *User, RatingKey, string) (*Title, RatingKey, error)
}
CollectionPlaceholder resolves a future title only through a visible, enabled collection in which it is currently a member for this viewer.
type CollectionPreview ¶
type CollectionPreview struct {
Total int `json:"total"`
Items []Title `json:"items"`
Warnings []string `json:"warnings"`
TookMs int64 `json:"tookMs"`
}
CollectionPreview is the result of evaluating an unsaved spec.
type CollectionRotate ¶
type CollectionRotate struct {
Size int `json:"size"`
Every string `json:"every"` // "daily" | "weekly"
}
CollectionRotate shows a rotating subset of the members.
type CollectionRow ¶
type CollectionRow struct {
Hub Hub `json:"hub"`
CollectionID string `json:"collectionId"`
HomeRow bool `json:"homeRow"`
SectionRow bool `json:"sectionRow"`
}
CollectionRow is an owner-designed collection offered as a Home or section row for a user in a context (targeting and schedules already applied).
type CollectionRows ¶
type CollectionRows interface {
HomeRowsFor(ctx context.Context, user *User, hc HubContext) ([]CollectionRow, error)
}
CollectionRows is implemented by the collection engine for the personalization engine.
type CollectionRule ¶
type CollectionRule struct {
Field string `json:"field"`
Op string `json:"op"`
Value json.RawMessage `json:"value"`
Label string `json:"label,omitempty"`
}
CollectionRule is one condition. Value is typed by Field; Label is display text for ids.
type CollectionSchedule ¶
type CollectionSchedule struct {
Days []int `json:"days,omitempty"`
FromHour *int `json:"fromHour,omitempty"`
ToHour *int `json:"toHour,omitempty"`
Devices []string `json:"devices,omitempty"`
}
CollectionSchedule limits when rows appear. Days use 0 = Sunday … 6 = Saturday; hours are local, FromHour inclusive and ToHour exclusive, wrapping past midnight when FromHour > ToHour.
type CollectionSource ¶
type CollectionSource struct {
Kind string `json:"kind"`
List string `json:"list,omitempty"`
MediaType string `json:"mediaType,omitempty"`
ID int64 `json:"id,omitempty"`
Label string `json:"label,omitempty"`
Params map[string]string `json:"params,omitempty"`
Region string `json:"region,omitempty"`
URL string `json:"url,omitempty"`
Keys []string `json:"keys,omitempty"`
// Role narrows tmdbPerson credits: "cast", "director", "writer",
// "crew" or "" (every credit). Additive to the contract.
Role string `json:"role,omitempty"`
}
CollectionSource is one place candidates come from. Kind selects which other fields apply:
catalog the whole browsable catalogue tmdbList List, MediaType trending_day|trending_week|popular|top_rated|now_playing|upcoming|airing_today|on_the_air tmdbCollection ID, Label a TMDB franchise tmdbDiscover Params raw /discover parameters (names allowed for ids) tmdbKeyword | tmdbCompany | tmdbNetwork | tmdbPerson ID, Label (Role for people) watchProvider ID, Region, Label what's streaming on a service traktList | letterboxdList | mdblist URL anilistList URL (an AniList anime list; optionally one named list) stevenlu List: movies (default) or a score-filtered variant titles Keys hand-picked rating keys
When ID is 0 the Label is resolved to a TMDB id by name.
type CollectionSpec ¶
type CollectionSpec struct {
ID string `json:"id,omitempty"` // server-assigned
Name string `json:"name"`
Description string `json:"description,omitempty"`
MediaType string `json:"mediaType"` // "movie" | "show" | "mixed"
Sources []CollectionSource `json:"sources"`
Match string `json:"match"` // "all" | "any"
Rules []CollectionRule `json:"rules"`
Exclude []CollectionRule `json:"exclude"`
// Sort: popularity | rating | released | title | added | random | personal | source.
Sort string `json:"sort"`
SortDesc bool `json:"sortDesc"`
Limit int `json:"limit"` // 0 = no limit
Refresh string `json:"refresh"` // live | hourly | daily | weekly
Rotate *CollectionRotate `json:"rotate,omitempty"`
Artwork CollectionArtwork `json:"artwork"`
Targets CollectionTargets `json:"targets"`
Enabled bool `json:"enabled"`
LocalOnly bool `json:"localOnly,omitempty"` // evaluate rules against the local catalogue only; no remote discovery
ReleaseMode string `json:"releaseMode,omitempty"` // released (default), upcoming, or mixed
LookaheadDays int `json:"lookaheadDays,omitempty"` // 1..366 when upcoming is enabled
TemplateID string `json:"templateId,omitempty"`
// Server-maintained.
UpdatedAt *time.Time `json:"updatedAt,omitempty"`
LastBuiltAt *time.Time `json:"lastBuiltAt,omitempty"`
ItemCount int `json:"itemCount"`
// Additive fields beyond the contract (read-only for clients).
BuiltIn bool `json:"builtIn,omitempty"` // shipped with Ether; only targets/artwork/rotate/enabled are editable
RatingKey string `json:"ratingKey,omitempty"` // the Plex ratingKey of the published collection
Warnings []string `json:"warnings,omitempty"` // from the last build
// OwnerUserID is set for private collections created by a Plex user
// (core.Collections.CreateSmart); 0 = server-wide.
OwnerUserID int64 `json:"ownerUserId,omitempty"`
}
CollectionSpec is an owner-designed collection: candidates gathered from Sources, filtered by Rules, sorted, limited and published to Plex.
type CollectionSpecSource ¶ added in v0.2.7
type CollectionSpecSource interface {
ListSpecs(context.Context) ([]CollectionSpec, error)
}
CollectionSpecSource exposes the optional ListSpecs capability.
type CollectionTargets ¶
type CollectionTargets struct {
CollectionsTab bool `json:"collectionsTab"`
HomeRow bool `json:"homeRow"`
SectionRow bool `json:"sectionRow"`
Users UserTargets `json:"users"`
Schedule *CollectionSchedule `json:"schedule,omitempty"`
}
CollectionTargets says where and for whom the collection is published.
type CollectionTemplate ¶
type CollectionTemplate struct {
ID string `json:"id"`
Name string `json:"name"`
Description string `json:"description"`
Category string `json:"category"`
Spec CollectionSpec `json:"spec"`
}
CollectionTemplate is a curated starting point in the Collection Studio.
type Collections ¶
type Collections interface {
List(ctx context.Context, user *User, t MediaType) ([]Collection, error)
Get(ctx context.Context, user *User, key RatingKey) (*Collection, error)
Items(ctx context.Context, user *User, key RatingKey, offset, limit int) (Page, error)
CreateSmart(ctx context.Context, c Collection) (*Collection, error)
DeleteSmart(ctx context.Context, key RatingKey) error
}
type ContextReaderAt ¶ added in v0.2.7
ContextReaderAt reads source bytes with request cancellation.
type ContextualRecommender ¶
type ContextualRecommender interface {
HomeHubsFor(ctx context.Context, user *User, hc HubContext, limit int) ([]Hub, error)
SectionHubsFor(ctx context.Context, user *User, t MediaType, hc HubContext, limit int) ([]Hub, error)
}
ContextualRecommender is implemented by recommenders that adapt rows to the request context. internal/plex prefers it over Recommender when available.
type CreditFilter ¶ added in v0.3.0
type CreditFilter struct {
People []int64 `json:"people,omitempty"`
Kind string `json:"kind,omitempty"`
Exclude bool `json:"exclude,omitempty"`
}
CreditFilter narrows by credited person TMDB IDs and optional credit kind ("cast", "director", "writer", "crew", or "" for any).
type CustomFormat ¶
type CustomFormat struct {
ID string `json:"trash_id"`
Name string `json:"name"`
Scores map[string]int `json:"trash_scores,omitempty"`
Specifications []FormatSpecification `json:"specifications"`
// App names the Starr app whose enum values the specifications use:
// Sonarr numbers sources differently from Radarr. Empty means Radarr.
App string `json:"app,omitempty"`
}
CustomFormat retains the native TRaSH/Radarr/Sonarr JSON for owner editing. Unknown specifications are rejected at import rather than silently matching.
type DASHSession ¶
type DASHSession interface {
HLSSession
// ServeManifest writes the MPD.
ServeManifest(w http.ResponseWriter, r *http.Request)
// ServeInit writes the initialization segment of a representation.
ServeInit(w http.ResponseWriter, r *http.Request, rep int)
// ServeMedia writes media segment n of a representation, waiting for
// ffmpeg and restarting it at the right offset when a seek jumps ahead.
ServeMedia(w http.ResponseWriter, r *http.Request, rep, n int)
}
DASHSession is a running ffmpeg remux or transcode producing MPEG-DASH: a static, full-length MPD with separate video and audio representations of fMP4 segments addressed by number ($Number$, from 0). Its HLSSession methods map onto the first representation; ServePlaylist writes the MPD.
type DamageReporter ¶ added in v0.2.7
DamageReporter exposes the optional SetDamageHandler capability.
type DateFilter ¶ added in v0.3.0
type DateFilter struct {
Op string `json:"op,omitempty"`
Unix int64 `json:"unix,omitempty"`
SpanDay bool `json:"spanDay,omitempty"`
}
DateFilter narrows a release timestamp with a comparison operator ("=", "!=", "<<", "<=", ">>", ">="). SpanDay is true when the value was parsed from a calendar day (YYYY-MM-DD), so "=" and "!=" cover the 24-hour UTC day.
type DecideOptions ¶
type DecideOptions struct {
// DisableVideoTranscode prevents optional enhancement from promoting direct playback.
DisableVideoTranscode bool
DirectPlay bool // client allows direct play
DirectStream bool // client allows remux
MaxBitrateKbps int // client-requested cap (maxVideoBitrate)
MaxHeight int // from videoResolution
AudioStream int // selected stream index, -1 default
SubtitleStream int // -1 none
AudioFilters []string // trusted owner/viewer audio processing; forces audio encoding
BurnSubtitles bool
// Protocol is the conversion protocol the client asked for (hls, dash,
// http). Empty keeps the HLS target. Additive.
Protocol string
}
DecideOptions are per-request choices from the Plex decision request.
type Decision ¶
type Decision struct {
Enhancement VideoEnhancement `json:"enhancement,omitempty"`
Kind DecisionKind `json:"kind"`
VideoCopy bool `json:"videoCopy"`
AudioCopy bool `json:"audioCopy"`
VideoCodec string `json:"videoCodec"` // target codec when transcoding
AudioCodec string `json:"audioCodec"`
Container string `json:"container"` // "mpegts" (HLS) or original
MaxHeight int `json:"maxHeight"`
// H264Level is a verified output level_idc for a constrained H.264 encode.
// Zero retains the encoder's existing automatic selection.
H264Level int `json:"h264Level,omitempty"`
// H264FrameRate bounds the selected encoder output rate for that level.
H264FrameRate float64 `json:"h264FrameRate,omitempty"`
BitrateKbps int `json:"bitrateKbps"`
AudioStream int `json:"audioStream"`
SubtitleStream int `json:"subtitleStream"` // -1 none
BurnSubtitles bool `json:"burnSubtitles"`
Reason string `json:"reason"`
AudioFilters []string `json:"audioFilters,omitempty"`
// AudioChannels and AudioSampleRate keep the already negotiated audio
// decoder configuration across a source change. Zero uses the normal
// encoder defaults.
AudioChannels int `json:"audioChannels,omitempty"`
AudioSampleRate int `json:"audioSampleRate,omitempty"`
// ToneMap converts HDR (HDR10, HLG, Dolby Vision) video to SDR while
// transcoding, for clients without HDR support.
ToneMap bool `json:"toneMap,omitempty"`
// StripDolbyVision copies the compatible HDR10 base layer while
// removing Dolby Vision RPU/configuration data; it never re-encodes.
StripDolbyVision bool `json:"stripDolbyVision,omitempty"`
}
type DecisionCandidate ¶ added in v0.3.0
type DecisionCandidate struct {
ReleaseID string
Name string
Height int
Size int64
Score float64
Rejected bool
Reason string
Healthy bool
HealthChecked bool
}
DecisionCandidate is one ranked or rejected release in a DecisionTrace.
type DecisionKind ¶
type DecisionKind string
const ( DecisionDirectPlay DecisionKind = "directplay" DecisionRemux DecisionKind = "copy" // Plex calls this "direct stream" DecisionTranscode DecisionKind = "transcode" )
type DecisionTrace ¶ added in v0.3.0
type DecisionTrace struct {
Profile string
ProfileMaxHeight int
ClientMaxHeight int
EffectiveMaxHeight int
AllowHDR bool
AllowDolbyVision bool
Chooser string
ChosenVersion string
Candidates []DecisionCandidate
}
DecisionTrace is the privacy-safe shape of the latest resolution for a title: ceilings, who chose, and a bounded candidate list. It has no username, address, or stream URL. Release names are the file names the resolver ranked.
type DecisionTraceSource ¶ added in v0.3.0
type DecisionTraceSource interface {
LatestDecision(key RatingKey) (DecisionTrace, bool)
}
DecisionTraceSource is the latest resolution for a title. Plex reads it for the support capture and stays outside the resolver package.
type DelegationAuth ¶ added in v0.2.7
DelegationAuth issues expiring, server-local casting credentials. Implementations must enforce current membership on use and must not delegate owner privileges.
type Device ¶ added in v0.3.0
type Device struct {
ID string
Client string
Product string
Version string
Platform string
DeviceName string
Language string
}
Device identifies the client receiving a surface-specific credential.
type DirectPlayRetrier ¶ added in v0.2.7
type DirectPlayRetrier interface{ RetryDirectPlay() bool }
DirectPlayRetrier exposes the optional RetryDirectPlay capability.
type DownloadAccessPolicy ¶ added in v0.2.7
DownloadAccessPolicy exposes the optional AllowDownloads capability.
type DownloadRemuxRequest ¶
type DownloadRemuxRequest struct {
// InputURL is the loopback URL of the playback session feeding ffmpeg.
InputURL string
// Info is the probed media info of the resolved source.
Info MediaInfo
// AudioStream is the source stream index to keep; -1 picks the
// default (first) audio stream.
AudioStream int
// ViewerID bounds converting downloads to one encode per viewer.
// Zero skips the per-viewer encode lock (copy remuxes do not take it).
ViewerID int64
// Caps is the requesting client's download profile. Empty uses
// H.264/HEVC + AAC/AC3 in MP4, the mobile download target.
Caps ClientCaps
// Options are the per-request transcode choices (bitrate, height, burn).
Options DecideOptions
}
DownloadRemuxRequest is one whole-file remux to MP4.
type DownloadRemuxer ¶
type DownloadRemuxer interface {
// RemuxDownload copies or converts a resolved source to a temp MP4,
// reporting progress as a fraction in [0,1] when progress is non-nil.
// Cancelling ctx kills ffmpeg and removes the partial file.
RemuxDownload(ctx context.Context, req DownloadRemuxRequest, progress func(fraction float64)) (path string, size int64, err error)
// ReleaseDownload deletes a remuxed file and frees its budget.
// Releasing an unknown path is a no-op.
ReleaseDownload(path string)
}
DownloadRemuxer copies a resolved source into a temporary faststart MP4. Implemented by internal/transcode. The returned path is owned by the remuxer until ReleaseDownload is called; files are never kept permanently and are bounded by a disk budget.
type DurablePrefetcher ¶ added in v0.2.7
type DurablePrefetcher interface {
DurablePrefetch(context.Context, string, []byte, int64, int64) error
}
DurablePrefetcher exposes the optional DurablePrefetch capability.
type EncoderInputLease ¶ added in v0.3.0
type EncoderInputLease interface {
// ClaimInput succeeds once, before seal. Failed claims never call onDrained.
// Successful claims call it exactly once, possibly before this returns,
// after sealed producers and registry ownership are released. The trusted
// callback must only do bounded accounting/requeue; no I/O, waits or source
// operations. It runs outside every manager/session/scope lock.
ClaimInput(onDrained func(error)) error
HeadersForInput(inputURL string) (map[string]string, error)
SealInput()
InputDone() <-chan struct{}
InputErr() error
}
EncoderInputLease is issued by PlaybackEncoderInputs for one exact source lifetime. Host composition passes the opaque object; wire inputs cannot mint one. Each encoder must obtain its own lease, including shared-source owners.
type EncoderRetirement ¶ added in v0.3.0
type EncoderRetirement interface {
EncoderDone() <-chan struct{}
EncoderErr() error
}
EncoderRetirement covers one exact encoder session, including all its runs and preflights. EncoderDone closes only at a terminal result. EncoderErr is ErrEncoderPending before then and is immutable afterwards; only nil proves full retirement. SourceRetirement alone never supplies this proof.
type Engine ¶
type Engine interface {
// Open builds the byte-offset index for the main video file of an NZB.
Open(ctx context.Context, releaseID string, nzb []byte) (MediaSource, error)
// Prefetch warms [offset, offset+length) at background priority.
Prefetch(ctx context.Context, releaseID string, nzb []byte, offset, length int64) error
}
type ExactVariantPlayback ¶ added in v0.3.0
type ExactVariantPlayback interface {
PrepareExactVariant(ctx context.Context, user *User, key RatingKey, caps ClientCaps, releaseID string) (*PlaySession, error)
}
ExactVariantPlayback never substitutes a different release, including during later failover. The requested release may instead become unavailable.
type FacetValue ¶
type FacetValue struct {
ID string `json:"id,omitempty"` // Stable namespace-aware neutral identifier.
Key string `json:"key"`
Title string `json:"title"`
Count int `json:"count"`
// Labels are the equivalent values Key stands for, where a facet groups
// them (content-rating levels list every board's label).
Labels []string `json:"labels,omitempty"`
}
type Filter ¶
type Filter struct {
KnownAddedDate bool `json:"-"` // only released/aired titles, before pagination
// ExcludeKeys applies local visibility policy before counting and pagination.
ExcludeKeys []RatingKey `json:"-"`
// IncludeKeys, when set, restricts the page to these keys before
// counting and pagination. An empty list matches nothing.
IncludeKeys []RatingKey `json:"-"`
// ExcludeGenres and ExcludeKeywords remove viewer-blocked facts before
// counting and pagination. Matching is case-insensitive.
ExcludeGenres []string `json:"-"`
ExcludeKeywords []string `json:"-"`
AddedAfter int64 `json:"-"` // inclusive Unix timestamp bound on added/release time
AddedBefore int64 `json:"-"` // inclusive Unix timestamp bound on added/release time
UpdatedAfter int64 `json:"-"` // inclusive Unix timestamp bound on metadata update time
UpdatedBefore int64 `json:"-"` // inclusive Unix timestamp bound on metadata update time
Type MediaType `json:"type,omitempty"` // movie or show
Genres []string `json:"genres,omitempty"`
Keywords []string `json:"keywords,omitempty"` // every keyword must match (case-insensitive)
YearFrom int `json:"yearFrom,omitempty"`
YearTo int `json:"yearTo,omitempty"`
Years []int `json:"years,omitempty"`
ExcludeYears []int `json:"excludeYears,omitempty"`
MinRating float64 `json:"minRating,omitempty"`
MaxRating float64 `json:"maxRating,omitempty"`
ExcludeRatings []float64 `json:"excludeRatings,omitempty"`
MaxRuntime time.Duration `json:"maxRuntime,omitempty"`
MinRuntime time.Duration `json:"minRuntime,omitempty"`
ExcludeRuntimes []time.Duration `json:"excludeRuntimes,omitempty"`
Languages []string `json:"languages,omitempty"`
Countries []string `json:"countries,omitempty"`
ExcludeCountries []string `json:"excludeCountries,omitempty"`
ContentRatings []string `json:"contentRatings,omitempty"`
ExcludeContentRatings []string `json:"excludeContentRatings,omitempty"`
MaxContentRating string `json:"maxContentRating,omitempty"` // per-user limit
// SaferPlexRating applies cached Plex content-rating levels in SQL
// together with MaxContentRating so paging and counts stay correct.
SaferPlexRating bool `json:"-"`
Collection int64 `json:"collection,omitempty"`
Collections []int64 `json:"collections,omitempty"`
ExcludeCollections []int64 `json:"excludeCollections,omitempty"`
Person int64 `json:"person,omitempty"` // cast or crew TMDB id
Credits []CreditFilter `json:"credits,omitempty"`
Studio string `json:"studio,omitempty"`
StudioFilters []StringFilter `json:"studioFilters,omitempty"`
FirstCharacter string `json:"firstCharacter,omitempty"`
Query string `json:"query,omitempty"` // title substring
TitleFilters []StringFilter `json:"titleFilters,omitempty"`
ReleasedFilters []DateFilter `json:"releasedFilters,omitempty"`
// MinContentRating is an additive share-policy predicate (plex.tv share
// filters). It does not replace MaxContentRating or ContentRatings.
MinContentRating string `json:"-"`
// IncludeCollectionNames / ExcludeCollectionNames match
// Title.CollectionName (plex.tv share label filters). An empty
// collection name is unmappable and is not excluded.
IncludeCollectionNames []string `json:"-"`
ExcludeCollectionNames []string `json:"-"`
}
Filter narrows a browse or a smart collection. Zero values mean "any".
type FormatSpecification ¶
type GoodputSession ¶
type GoodputSession interface {
// GoodputKbps is the rolling segment-delivery estimate; 0 unknown.
GoodputKbps() int
}
GoodputSession is a session that measures client delivery goodput.
type HLSIndependentSegments ¶ added in v0.3.0
type HLSIndependentSegments interface {
IndependentSegments() bool
}
HLSIndependentSegments is an optional, session-wide guarantee that every segment in every advertised rendition is independently decodable. A session must not implement it as true unless it can prove that guarantee for copied media, all encoder paths, and every rung it actually advertises.
type HLSLadderSession ¶
type HLSLadderSession interface {
HLSSession
// Rungs lists the ladder, highest first; Rungs()[0] is "base".
Rungs() []HLSRung
// ServeRungPlaylist writes rung's media playlist.
ServeRungPlaylist(w http.ResponseWriter, r *http.Request, rung string)
// ServeRungSegment writes segment n of rung (InitSegment numbering as
// in ServeSegment: the caller passes the parsed segment number).
ServeRungSegment(w http.ResponseWriter, r *http.Request, rung string, n int)
}
HLSLadderSession is an HLSSession that can serve a multi-rung ABR ladder. Only the primary rung's encoder runs until a client requests a segment on another rung; at most one rung encodes at a time.
type HLSRequest ¶
type HLSRequest struct {
// RequireIndependentProof emits HLS independence tags only when the
// session can guarantee every advertised segment is independently decodable.
// Zero preserves the legacy playlist contract for existing callers.
RequireIndependentProof bool
SessionID string
InputURL string // ffmpeg input; Ether serves sources on loopback HTTP with range support
// LiveInput permits playlist demuxers for owner-configured live sources.
// Ordinary resolved media must leave this false, even if duration is unknown.
LiveInput bool
// InputHeaders are optional HTTP headers ffmpeg must send when reading
// InputURL (e.g. for resolved trailer URLs). Transcoders that cannot
// send headers ignore them; most resolved URLs need none (additive).
InputHeaders map[string]string
// InputLease is trusted host composition only, never decoded from wire
// requests. A caller retains an unclaimed lease if admission fails early.
InputLease EncoderInputLease `json:"-"`
Info MediaInfo
Decision Decision
StartOffset time.Duration
// SegmentDuration defaults to 4s when zero (5s for DASH).
SegmentDuration time.Duration
// Protocol is ProtocolHLS (default when empty), ProtocolDASH, or
// ProtocolHTTP (Plex for Mac / Desktop's chunked Matroska stream;
// the constant lives with the other "http" protocol name in debrid.go).
// A DASH session also implements DASHSession; an HTTP session also
// implements HTTPSession. Transcoder.Session returns either as an
// HLSSession, so type-assert to reach the protocol methods.
Protocol string
}
type HLSRung ¶
type HLSRung struct {
// ID is the rung's URL component: session/{id}/{ID}/index.m3u8. The
// primary rung is always "base" (served by the HLSSession methods).
ID string
// Bandwidth is the peak bitrate in bits per second (#EXT-X-STREAM-INF
// BANDWIDTH / DASH Representation bandwidth).
Bandwidth int
// AverageBandwidth is the average bitrate in bits per second.
AverageBandwidth int
Width int
Height int
// Codecs is an RFC 6381 codecs string ("avc1...,mp4a...").
Codecs string
FrameRate float64
}
HLSRung is one variant of an adaptive HLS/DASH ladder. All rungs of a session share deterministic segment numbering over one segment timeline: segment N covers the same media on every rung.
type HLSSession ¶
type HLSSession interface {
ID() string
// ServePlaylist writes the media playlist (index.m3u8).
ServePlaylist(w http.ResponseWriter, r *http.Request)
// ServeSegment writes segment n, waiting for ffmpeg to produce it and
// restarting ffmpeg at the right offset when a seek jumps ahead.
ServeSegment(w http.ResponseWriter, r *http.Request, n int)
// SwapInput restarts the session on a new input at the given position
// (mid-stream failover). Segment numbering continues.
SwapInput(ctx context.Context, inputURL string, info MediaInfo, at time.Duration) error
LastAccess() time.Time
Close() error
}
HLSSession is one running ffmpeg remux or transcode producing HLS (or DASH; see DASHSession).
type HTTPSession ¶ added in v0.3.0
type HTTPSession interface {
HLSSession
ServeHTTP(w http.ResponseWriter, r *http.Request)
}
HTTPSession is a running ffmpeg remux or transcode writing one streamable Matroska to the client (Plex for Mac protocol=http). ServeHTTP writes the chunked body; a later start with offset is a new StartHLS of the same session id.
type HWAccel ¶
type HWAccel struct {
Name string `json:"name"` // "videotoolbox", "nvenc", "qsv", "vaapi", "none"
Encoders []string `json:"encoders"`
Device string `json:"device,omitempty"`
// NoGPUScale: the encoder works but the device's video processing
// (VAAPI scale_vaapi) does not, so frames are decoded and scaled in
// software and uploaded to the encoder.
NoGPUScale bool `json:"noGpuScale,omitempty"`
// NoGPUTonemap: the device's VAAPI VPP cannot run tonemap_vaapi, so HDR
// tone-mapping falls back to the software zscale/tonemap path.
NoGPUTonemap bool `json:"noGpuTonemap,omitempty"`
// VAAPIQualityRC / VAAPIBitrateRC record the probed VAAPI rate-control
// modes ("QVBR", "VBR", "CBR", "CQP") per encoder ("h264_vaapi",
// "hevc_vaapi"); nil/empty falls back to the default QVBR/VBR modes.
VAAPIQualityRC map[string]string `json:"vaapiQualityRc,omitempty"`
VAAPIBitrateRC map[string]string `json:"vaapiBitrateRc,omitempty"`
}
type HealthChecker ¶
HealthChecker checks a sample of an NZB's articles exist (NNTP STAT). It also inspects archive headers: compressed or encrypted RARs and releases without a playable video file report healthy=false with a reason. Implemented by internal/stream.
type HistoryEntry ¶
type HomeCandidateSource ¶ added in v0.2.7
type HomeCandidateSource interface {
HomeCandidatesFor(context.Context, *User, HubContext, int) ([]Hub, error)
}
HomeCandidateSource exposes the optional HomeCandidatesFor capability.
type HomeLayout ¶
type HomeLayout struct {
Global []LayoutPage `json:"global"`
Viewers []ViewerLayout `json:"viewers"`
UpdatedAt time.Time `json:"updatedAt,omitempty"`
}
HomeLayout is the owner's global template, with complete row policies in viewer layers replacing matching global policies. Slots are one-based.
type HomeLayoutSource ¶ added in v0.2.7
type HomeLayoutSource interface {
FinalizeHome(context.Context, *User, HubContext, string, []Hub) ([]Hub, error)
}
HomeLayoutSource exposes the optional FinalizeHome capability.
type HomePreview ¶
type HomePreview struct {
Rows []HomeRow `json:"rows"`
GeneratedAt time.Time `json:"generatedAt"`
Context HubContext `json:"context"`
// HomeDeduped counts the titles kept off a Movies or TV Shows page
// because the viewer's Home leads with them (DedupeHome).
HomeDeduped int `json:"homeDeduped,omitempty"`
}
HomePreview is a viewer's assembled rows for one context.
type HomeRow ¶
type HomeRow struct {
HubID string `json:"hubId"`
Layer string `json:"layer,omitempty"`
Slot int `json:"slot,omitempty"`
AnchorSlot int `json:"anchorSlot,omitempty"`
Placement string `json:"placement,omitempty"`
HiddenReason string `json:"hiddenReason,omitempty"`
Policy *RowPolicy `json:"policy,omitempty"`
PolicyLayer string `json:"policyLayer,omitempty"`
Title string `json:"title"`
Kind string `json:"kind"` // e.g. "because-you-watched", "collection:<id>"
Reason string `json:"reason"`
Score float64 `json:"score"` // predicted engagement used for ordering
Pinned bool `json:"pinned,omitempty"`
Hidden bool `json:"hidden,omitempty"` // hidden by a layout rule: not sent to Plex
Source string `json:"source"`
Items []Title `json:"items"`
ItemReasons map[RatingKey]string `json:"itemReasons,omitempty"`
// Hub is the row as handed to the Plex front end.
Hub Hub `json:"-"`
}
HomeRow is one row of a viewer's Home or section as Plex receives it, with the engine's explanation. Items are catalogue titles; the admin API turns them into TitleCards.
type HomeSituation ¶ added in v0.3.0
type HomeSituation struct {
Device, Daypart string
Weekend bool
Now time.Time
LibraryID int
Product, Platform, SessionID, ClientID string
}
HomeSituation describes the viewer's device and local time for row ranking.
type Hub ¶
type Hub struct {
ID string `json:"id"` // stable identifier, e.g. "trending.week.movie"
Title string `json:"title"`
Type MediaType `json:"type"` // item type in the row ("mixed" allowed via "")
Context string `json:"context"` // Plex hub context, e.g. "hub.movie.recentlyreleased"
Style string `json:"style,omitempty"` // "shelf", "hero", "clip"
Promoted bool `json:"promoted"` // show on Home
Items []Title `json:"items"`
More bool `json:"more"`
Key RatingKey `json:"key,omitempty"` // backing collection, if any
// ItemCount carries rendered availability when a front end retains the
// actual metadata and asks only for row placement.
ItemCount int `json:"itemCount,omitempty"`
}
Hub is a Home row or a section row.
func SectionView ¶
SectionView restricts a Home hub to one library section's media type, so mixed rows that belong on a section too (the watchlist, Rediscover) can appear there with only that section's titles. A typed hub passes through when its type matches. Recaps (Year in Review) stay on Home. ok is false when nothing of the type remains.
type HubContext ¶
type HubContext struct {
Device string `json:"device"`
Daypart string `json:"daypart"`
Weekend bool `json:"weekend"`
Now time.Time `json:"now"`
SectionID int `json:"sectionId,omitempty"`
Product string `json:"product,omitempty"` // X-Plex-Product
Platform string `json:"platform,omitempty"` // X-Plex-Platform
SessionID string `json:"sessionId,omitempty"`
ClientID string `json:"clientId,omitempty"`
}
HubContext is the situation a Plex client asked for rows in: which kind of device, when, and for which section (empty = Home).
func NewHubContext ¶
func NewHubContext(now time.Time, product, platform, device string) HubContext
NewHubContext derives the request context for a hubs call at now (in the server's local time; pass time.Now() or a time already converted with In(loc)) from the client's X-Plex-* headers.
func (HubContext) Bucket ¶
func (hc HubContext) Bucket() string
Bucket is a stable cache key for the context's coarse shape: "section/device/daypart/weekday|weekend".
type HubImpression ¶
type HubImpression struct {
UserID int64 `json:"userId"`
HubID string `json:"hubId"`
Position int `json:"position"`
Keys []RatingKey `json:"keys"`
Context HubContext `json:"context"`
At time.Time `json:"at"`
}
HubImpression is one row as served to a user, for the personalization feedback loop.
type HubItemSource ¶ added in v0.2.56
type HubItemSource interface {
HubItemsFor(context.Context, *User, HubContext, string, int) (Hub, bool)
}
HubItemSource exposes the optional HubItemsFor capability for resolving a specific hub by identifier even after a model or window transition.
type IDs ¶
type IDs struct {
TMDB int64 `json:"tmdb,omitempty"`
IMDB string `json:"imdb,omitempty"`
TVDB int64 `json:"tvdb,omitempty"`
}
IDs are the external identifiers of a title. Episodes carry their show's IMDb/TVDB ids in ShowIDs on Title, and their own TMDB episode id here.
type Identity ¶ added in v0.3.0
type Identity interface {
Resolve(ctx context.Context, surface, credential string) (*Viewer, error)
}
Identity resolves a credential only for the supplied surface. Surface IDs are protocol-defined strings so additional front ends can register them.
type ImageURLFunc ¶
ImageURL returns a full TMDB image URL for a path and size ("w500", "original").
type ImpressionSink ¶
type ImpressionSink interface {
RecordImpressions(user *User, hc HubContext, hubs []Hub)
}
ImpressionSink receives served rows. Implementations must not block.
type IntentTracker ¶
type IntentTracker interface {
// RecordDetailOpen notes that a viewer opened a title's detail page.
RecordDetailOpen(ctx context.Context, user *User, t *Title)
// NotePlayback notes that playback of key started; an open for the
// same title moments earlier was a conversion, not browsing intent.
NotePlayback(user *User, key RatingKey)
}
IntentTracker receives live in-session browsing signals (item #32): single-item detail opens that do not turn into playback. Signals are in-memory only and decay over ~45 minutes. Implementations must not block the caller for long.
type KeyframePoint ¶
KeyframePoint ties a byte offset in a media file to the presentation time of the sync sample (keyframe) or cue point that starts there, as read from the container index (Matroska Cues, MP4 stss with stco/co64) or a packet scan. MediaInfo.Keyframes holds them sorted by Offset and Time.
type LayoutPage ¶
type LayoutPage struct {
Section string `json:"section"`
MaxRows int `json:"maxRows,omitempty"`
DeviceMaxRows map[string]int `json:"deviceMaxRows,omitempty"`
Rows []RowPolicy `json:"rows"`
// DedupeHome keeps titles the viewer's Home leads with off this page
// (Movies/TV Shows only). Nil means the default: on.
DedupeHome *bool `json:"dedupeHome,omitempty"`
// Tuning shapes how the page's rows and titles are chosen. Nil fields
// inherit (viewer page → global page → engine default).
Tuning *LayoutTuning `json:"tuning,omitempty"`
}
type LayoutTuning ¶
type LayoutTuning struct {
// Discovery: 0 sticks to proven favourites, 1 explores new territory.
Discovery *float64 `json:"discovery,omitempty"`
// Freshness: 0 favours timeless picks, 1 favours new and trending.
Freshness *float64 `json:"freshness,omitempty"`
// Variety: 0 keeps rows focused on the strongest tastes, 1 spreads
// across genres, eras and moods.
Variety *float64 `json:"variety,omitempty"`
}
LayoutTuning is the owner's three dials for a page, each 0..1 with 0.5 as the engine default.
type LayoutWhen ¶
type LayoutWhen struct {
Days []int `json:"days,omitempty"`
Dayparts []string `json:"dayparts,omitempty"`
Months []int `json:"months,omitempty"`
StartDate string `json:"startDate,omitempty"`
EndDate string `json:"endDate,omitempty"`
FromHour *int `json:"fromHour,omitempty"`
ToHour *int `json:"toHour,omitempty"`
Devices []string `json:"devices,omitempty"`
}
LayoutWhen restricts a Home layout row to days (0 = Sunday … 6 = Saturday), an hour window [FromHour, ToHour) in server local time (wraps past midnight when FromHour > ToHour) and device classes.
type LibraryExclusion ¶ added in v0.2.12
type LibraryExclusion struct {
// Name is optional. Clients label a rule from its conditions.
Name string `json:"name"`
Action string `json:"action,omitempty"` // show, hide; empty means hide
MediaType string `json:"mediaType"` // movie, show, mixed
Match string `json:"match"` // all, any
Rules []CollectionRule `json:"rules"`
}
LibraryExclusion is one ordered visibility rule. Slice order is evaluation order: the first match wins. Action is "show" or "hide"; an empty Action is "hide", so a saved exclusion group stays a hide rule. Conditions inside a rule combine with Match "all" or "any". Watch history and metadata are kept.
type LikesState ¶ added in v0.3.0
LikesState atomically applies a viewer's tri-state like to the shared rating. Nil clears the rating; true and false preserve existing compatible ratings.
type LocalFileSource ¶ added in v0.3.0
LocalFileSource exposes the opened file for change detection. The path and inode must still identify the same regular file when a revision is checked.
type LookupResult ¶
type LookupResult struct {
ID int64 `json:"id"`
Name string `json:"name"`
Subtitle string `json:"subtitle,omitempty"`
ImagePath string `json:"imagePath,omitempty"` // TMDB image path
}
LookupResult is one TMDB entity (person, keyword, company, network, collection, watch provider) found by name for the collection builder.
type MarkedPlaylists ¶ added in v0.3.0
type MarkedPlaylists interface {
MarkedPlaylist(context.Context, int64, string) (*Playlist, error)
EnsureMarkedPlaylist(context.Context, int64, string, string) (*Playlist, error)
}
MarkedPlaylists provides stable, per-viewer playlist identities independent of names.
type MediaInfo ¶
type MediaInfo struct {
Chapters []Chapter `json:"chapters,omitempty"`
Container string `json:"container"` // mkv, mp4, avi, mpegts
Duration time.Duration `json:"duration"`
Size int64 `json:"size"`
BitrateKbps int `json:"bitrateKbps"`
Streams []StreamInfo `json:"streams"`
Estimated bool `json:"estimated"` // derived from release name, not probed
// Keyframes is the container's keyframe/cue index, sorted, when it was
// read on open or probe; empty when unknown. Not serialized: it can hold
// thousands of points (additive).
Keyframes []KeyframePoint `json:"-"`
}
func CloneMediaInfo ¶ added in v0.3.0
CloneMediaInfo detaches every mutable fact while preserving nil and empty values. The caller must own the input or hold its writer's lock during this copy; cloning does not synchronize concurrent mutation of the input itself.
func (MediaInfo) Video ¶
func (m MediaInfo) Video() *StreamInfo
type MediaSource ¶
type MediaSource interface {
io.ReaderAt
Size() int64
Name() string // file name inside the release, e.g. "Movie.2024.1080p.mkv"
ReleaseID() string
Close() error
}
MediaSource is a seekable byte stream of one playable file (the video file inside a release, after NZB/RAR/7z unwrapping).
type MetadataReaderAt ¶ added in v0.2.7
type MetadataReaderAt interface {
ReadMetadataAtContext(context.Context, []byte, int64) (int, error)
}
MetadataReaderAt reads container metadata without advancing playback or read-ahead.
type MicroReason ¶
type MicroReason struct {
Header string `json:"header,omitempty"`
MatchPercent int `json:"matchPercent,omitempty"`
HasMatch bool `json:"hasMatch,omitempty"`
Reason string `json:"reason,omitempty"`
EndsAt time.Time `json:"endsAt,omitempty"`
HasEnd bool `json:"hasEnd,omitempty"`
}
MicroReason is the per-viewer decision header for a detail page (item #31): a calibrated match percentage, the strongest taste reason and the local finish time, e.g. "96% Match · Directed by Denis Villeneuve · Ends at 10:45 PM". Parts that cannot be supported honestly (low taste confidence, unknown runtime) are left empty.
func (MicroReason) Empty ¶
func (m MicroReason) Empty() bool
Empty reports whether there is nothing worth showing.
type MicroReasoner ¶
type MicroReasoner interface {
MicroReason(ctx context.Context, user *User, t *Title, now time.Time) MicroReason
}
MicroReasoner builds a MicroReason for one viewer and title. The title is only read, never mutated, so a shared catalogue record can never leak one viewer's header to another.
type NeutralEntryRef ¶ added in v0.3.0
type NeutralEntryRef struct{ Kind, ID string }
NeutralEntryRef identifies one delivered entry in a stable namespace.
type NeutralHomeLayoutSource ¶ added in v0.3.0
type NeutralHomeLayoutSource interface {
FinalizeNeutralHome(context.Context, *User, HomeSituation, string, []NeutralHomeRow) ([]NeutralHomeRow, error)
}
NeutralHomeLayoutSource arranges rows without a protocol-specific context.
type NeutralHomeRow ¶ added in v0.3.0
type NeutralHomeRow struct {
ID, Title, Kind string
Purpose RowPurpose
Type MediaType
Items []Title
ItemCount int
}
NeutralHomeRow carries a stable producer identity and semantic row type. Kind is the owner-layout identity (for example a collection rule), not a wire context.
type NeutralImpression ¶ added in v0.3.0
type NeutralImpression struct {
Situation HomeSituation
RowID, Kind, Title string
Purpose RowPurpose
Rank int
Items []RatingKey
Collection RatingKey
Item RatingKey // Parent item for detail rows.
Placement, ViewID string
Entries []NeutralEntryRef
}
NeutralImpression is a server-issued snapshot of a delivered row.
type NeutralImpressionSink ¶ added in v0.3.0
type NeutralImpressionSink interface {
RecordNeutralImpression(*User, NeutralImpression)
}
NeutralImpressionSink records a validated server-issued row snapshot.
type OriginSource ¶ added in v0.2.44
type OriginSource interface {
Origin() string
}
OriginSource is implemented by a MediaSource that can name the service its bytes come from, such as "Real-Debrid" (additive). Sources without it are Usenet.
type OwnedEncoderSession ¶ added in v0.3.0
type OwnedEncoderSession interface {
HLSSession
EncoderRetirement() EncoderRetirement
RetireEncoder() error
}
OwnedEncoderSession retires this exact object, never a replacement with the same public ID. RetireEncoder admits bounded asynchronous detachment; callers must inspect EncoderRetirement for completion, including input producers.
type OwnedSourcePlayback ¶ added in v0.3.0
type OwnedSourcePlayback interface {
PrepareSurfaceSource(context.Context, *User, RatingKey, ClientCaps, string, bool) (*PlaySession, SourceRetirement, error)
SourceRetirement(string) (SourceRetirement, bool)
// RetireSource detaches the exact captured source lifetime and schedules
// cleanup. Admission failure leaves the session attached. It is idempotent
// for the same lifetime and cannot detach a replacement.
RetireSource(string, SourceRetirement) error
}
OwnedSourcePlayback exposes source responsibility even when preparation fails or its caller cancels while a shared backend Open is still running.
type OwnedTranscoder ¶ added in v0.3.0
type OwnedTranscoder interface {
StartHLSOwned(context.Context, HLSRequest) (HLSSession, EncoderRetirement, error)
}
OwnedTranscoder returns responsibility even when a canceled start is still completing. A late start cannot publish after that responsibility is sealed.
type Person ¶
type Person struct {
TMDB int64 `json:"tmdb,omitempty"`
IMDB string `json:"imdb,omitempty"`
ID string `json:"id,omitempty"` // catalogue person id when there is no TMDB id
Name string `json:"name"`
Role string `json:"role,omitempty"` // character for cast, job for crew
ThumbPath string `json:"thumbPath,omitempty"`
}
type PersonalScorer ¶
type PersonalScorer interface {
ScoreTitles(ctx context.Context, user *User, titles []Title) (map[RatingKey]float64, error)
}
PersonalScorer scores titles for a user (higher = better fit). The collection engine uses it for the "personal" sort.
type PlaySession ¶
type PlaySession struct {
PlaybackGroup string `json:"playbackGroup,omitempty"`
// PreparedOnly marks a source reserved for planning but not opened by a
// frontend. Cluster snapshots carry it for owner Activity.
PreparedOnly bool `json:"preparedOnly,omitempty"`
ID string
UserID int64
ClientID string
Key RatingKey
Resolution *Resolution
Source MediaSource // swaps on failover; read through Playback.Source
Info MediaInfo
StartedAt time.Time
// Status for the admin dashboard and /status/sessions, filled on the
// snapshots Playback returns.
TitleName string // "Movie (2024)" or "Show - S01E02 - Episode"
Username string // user display name
Client ClientCaps // the client's product, device and limits
DecisionReason string `json:"decisionReason,omitempty"`
Decision DecisionKind // directplay once bytes go straight to the client; "" until known
BytesServed int64 // source bytes delivered (direct play and ffmpeg input)
SpeedBps int64 // recent delivery rate, bytes per second
LastActive time.Time
// ViewOffset is the client's last reported playhead in milliseconds.
// Nil means no timeline has arrived; source bytes do not imply progress.
ViewOffset *int64 `json:"viewOffset,omitempty"`
Failovers int // mid-stream release swaps so far
// Origin names where the current release streams from: "Usenet" or the
// debrid service, such as "Real-Debrid" (additive).
Origin string `json:"origin,omitempty"`
// DownFailovers counts speed-driven swaps to a lower-bitrate release
// (a subset of Failovers) (additive).
DownFailovers int `json:"downFailovers,omitempty"`
// RequiresRemux is set when a direct-play failover could not splice or
// find an exact-size replacement: the next decision/start for this
// session must be a zero-encode remux (additive).
RequiresRemux bool `json:"requiresRemux,omitempty"`
// Node is the cluster node serving a session reported by another node
// (empty for this node's own sessions and on a standalone server).
Node string `json:"node,omitempty"`
}
PlaySession binds a user, a title and a client to a resolved, open source.
type Playback ¶
type Playback interface {
// Estimate is the virtual media info shown before a title is resolved.
Estimate(ctx context.Context, t *Title, caps ClientCaps) MediaInfo
// Prepare resolves and opens a source for the user and client, enforcing
// stream limits. Reuses an existing session for the same user/client/key.
Prepare(ctx context.Context, user *User, key RatingKey, caps ClientCaps) (*PlaySession, error)
Session(id string) (*PlaySession, bool)
// SessionFor finds the live session of a client for a title.
SessionFor(userID int64, clientID string, key RatingKey) (*PlaySession, bool)
// ServeRange serves the session's current source with HTTP range
// support, failing over to the next release when articles are missing.
ServeRange(w http.ResponseWriter, r *http.Request, sessionID string)
// InputURL is a loopback URL ffmpeg can read the session's source from.
InputURL(sessionID string) string
// Failover swaps the session to the next candidate release, keeping the
// timestamp. Returns the new media info.
Failover(ctx context.Context, sessionID string, at time.Duration) (*PlaySession, error)
Stop(sessionID string)
Sessions() []*PlaySession
}
type PlaybackAccessPolicy ¶ added in v0.2.7
PlaybackAccessPolicy exposes the optional CanPlay capability.
type PlaybackEncoderInputs ¶ added in v0.3.0
type PlaybackEncoderInputs interface {
ReserveEncoderInput(context.Context, string, SourceRetirement) (EncoderInputLease, error)
}
type PlaybackPosition ¶ added in v0.2.7
PlaybackPosition exposes the optional RequestedPosition capability.
type PlaybackPreparer ¶ added in v0.2.7
PlaybackPreparer warms a title without reserving playback or changing history.
type PlaybackRevisionPin ¶ added in v0.3.0
type PlaybackRevisionPin interface {
PinSourceRevision(ctx context.Context, id, revision string) error
UnpinSourceRevision(id string)
}
PlaybackRevisionPin keeps an opened generation from silently failing over while a client consumes metadata bound to its source revision.
type PlaybackSourceHistory ¶ added in v0.3.0
type PlaybackSourceHistory struct {
Revision, ReleaseDigest, VideoCodec string
Height int
HDR *bool
}
PlaybackSourceHistory contains persisted source facts without raw release identifiers. A digest can only be matched against authorized candidates.
type PlaybackSourceObservation ¶ added in v0.3.0
type PlaybackSourceObservation struct {
Revision, ReleaseID string
VideoCodec string
Height int
HDR *bool
}
PlaybackSourceObservation contains scalar facts from one opened source generation. Empty Revision means its identity cannot be established safely; nil HDR and empty codec/zero height remain unknown.
type PlaybackSourceSnapshot ¶ added in v0.3.0
type PlaybackSourceSnapshot interface {
CurrentSource(context.Context, string) (PlaybackSourceObservation, error)
}
PlaybackSourceSnapshot copies immutable facts validated at source open/probe for the current generation. It performs no filesystem I/O and is not fresh authorization or a claim that a local path has remained unchanged.
type PlaybackTimeline ¶ added in v0.2.8
type PlaybackTimeline interface {
PlaybackProgress(userID int64, clientID string, key RatingKey, position time.Duration, state string)
}
PlaybackTimeline carries actual client position without changing history.
type Playlist ¶
type Playlist struct {
Key RatingKey `json:"key"`
UserID int64 `json:"userId"`
Title string `json:"title"`
Smart bool `json:"smart"`
Items []RatingKey `json:"items"`
UpdatedAt time.Time `json:"updatedAt"`
}
Playlists are user-created lists.
type Playlists ¶
type Playlists interface {
List(ctx context.Context, userID int64) ([]Playlist, error)
Get(ctx context.Context, userID int64, key RatingKey) (*Playlist, error)
Create(ctx context.Context, userID int64, title string, items []RatingKey) (*Playlist, error)
Add(ctx context.Context, userID int64, key RatingKey, items []RatingKey) error
Remove(ctx context.Context, userID int64, key RatingKey, itemIndex int) error
Move(ctx context.Context, userID int64, key RatingKey, from, to int) error
Delete(ctx context.Context, userID int64, key RatingKey) error
}
type PolicyHomeCandidateSource ¶ added in v0.3.0
type PolicyHomeCandidateSource interface {
HomeCandidatesWithPolicy(context.Context, *User, HubContext, int, func(context.Context, *User, *Title) bool) ([]Hub, error)
SectionCandidatesWithPolicy(context.Context, *User, MediaType, HubContext, int, func(context.Context, *User, *Title) bool) ([]Hub, error)
}
PolicyHomeCandidateSource filters a viewer's candidate pool before ranking and row limits. The caller supplies a fail-closed visibility predicate.
type PostPlayPick ¶
type PostPlayPick struct {
Title Title `json:"title"`
Score float64 `json:"score"`
TasteFit float64 `json:"tasteFit"`
Similarity float64 `json:"similarity"`
RuntimeFit float64 `json:"runtimeFit"`
Reason string `json:"reason,omitempty"`
}
PostPlayPick is one ranked post-play recommendation with its explained score components (item #30): Score = taste factor × similarity factor × runtime factor (× a continuation bonus for the franchise's next entry), where TasteFit is the raw taste fit (-1..1), Similarity the feature overlap with the just-watched title (0..1) and RuntimeFit how well the runtime fits the viewer's remaining time tonight (0..1).
type PostPlayer ¶
type PostPlayer interface {
PostPlay(ctx context.Context, user *User, justWatched RatingKey, hc HubContext, limit int) ([]PostPlayPick, error)
}
PostPlayer ranks a personalized post-play "hook queue" after a title. Implementations cache the ranking per user and just-watched title for the session, so the pick pre-buffered during playback is the pick the post-play endpoint returns first.
type PrefetchReaderAt ¶ added in v0.2.7
type PrefetchReaderAt interface {
ReadAtPrefetchContext(context.Context, []byte, int64) (int, error)
}
PrefetchReaderAt reads speculative bytes at background priority.
type PrewarmOptions ¶
type PrewarmOptions struct {
// Reason labels the trigger for logs and budgets (Prewarm* constants).
Reason string `json:"reason"`
// PrefetchBytes is how much of the opening of the file to pre-buffer at
// background priority once the release is resolved, opened and probed.
// Zero uses the implementation's default for the reason.
PrefetchBytes int64 `json:"prefetchBytes,omitempty"`
// DuringPlayback allows the warm-up while the viewer already has an
// active session (a trailer, or the end of a film, is playing).
DuringPlayback bool `json:"duringPlayback,omitempty"`
}
PrewarmOptions tune a speculative warm-up of a title before the viewer presses Play.
type Prewarmer ¶
type Prewarmer interface {
Prewarm(ctx context.Context, user *User, key RatingKey, caps ClientCaps, opts PrewarmOptions) bool
}
Prewarmer is implemented by playback managers that can resolve, open, probe and pre-buffer a title ahead of Play, so the later Prepare for the same user, client and title is near-instant. A warm-up never reserves a stream or writes resume/history records. It reports whether a warm-up was scheduled (false when skipped by budgets or already warm).
type ProcessCPUTime ¶ added in v0.2.7
ProcessCPUTime exposes the optional CPUTime capability.
type ProcessIdentity ¶ added in v0.2.7
type ProcessIdentity interface{ PID() int }
ProcessIdentity exposes the optional PID capability.
type ProcessPeakMemory ¶ added in v0.2.7
ProcessPeakMemory exposes the optional PeakRSSBytes capability.
type Protocol ¶ added in v0.3.0
type Protocol string
Protocol identifies a client-facing surface independently of client product.
type QualityProfile ¶
type QualityProfile struct {
ReleaseRules []ReleaseRule `json:"releaseRules,omitempty"`
Ranking []string `json:"ranking,omitempty"`
AllowedQualities []string `json:"allowedQualities,omitempty"` // imported source-resolution gates
CustomFormatScores map[string]int `json:"customFormatScores,omitempty"`
MinCustomFormatScore *int `json:"minCustomFormatScore,omitempty"`
Name string `json:"name"`
MaxHeight int `json:"maxHeight"` // cap, e.g. 1080
// ConfiguredMaxHeight is MaxHeight as the owner configured it,
// before download reshaping or a client's caps clamped the
// effective MaxHeight. -1 means the owner set no ceiling ("Any");
// 0 means unset (a profile built outside SelectProfile), in which
// case MaxHeight itself is the configured value. Runtime-only,
// never persisted with the profile.
ConfiguredMaxHeight int `json:"-"`
MinHeight int `json:"minHeight"` // floor, e.g. 720
AllowHDR bool `json:"allowHdr"` // only applied when the client also supports it
AllowDolbyVision bool `json:"allowDolbyVision"`
PreferredSources []Source `json:"preferredSources"` // best first
PreferredCodecs []string `json:"preferredCodecs"` // best first; codecs the client can't play are dropped anyway
PreferredAudio []string `json:"preferredAudio"`
MinSizeMBPerMin float64 `json:"minSizeMbPerMin"` // size sanity, per minute of runtime (movies, and fallback for TV)
MaxSizeMBPerMin float64 `json:"maxSizeMbPerMin"`
EpisodeMinSizeMBPerMin float64 `json:"episodeMinSizeMbPerMin,omitempty"` // optional TV episode size bounds (0 uses MinSizeMBPerMin/MaxSizeMBPerMin)
EpisodeMaxSizeMBPerMin float64 `json:"episodeMaxSizeMbPerMin,omitempty"`
PreferLargest bool `json:"preferLargest,omitempty"` // prefer larger files among candidates matching the profile
PreferredLanguages []string `json:"preferredLanguages"`
AllowCam bool `json:"allowCam"` // the only CAM switch; cinema recordings play only for profiles that allow them
// SelectionKey is the canonical hash of this profile's configured
// definition, computed by resolver.SelectProfile from the pristine
// configured profile before download reshaping or client-cap
// clamping. Release rules are part of that definition. The catalogue
// original language is not: it is per-title evaluation context, not a
// profile fact. Runtime-only, never persisted with the profile.
SelectionKey string `json:"-"`
}
QualityProfile is an owner-editable rule set ranking releases for a class of client.
func (QualityProfile) ComputeSelectionKey ¶ added in v0.2.48
func (p QualityProfile) ComputeSelectionKey() string
ComputeSelectionKey returns the canonical key of the configured definition in p: sha256 of its JSON (runtime-only fields tagged json:"-" are excluded) truncated to 16 hex chars. Any selection-field edit (heights, HDR/DV, codecs, sources, audio, languages, sizes, qualities, scores, release rules, ranking) changes it; client caps never enter it.
func (QualityProfile) EffectiveRanking ¶ added in v0.3.0
func (p QualityProfile) EffectiveRanking() []string
EffectiveRanking returns the complete ranking ladder for p: DefaultRanking when Ranking is empty, or p.Ranking with any unmentioned Prefer rules prepended and any omitted built-in steps placed in their default relative positions.
func (QualityProfile) SizeBoundsFor ¶ added in v0.2.58
func (p QualityProfile) SizeBoundsFor(t *Title) (minMBPerMin, maxMBPerMin float64)
SizeBoundsFor returns the configured (min, max) MB/min bounds for a title.
func (QualityProfile) SizeBoundsForKey ¶ added in v0.2.58
func (p QualityProfile) SizeBoundsForKey(key RatingKey) (minMBPerMin, maxMBPerMin float64)
SizeBoundsForKey returns the configured (min, max) MB/min bounds for a rating key. TV episodes use EpisodeMinSizeMBPerMin / EpisodeMaxSizeMBPerMin when positive, falling back to MinSizeMBPerMin / MaxSizeMBPerMin.
type RankerFeature ¶
type RankerFeature struct {
Name string `json:"name"`
Label string `json:"label"`
Weight float64 `json:"weight"`
}
RankerFeature is one learned weight, largest magnitude first.
type RankerInsight ¶
type RankerInsight struct {
TrainedAt *time.Time `json:"trainedAt,omitempty"`
// Examples/Positives are the impressions and plays the model last
// trained on.
Examples int `json:"examples"`
Positives int `json:"positives"`
// AUC of the learned model and of the hand-tuned baseline on held-out
// impressions (0.5 = chance). Zero when there is not enough data.
AUC float64 `json:"auc"`
BaselineAUC float64 `json:"baselineAuc"`
// Active is true when the learned model is being used for ranking.
Active bool `json:"active"`
Features []RankerFeature `json:"features"`
}
RankerInsight describes the learned ranking model for the owner UI.
type RatingKey ¶
type RatingKey int64
RatingKey is the Plex ratingKey of an Ether item. It is derived from TMDB identifiers so a title keeps the same key before and after anything about it is resolved or cached.
Layout (decimal, kept below 2^53 so JavaScript clients parse it safely):
kind * 10^15 + payload
KindMovie payload = tmdb movie id
KindShow payload = tmdb tv id
KindSeason payload = show*10^4 + season (season < 10^4)
KindEpisode payload = show*10^7 + season*10^4 + ep (show < 10^8, season < 1000, ep < 10^4)
KindCollection payload = tmdb collection id (franchise)
KindSmart payload = local smart-collection / generated hub id;
payloads in [EphemeralSmartBase, EphemeralSmartEnd)
are reserved for ephemeral (in-memory, per-viewer)
generated collections, and payloads from
EphemeralSmartEnd up for personalize's Year in Review
collections; database ids stay far below both
KindPlaylist payload = local playlist id
KindExtra payload = compact extra id from the extras registry
KindLocal payload = local file id (spike / test library)
func CollectionKey ¶
func EphemeralSmartKey ¶
EphemeralSmartKey builds an ephemeral collection key from a sequence number (1 .. 10^14-1).
func EpisodeKey ¶
func ParseRatingKey ¶
func PlaylistKey ¶
func (RatingKey) IsEphemeral ¶
IsEphemeral reports whether k is an ephemeral generated collection key.
type ReadRetirement ¶ added in v0.3.0
type ReadRetirement struct {
// contains filtered or unexported fields
}
ReadRetirement tracks producer references belonging to one media request. Seal returns a channel closed only after all registered producers release their references. It does not wait or cancel those producers and does not prove that the underlying MediaSource.Close succeeded.
func ReadRetirementFrom ¶ added in v0.3.0
func ReadRetirementFrom(ctx context.Context) *ReadRetirement
ReadRetirementFrom returns the tracker attached to ctx, if any.
func (*ReadRetirement) Begin ¶ added in v0.3.0
func (t *ReadRetirement) Begin() (func(), bool)
Begin registers one producer before it starts. Once sealed, registrations fail closed; a successful registration must call its returned function once.
func (*ReadRetirement) Seal ¶ added in v0.3.0
func (t *ReadRetirement) Seal() <-chan struct{}
Seal rejects later producers and returns the completion signal.
type Recommender ¶
type Recommender interface {
// HomeHubs are the rows on the Home screen across both sections.
HomeHubs(ctx context.Context, user *User, limit int) ([]Hub, error)
// SectionHubs are the rows at the top of a library section.
SectionHubs(ctx context.Context, user *User, t MediaType, limit int) ([]Hub, error)
// Related are rows on a detail page ("More like this", franchise).
Related(ctx context.Context, user *User, key RatingKey, limit int) ([]Hub, error)
}
Recommender produces per-user Home and section rows.
type RecoveryBuffer ¶ added in v0.2.8
type RecoveryBuffer struct {
Position, ReadyUntil time.Duration
SeekAt time.Time // a discontinuous output request invalidates older telemetry
// DeliveredUntil is contiguous complete HTTP delivery, not a promise that
// the client retained or decoded it. Zero means unavailable.
DeliveredUntil time.Duration
}
RecoveryBuffer reports contiguous, published media, not the encoder's input offset. It deliberately does not claim that bytes reached the client.
type RecoveryBufferSource ¶ added in v0.2.8
type RecoveryBufferSource interface{ RecoveryBuffer() RecoveryBuffer }
type Release ¶
type Release struct {
ID string `json:"id"` // stable: sha1(indexer + guid)
GUID string `json:"guid"` // indexer guid
Indexer string `json:"indexer"` // indexer name
Name string `json:"name"` // release name
NZBURL string `json:"nzbUrl"`
Size int64 `json:"size"`
PubDate time.Time `json:"pubDate"`
Grabs int `json:"grabs,omitempty"`
Password bool `json:"password,omitempty"` // indexer flagged passworded
Category int `json:"category,omitempty"`
Info ReleaseInfo `json:"info"`
Score float64 `json:"score"`
// TitleIDs are movie/series identifiers reported by the indexer. They
// must never be inferred from the search request's identifiers.
TitleIDs IDs `json:"titleIds,omitempty"`
// Torrent releases (additive). Protocol is "" for Usenet and
// ProtocolTorrent for Torznab results; torrents are streamed through
// an owner-configured debrid service (internal/debrid).
Protocol string `json:"protocol,omitempty"`
InfoHash string `json:"infoHash,omitempty"` // lower-case hex BitTorrent v1 info hash
MagnetURL string `json:"magnetUrl,omitempty"`
Seeders int `json:"seeders,omitempty"`
Peers int `json:"peers,omitempty"`
// Target narrows a multi-file release (a season pack) to the wanted
// episode; set by the resolver on candidates before fetching.
Target *ReleaseTarget `json:"target,omitempty"`
// DebridCached and DebridUncached name the debrid services (config
// Debrid* kinds) the source reported as holding, or not holding, the
// torrent, such as a Stremio addon's cached marker (additive). Hints
// only: a provider's own answer always wins.
DebridCached []string `json:"debridCached,omitempty"`
DebridUncached []string `json:"debridUncached,omitempty"`
// HTTP stream releases (ProtocolHTTP, additive). StreamURL is the URL
// the addon answered with; it and StreamHeaders (request headers the
// addon requires) can carry the addon's credentials, so they never
// leave the server. StreamOrigin is the owner-configured addon origin
// (scheme://host:port), the only private address the URL may reach.
StreamURL string `json:"streamUrl,omitempty"`
StreamHeaders map[string]string `json:"streamHeaders,omitempty"`
StreamOrigin string `json:"streamOrigin,omitempty"`
}
Release is an indexer search result for a title.
type ReleaseBlockChecker ¶ added in v0.2.34
ReleaseBlockChecker lets stored source consumers honor durable owner blocks. Errors must prevent reuse, rather than silently bypassing the blocklist.
type ReleaseCondition ¶ added in v0.2.49
type ReleaseCondition struct {
Field string `json:"field"`
Operator string `json:"operator"` // equals, contains, regex, range
Value string `json:"value,omitempty"`
Min float64 `json:"min,omitempty"`
Max float64 `json:"max,omitempty"`
}
ReleaseCondition inspects declared release metadata, never presumed language. Language and subtitle facts describe the indexer's/name's declarations, not verified tracks. A missing fact is unknown, not a successful negative match. audio_matches_original takes no value: evaluation compares declared audio with the catalogue original language supplied beside the release.
type ReleaseFeed ¶ added in v0.2.8
type ReleaseFeed struct {
Categories []int `json:"categories,omitempty"` // local filter when a feed ignores category queries
ID string `json:"id"`
Name string `json:"name"`
Generation string `json:"-"`
Protocol string `json:"protocol"`
Supported bool `json:"supported"`
Reason string `json:"reason,omitempty"`
// DailyLimit is the indexer's own cap. Zero means unlimited.
DailyLimit int `json:"dailyLimit,omitempty"`
// PageMax is the page size reported by caps. Zero means unknown.
PageMax int `json:"pageMax,omitempty"`
}
ReleaseFeed describes an indexer's recent-release discovery capability.
type ReleaseHealthChecker ¶
type ReleaseHealthChecker interface {
HealthChecker
CheckRelease(ctx context.Context, releaseID string, nzb []byte) (healthy bool, err error)
}
ReleaseHealthChecker is a HealthChecker that is also told which release the NZB belongs to, so what the check reads (the PAR2 index, archive headers) lands in the segment cache under the ID a following Open uses. Optional: callers fall back to Check when it is not implemented (additive).
type ReleaseInfo ¶
type ReleaseInfo struct {
Title string `json:"title"`
Edition string `json:"edition,omitempty"`
Year int `json:"year,omitempty"`
Seasons []int `json:"seasons,omitempty"`
Episodes []int `json:"episodes,omitempty"`
FullSeason bool `json:"fullSeason,omitempty"`
Height int `json:"height,omitempty"` // 480, 720, 1080, 2160
Source Source `json:"source,omitempty"`
VideoCodec string `json:"videoCodec,omitempty"` // h264, hevc, av1
HDR10 bool `json:"hdr10,omitempty"`
DolbyVision bool `json:"dolbyVision,omitempty"`
AudioCodec string `json:"audioCodec,omitempty"` // aac, ac3, eac3, truehd, dts, dtshd
Atmos bool `json:"atmos,omitempty"`
Channels string `json:"channels,omitempty"` // "5.1"
Group string `json:"group,omitempty"`
Languages []string `json:"languages,omitempty"`
// SubtitleLanguages are subtitle languages a release declares without
// claiming the audio (VOSTFR, VOSE, SUBFRENCH) (additive).
SubtitleLanguages []string `json:"subtitleLanguages,omitempty"`
// AbsoluteEpisodes are episode numbers counted from the series start,
// as anime releases number them ("Show - 1071") (additive).
AbsoluteEpisodes []int `json:"absoluteEpisodes,omitempty"`
Proper bool `json:"proper,omitempty"`
Repack bool `json:"repack,omitempty"`
Container string `json:"container,omitempty"`
}
ReleaseInfo is what can be parsed from a release name.
type ReleaseRule ¶ added in v0.2.49
type ReleaseRule struct {
ID string `json:"id"`
Name string `json:"name"`
Action string `json:"action"` // require, prefer, avoid (exclude)
Match string `json:"match,omitempty"` // all (default) or any
Conditions []ReleaseCondition `json:"conditions"`
Unless []ReleaseCondition `json:"unless,omitempty"` // any matching exception skips the rule
Fallback []ReleaseCondition `json:"fallback,omitempty"` // require only, any matching condition
Disabled bool `json:"disabled,omitempty"`
}
ReleaseRule is a protocol-neutral owner preference. Ordered soft preferences break ties lexicographically before ordinary quality scores. All hard rules must pass. Empty rules preserve existing profile behavior.
type ReleaseSizeSource ¶ added in v0.2.7
ReleaseSizeSource exposes the optional ReleaseSizes capability.
type ReleaseTarget ¶
type ReleaseTarget struct {
Season int `json:"season,omitempty"`
Episode int `json:"episode,omitempty"`
ShowYear int `json:"showYear,omitempty"`
EpisodeTitle string `json:"episodeTitle,omitempty"`
// ExpectedIDs identify the requested series; ReportedIDs are the
// release's indexer-reported series IDs, retained for file validation.
ExpectedIDs IDs `json:"expectedIds,omitempty"`
ReportedIDs IDs `json:"reportedIds,omitempty"`
}
ReleaseTarget is the episode wanted from a multi-file release such as a season pack.
type ReleaseVariant ¶
type ReleaseVariant struct {
// ID is stable for the title and release; front ends encode it (or its
// position) in Media/Part ids.
ID string `json:"id"`
// Label is the viewer-facing name, e.g. "4K Dolby Vision Remux" or
// "1080p WEB-DL (High Compatibility)".
Label string `json:"label"`
// Edition is the cut, e.g. "Director's Cut", "Extended", "IMAX"; empty
// for the theatrical/unspecified cut.
Edition string `json:"edition,omitempty"`
// Auto marks the resolver's own pick for this client ("Best for Device").
Auto bool `json:"auto,omitempty"`
Release Release `json:"release"`
// Info is the expected media info, estimated from the release name until
// the release has been probed.
Info MediaInfo `json:"info"`
}
ReleaseVariant is one playable version of a title, offered in the Plex "Play Version" picker: a distinct candidate release, by quality tier or edition (cut).
type RemuxRequirer ¶
RemuxRequirer is implemented by playback managers that can report whether a session must be (re)started as a zero-encode remux (HLS/DASH) rather than direct play — set when a mid-stream failover of a non-spliceable direct-play session found no exact-size replacement release, so the client needs fresh container headers at the mapped timestamp.
type RepairEvent ¶ added in v0.2.8
type RepairEvent struct {
Key int
Attempt uint64 // distinguishes concurrent readers repairing one article
Offset int64
Approximate bool
Phase string // missing, planning, repairing, repaired, failed, obsolete
Estimate time.Duration
RemainingBytes int64
}
RepairEvent reports verified damage and bounded recovery work. Offset is in the selected media file, never an NNTP article or archive-volume coordinate. Estimate is conservative, not a guarantee; zero means not yet known.
type RepairReporter ¶ added in v0.2.8
type RepairReporter interface {
SetRepairHandler(func(RepairEvent) RepairWindow)
}
type RepairWindow ¶ added in v0.2.8
RepairWindow is playback's current useful repair lifetime. A zero deadline leaves the source's ordinary bound in force. Stop cancels obsolete work.
type RescueIndexer ¶ added in v0.2.7
type RescueIndexer interface {
SearchRescue(context.Context, SearchRequest) ([]Release, error)
}
RescueIndexer exposes the optional SearchRescue capability.
type Resolution ¶
type Resolution struct {
Title RatingKey `json:"title"`
Release Release `json:"release"`
NZB []byte `json:"-"`
Alternates []Release `json:"alternates"` // next candidates, best first
ResolvedAt time.Time `json:"resolvedAt"`
}
Resolution is the resolver's answer for a title and client: the winning release, already health-checked, plus fallbacks for mid-stream failover.
type ResolveRequest ¶
type ResolveRequest struct {
Title *Title
Client ClientCaps
User *User
// PlayedRelease is the release this viewer last played of the title
// (the one a resume opens); Variants names Auto after it (additive).
PlayedRelease string
// Exclude releases already tried (failover).
Exclude []string
// Prefer is a release ID to try first (the viewer picked a version in
// Plex's "Play Version" picker). It is health-checked like any other
// candidate; when it is unavailable, normal ranking applies (additive).
Prefer string
// ExactHEVCTranscode permits the explicitly preferred HEVC source to reach
// playback admission for an H.264 encode. The broker must still validate
// the probed source and the client's complete output profile.
ExactHEVCTranscode bool
}
type Resolver ¶
type Resolver interface {
// Resolve finds a healthy release. Returns ErrNotAvailable when nothing
// acceptable exists.
Resolve(ctx context.Context, req ResolveRequest) (*Resolution, error)
// MarkBad records a release as broken so nobody gets it again.
MarkBad(ctx context.Context, releaseID string, reason string) error
// Available reports a cached availability answer without searching:
// (known, available).
Available(ctx context.Context, key RatingKey) (known bool, available bool)
}
type RowDescriptor ¶
type RowDescriptor struct {
HubID string `json:"hubId"`
Title string `json:"title"`
Kind string `json:"kind"`
Description string `json:"description"`
// Sections lists the pages this row can appear on ("home", "movies",
// "shows"); empty means every page.
Sections []string `json:"sections,omitempty"`
// Group is the designer's category: "picks", "explore", "shows",
// "household", "collections" or "plex".
Group string `json:"group,omitempty"`
}
RowDescriptor describes a kind of row the owner can place in the Home layout.
type RowInsight ¶
type RowInsight struct {
HubID string `json:"hubId"`
Title string `json:"title"`
Impressions7d int `json:"impressions7d"`
Plays7d int `json:"plays7d"`
PlayRate float64 `json:"playRate"`
}
RowInsight is the 7-day engagement of one row kind.
type RowPolicy ¶
type RowPolicy struct {
Row string `json:"row"`
Status string `json:"status"`
Slot int `json:"slot,omitempty"`
MinSlot int `json:"minSlot,omitempty"`
MaxSlot int `json:"maxSlot,omitempty"`
Priority float64 `json:"priority,omitempty"`
MaxPerPage int `json:"maxPerPage,omitempty"`
MaxDaysPerWeek int `json:"maxDaysPerWeek,omitempty"`
When *LayoutWhen `json:"when,omitempty"`
}
type RowPurpose ¶ added in v0.3.0
type RowPurpose string
RowPurpose describes the semantic reason for a row, independent of its wire representation.
type SearchCacheRefiller ¶ added in v0.2.56
type SearchCacheRefiller interface {
RefillSearchCache(*Title) <-chan struct{}
}
SearchCacheRefiller requests best-effort, non-blocking candidate recovery for an admitted detail warm-up reusing a remembered source. It searches only; it must not resolve or replace a playback source. The resolver owns the work independently of request/warm-up cancellation and joins it on Close. A nil signal means skipped; otherwise the signal closes when the existing or newly admitted refill finishes (not necessarily successfully).
type SearchRequest ¶
type SearchRequest struct {
Type MediaType // movie or episode
IDs IDs // movie ids, or the show's ids for episodes
Title string
OriginalTitle string // optional original-language or canonical title (additive)
Year int
Season int
Episode int
EpisodeTitle string // optional title used to distinguish same-numbered episodes
// AbsoluteEpisode is the episode's number counted from the series
// start (0 = unknown), and Anime marks a series whose releases are
// commonly numbered that way (additive).
AbsoluteEpisode int
Anime bool
// AlternativeTitles are other names of the movie or series (TMDB
// alternative titles) a release name may use; matching only, never
// part of a query or cache key (additive).
AlternativeTitles []string `json:"-"`
}
type SectionCandidateSource ¶ added in v0.2.7
type SectionCandidateSource interface {
SectionCandidatesFor(context.Context, *User, MediaType, HubContext, int) ([]Hub, error)
}
SectionCandidateSource exposes the optional SectionCandidatesFor capability.
type SegmentCache ¶
type SegmentCache interface {
Get(releaseID string, segment int) ([]byte, bool)
Put(releaseID string, segment int, data []byte) error
// Pin protects every segment of a release from eviction.
Pin(releaseID string, reason string) error
Unpin(releaseID string, reason string) error
Usage() (used, budget int64)
}
SegmentCache stores decoded segments on disk under an LRU budget.
type SegmentPresence ¶ added in v0.2.7
SegmentPresence exposes the optional Has capability.
type SessionActivity ¶ added in v0.2.9
type SessionActivity interface{ PlaybackState(state string) }
SessionActivity is an optional output-session extension. Only authenticated, ownership-checked player timelines may renew it; playlist polls may not.
type ShowTrajectory ¶ added in v0.2.7
type ShowTrajectory struct {
ShowKey RatingKey `json:"showKey"`
EarlyRating float64 `json:"earlyRating,omitempty"`
FinaleRating float64 `json:"finaleRating,omitempty"`
PeakRating float64 `json:"peakRating,omitempty"`
RatedSeasons int `json:"ratedSeasons,omitempty"`
SticksLanding bool `json:"sticksLanding,omitempty"`
}
ShowTrajectory summarizes a series' season/episode rating arc (additive).
type SortOrder ¶
type SortOrder string
const ( SortPopularity SortOrder = "popularity" SortTitle SortOrder = "title" SortReleased SortOrder = "released" SortYear SortOrder = "year" SortRating SortOrder = "rating" SortDuration SortOrder = "duration" SortAdded SortOrder = "added" // movie/episode release or air date; series and seasons use the latest aired episode, then the premiere SortUpdated SortOrder = "updated" // actual catalogue metadata update time )
type SourceDeliveryObserver ¶ added in v0.2.9
SourceDeliveryObserver receives uncached source throughput evidence. It is neither client bandwidth nor a claim about an entire provider network.
type SourceRetirement ¶ added in v0.3.0
type SourceRetirement interface {
Done() <-chan struct{}
Err() error
}
SourceRetirement reports backend responsibility for one exact manager source lifetime, including provisional and prior generations. Done is terminal; Err is nil only after Done, successful Close of every acquired source and settlement of its durable payload cleanup. Pending cleanup keeps Done open; a terminal backend Close error never becomes success. This does not prove encoder retirement or a durable ownership transfer.
type State ¶
type State interface {
Get(ctx context.Context, userID int64, key RatingKey) (WatchStatus, error)
GetMany(ctx context.Context, userID int64, keys []RatingKey) (map[RatingKey]WatchStatus, error)
// Progress records a timeline update. Crossing 90% marks it watched.
Progress(ctx context.Context, userID int64, key RatingKey, offset, duration time.Duration, state string) error
Scrobble(ctx context.Context, userID int64, key RatingKey) error // mark watched
Unscrobble(ctx context.Context, userID int64, key RatingKey) error // mark unwatched
Rate(ctx context.Context, userID int64, key RatingKey, rating float64) error
// OnDeck: in-progress items and next episodes, most recent first.
InProgress(ctx context.Context, userID int64, limit int) ([]WatchStatus, error)
History(ctx context.Context, userID int64, since time.Time, limit int) ([]HistoryEntry, error)
// InProgressAny lists keys in progress for any user (cache protection, prefetch).
InProgressAny(ctx context.Context) ([]RatingKey, error)
}
type StoredTitleLookup ¶ added in v0.2.37
StoredTitleLookup reads local metadata without remote discovery. Callers must apply their own authorization before exposing the returned title.
type StreamInfo ¶
type StreamInfo struct {
// Probe hints for enhancement backends that require progressive, steady-rate input.
Interlaced bool `json:"interlaced,omitempty"`
VariableFrameRate bool `json:"variableFrameRate,omitempty"`
Index int `json:"index"`
Type string `json:"type"` // video, audio, subtitle
Codec string `json:"codec"`
Profile string `json:"profile,omitempty"`
Level int `json:"level,omitempty"`
Language string `json:"language,omitempty"`
Title string `json:"title,omitempty"`
CodecLongName string `json:"codecLongName,omitempty"`
Default bool `json:"default,omitempty"`
Forced bool `json:"forced,omitempty"`
// Nil means the source did not report this ffprobe disposition.
DefaultDisposition *bool `json:"defaultDisposition,omitempty"`
ForcedDisposition *bool `json:"forcedDisposition,omitempty"`
HearingImpaired *bool `json:"hearingImpaired,omitempty"`
Original *bool `json:"original,omitempty"`
VisualImpaired *bool `json:"visualImpaired,omitempty"`
Commentary *bool `json:"commentary,omitempty"`
Dub *bool `json:"dub,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
FrameRate float64 `json:"frameRate,omitempty"`
// Optional probe facts are nil/empty when the source did not report them.
AverageFrameRate *float64 `json:"averageFrameRate,omitempty"`
ReferenceFrameRate *float64 `json:"referenceFrameRate,omitempty"`
DisplayAspectRatio string `json:"displayAspectRatio,omitempty"`
PixelFormat string `json:"pixelFormat,omitempty"`
CodecTag string `json:"codecTag,omitempty"`
TimeBase string `json:"timeBase,omitempty"`
NALLengthSize *int `json:"nalLengthSize,omitempty"`
ReferenceFrames *int `json:"referenceFrames,omitempty"`
BitsPerRawSample *int `json:"bitsPerRawSample,omitempty"`
ProbedLevel *int `json:"probedLevel,omitempty"`
FieldOrder string `json:"fieldOrder,omitempty"`
ProbedInterlaced *bool `json:"probedInterlaced,omitempty"`
BitDepth int `json:"bitDepth,omitempty"`
ColorTransfer string `json:"colorTransfer,omitempty"` // smpte2084 = HDR10, arib-std-b67 = HLG
// Signalled picture format, in ffprobe's names; empty when the stream
// and container leave it unspecified (decoders then assume square
// pixels and limited range).
SampleAspectRatio string `json:"sampleAspectRatio,omitempty"` // "N:D"
ColorRange string `json:"colorRange,omitempty"` // tv, pc
ColorPrimaries string `json:"colorPrimaries,omitempty"` // bt709, bt2020, smpte170m...
ColorSpace string `json:"colorSpace,omitempty"` // matrix: bt709, bt2020nc, smpte170m...
DolbyVision bool `json:"dolbyVision,omitempty"`
// HDR10Plus is nil unless the probe provides affirmative or explicit negative evidence.
HDR10Plus *bool `json:"hdr10Plus,omitempty"`
Channels int `json:"channels,omitempty"`
ChannelLayout string `json:"channelLayout,omitempty"`
SampleRate int `json:"sampleRate,omitempty"`
BitrateKbps int `json:"bitrateKbps,omitempty"`
External bool `json:"external,omitempty"` // sidecar subtitle (OpenSubtitles)
ExternalURL string `json:"externalUrl,omitempty"`
// DolbyVisionProfile is the DV profile (5, 7, 8...) from the DOVI
// configuration record; 0 when unknown or not Dolby Vision.
DolbyVisionProfile int `json:"dolbyVisionProfile,omitempty"`
DolbyVisionLevel int `json:"dolbyVisionLevel,omitempty"`
DolbyVisionCompatibilityID int `json:"dolbyVisionCompatibilityId,omitempty"`
CodecString string `json:"codecString,omitempty"` // RFC 6381, derived from the codec configuration
// Configuration presence is known from a completed MP4/Matroska container
// probe; nil means unprobed, unsupported or ambiguous. Codec tags alone do
// not establish whether enhancement/base layers or RPU are present.
DolbyVisionConfigurationPresent *bool `json:"dolbyVisionConfigurationPresent,omitempty"`
DolbyVisionBLCompatibilityIDPresent *bool `json:"dolbyVisionBLCompatibilityIdPresent,omitempty"`
ProbedDolbyVisionProfile *int `json:"probedDolbyVisionProfile,omitempty"`
ProbedDolbyVisionLevel *int `json:"probedDolbyVisionLevel,omitempty"`
DolbyVisionVersion string `json:"dolbyVisionVersion,omitempty"`
DolbyVisionBLPresent *bool `json:"dolbyVisionBLPresent,omitempty"`
DolbyVisionELPresent *bool `json:"dolbyVisionELPresent,omitempty"`
DolbyVisionRPUPresent *bool `json:"dolbyVisionRPUPresent,omitempty"`
}
type StreamingIndexer ¶ added in v0.2.7
type StreamingIndexer interface {
SearchWith(context.Context, SearchRequest, func([]Release)) ([]Release, error)
}
StreamingIndexer exposes the optional SearchWith capability.
type StreamingRescueIndexer ¶ added in v0.2.7
type StreamingRescueIndexer interface {
SearchRescueWith(context.Context, SearchRequest, func([]Release)) ([]Release, error)
}
StreamingRescueIndexer exposes the optional SearchRescueWith capability.
type StringFilter ¶ added in v0.3.0
StringFilter narrows a string column with a Plex string operator ("=", "!=", "==", "!==", "<=", ">=").
type SubtitleExtractor ¶ added in v0.2.49
type SubtitleExtractor interface {
ExtractSubtitle(ctx context.Context, inputURL string, streamIndex int, codec string, w io.Writer) error
}
SubtitleExtractor is optionally implemented by transcoders that can write an embedded text subtitle stream as WebVTT, so a track picked mid-playback can be served from the transcode session without a restart. Image subtitles (PGS/VobSub) return an error.
type SurfaceScopedPlayback ¶ added in v0.3.0
type SurfaceScopedPlayback interface {
PrepareSurface(ctx context.Context, user *User, key RatingKey, caps ClientCaps, releaseID string, exact bool) (*PlaySession, error)
SessionForSurface(surface string, userID int64, clientID string, key RatingKey, releaseID string, exact bool) (*PlaySession, bool)
MarkSurfaceOpened(id string) bool
MarkSurfacePrepared(id string) bool
}
SurfaceScopedPlayback separates client identifiers by their authenticated protocol surface, even when different clients supply identical IDs.
type TasteDecade ¶
TasteDecade is an affinity for a release decade (1990 = the 90s).
type TasteHabits ¶
type TasteHabits struct {
WeeknightMinutes float64 `json:"weeknightMinutes"` // typical minutes watched on an active weeknight
WeekendMinutes float64 `json:"weekendMinutes"` // typical minutes watched on an active weekend day
PreferredDevice string `json:"preferredDevice"` // DeviceTV, DeviceMobile, ... or ""
BingeScore float64 `json:"bingeScore"` // 0..1: share of episodes watched in same-day runs of 3+
RewatchScore float64 `json:"rewatchScore"` // 0..1: share of finished titles watched again
PeakHours []int `json:"peakHours"` // most common start hours (local), busiest first
}
TasteHabits are a viewer's learned viewing habits.
type TasteLanguage ¶
TasteLanguage is an affinity for an original language (ISO 639-1).
type TasteOverride ¶
type TasteOverride struct {
Kind string `json:"kind"`
Value string `json:"value"`
Weight float64 `json:"weight"`
}
TasteOverride is an owner correction applied on top of the learned model: Kind "genre" (Value = genre name), "person" (Value = TMDB person id) or "keyword" (Value = keyword); Weight -1..1 replaces the learned weight.
type TastePerson ¶
type TastePerson struct {
ID int64 `json:"id"`
Name string `json:"name"`
Role string `json:"role"` // "director", "writer", "actor"
Weight float64 `json:"weight"`
Image string `json:"image,omitempty"` // browser-loadable URL
}
TastePerson is an affinity for a cast or crew member.
type TasteProfile ¶
type TasteProfile struct {
UserID int64 `json:"userId"`
UpdatedAt time.Time `json:"updatedAt"`
Confidence float64 `json:"confidence"` // 0..1, grows with history
Genres []TasteWeight `json:"genres"`
People []TastePerson `json:"people"`
Keywords []TasteWeight `json:"keywords"`
Decades []TasteDecade `json:"decades"`
Languages []TasteLanguage `json:"languages"`
Habits TasteHabits `json:"habits"`
Overrides []TasteOverride `json:"overrides"`
}
TasteProfile is the explainable view of one viewer's taste model.
type TasteWeight ¶
TasteWeight is one named affinity, weight in -1..1.
type TimelineAligner ¶
type TimelineAligner interface {
AlignTime(ctx context.Context, req AlignRequest, at time.Duration) (mapped time.Duration, ok bool)
}
TimelineAligner maps a moment in one release to the same moment in another release of the title using dialogue (subtitle) timing rather than video, so nothing has to be downloaded. The mapping may be piecewise (different cuts or intros shift later timestamps). ok is false when there is no confident alignment; callers then fall back to duration-based alignment.
type Title ¶
type Title struct {
Key RatingKey `json:"key"`
Type MediaType `json:"type"`
IDs IDs `json:"ids"`
// Seasons and episodes.
ShowKey RatingKey `json:"showKey,omitempty"`
ShowIDs IDs `json:"showIds,omitempty"`
ShowTitle string `json:"showTitle,omitempty"`
ShowOriginalTitle string `json:"showOriginalTitle,omitempty"` // canonical original series name, distinct from episode title
ShowYear int `json:"showYear,omitempty"` // series premiere year, distinct from episode air year
SeasonTitle string `json:"seasonTitle,omitempty"`
Season int `json:"season,omitempty"`
Episode int `json:"episode,omitempty"`
// AbsoluteEpisode counts an episode from the series start across its
// regular seasons; 0 when an earlier season's size is unknown (additive).
AbsoluteEpisode int `json:"absoluteEpisode,omitempty"`
Title string `json:"title"`
OriginalTitle string `json:"originalTitle,omitempty"`
SortTitle string `json:"sortTitle,omitempty"`
Tagline string `json:"tagline,omitempty"`
Summary string `json:"summary,omitempty"`
Year int `json:"year,omitempty"`
// PrimaryReleased is TMDB's primary release_date for a movie. The title
// year comes from it. Released stays the date added (theatrical, when
// one exists). Empty when the year came from a premiere or the release
// itself. Not serialized.
PrimaryReleased time.Time `json:"-"`
// YearSource records which date produced Year: primary, premiere,
// released, none, or missing. Empty means a row stored before that
// date was kept. Not serialized.
YearSource string `json:"-"`
Released time.Time `json:"released,omitempty"` // first air / release date
AddedAt time.Time `json:"addedAt,omitzero"` // series/season latest aired episode, or a derived air date; not a catalogue insertion time
LastAirDate time.Time `json:"lastAirDate,omitzero"` // last aired episode date when known
HomeReleaseChecked bool `json:"homeReleaseChecked,omitempty"`
HomeReleased time.Time `json:"homeReleased,omitempty"`
HomeReleaseFallbackAdmitted bool `json:"homeReleaseFallbackAdmitted,omitempty"`
Runtime time.Duration `json:"runtime,omitempty"`
Status string `json:"status,omitempty"` // TMDB status: Released, In Production, Ended...
Genres []string `json:"genres,omitempty"`
Keywords []string `json:"keywords,omitempty"` // TMDB keywords (lower-case), for content-based recommendations
// AlternativeTitles are other names the title goes by (TMDB alternative
// titles: romanized originals, regional and working titles). Release
// matching only; never serialized (additive). Episodes and seasons carry
// their series' in ShowAlternativeTitles.
AlternativeTitles []string `json:"-"`
ShowAlternativeTitles []string `json:"-"`
RemoteTrailerName string `json:"remoteTrailerName,omitempty"`
RemoteTrailerURL string `json:"remoteTrailerURL,omitempty"`
Studios []string `json:"studios,omitempty"`
Countries []string `json:"countries,omitempty"`
Language string `json:"language,omitempty"` // ISO 639-1 original language
// ContentRating is the certification in contentrating's stored form:
// bare US labels ("PG", "TV-14"), region-qualified otherwise ("de/6").
ContentRating string `json:"contentRating,omitempty"`
// ContentRatingSource records where ContentRating came from: "tmdb:US:6"
// (TMDB, country, movie release type), "tmdb:CA" (TV), "omdb", "mdblist".
ContentRatingSource string `json:"contentRatingSource,omitempty"`
Adult bool `json:"adult,omitempty"`
Rating float64 `json:"rating,omitempty"` // TMDB vote average 0-10
VoteCount int `json:"voteCount,omitempty"`
Popularity float64 `json:"popularity,omitempty"`
PosterPath string `json:"posterPath,omitempty"`
BackdropPath string `json:"backdropPath,omitempty"`
StillPath string `json:"stillPath,omitempty"` // episodes
LogoPath string `json:"logoPath,omitempty"`
Cast []Person `json:"cast,omitempty"`
Directors []Person `json:"directors,omitempty"`
Writers []Person `json:"writers,omitempty"`
Crew []Person `json:"crew,omitempty"` // creators, cinematographers, composers (additive)
CollectionID int64 `json:"collectionId,omitempty"` // TMDB franchise
CollectionName string `json:"collectionName,omitempty"`
ChildCount int `json:"childCount,omitempty"` // seasons of a show, episodes of a season
LeafCount int `json:"leafCount,omitempty"` // episodes of a show
UpdatedAt time.Time `json:"updatedAt,omitempty"`
}
Title is a catalogue item: movie, show, season or episode. Image paths are TMDB paths ("/abc.jpg"); the front end turns them into URLs.
func (*Title) DateAdded ¶ added in v0.3.0
DateAdded is the owner date-added rule. A movie uses its release date and an episode uses its air date. A series uses the air date of its most recently aired episode, then its first-air date. A season uses the latest aired episode in that season, then the season premiere. Those series and season dates are carried on AddedAt after catalogue hydration; a virtual season with no premiere of its own uses the same field. Catalogue insertion, first observation, metadata refresh, file modification and release-publication times are never the date added. Future dates are unknown.
type TransactionalMarkedPlaylists ¶ added in v0.3.0
type TransactionalMarkedPlaylists interface {
EnsureMarkedPlaylistTx(context.Context, *sql.Tx, int64, string, string) (RatingKey, error)
DeleteMarkedPlaylistTx(context.Context, *sql.Tx, int64, string) error
MarkedPlaylistKeyTx(context.Context, *sql.Tx, int64, string) (RatingKey, error)
}
TransactionalMarkedPlaylists joins marked-playlist creation to an existing shared database transaction.
type Transcoder ¶
type Transcoder interface {
Probe(ctx context.Context, inputURL string) (*MediaInfo, error)
Decide(info MediaInfo, caps ClientCaps, opts DecideOptions) Decision
// StartHLS starts an HLS session, a DASH session (a DASHSession)
// when req.Protocol is ProtocolDASH, or an HTTP Matroska session
// (an HTTPSession) when req.Protocol is ProtocolHTTP.
StartHLS(ctx context.Context, req HLSRequest) (HLSSession, error)
Session(id string) (HLSSession, bool)
Stop(id string)
HWAccel() HWAccel
}
type TrickplayCanceler ¶ added in v0.2.7
type TrickplayCanceler interface{ CancelTrickplay(string) }
TrickplayCanceler exposes the optional CancelTrickplay capability.
type TrickplayLease ¶ added in v0.3.0
type TrickplayLease interface {
Ensure(context.Context, TrickplaySource)
Release(cancelIfIdle bool)
}
TrickplayLease holds one release. Ensure after Release is inert. Release is idempotent; cancelIfIdle applies the caller's idle policy only when no other holder remains. Only the runtime owner can Close the provider.
type TrickplayLeaser ¶ added in v0.3.0
type TrickplayLeaser interface {
AcquireTrickplay(context.Context, TrickplaySource) (TrickplayLease, error)
}
TrickplayLeaser is supplied by the runtime-owned shared provider. Acquire registers a holder and starts generation atomically with idle cancellation. Calls return promptly; consumers retain one lease until their source ends.
type TrickplayProvider ¶
type TrickplayProvider interface {
// EnsureTrickplay starts (or continues) progressive thumbnail
// generation for the source in the background. It returns
// immediately; duplicate calls for a release already generating are
// no-ops.
EnsureTrickplay(ctx context.Context, src TrickplaySource)
// TrickplayAvailable reports whether thumbnails for the release
// exist or are being generated, so a front end can advertise them
// (Plex's indexes="sd").
TrickplayAvailable(releaseID string) bool
// TrickplayBIF returns a snapshot of the release's sparse BIF index
// built from the frames generated so far.
TrickplayBIF(releaseID string) ([]byte, bool)
// TrickplayFrame returns the JPEG of the latest generated frame at
// or before at (a fallback still when no real frame precedes it).
TrickplayFrame(releaseID string, at time.Duration) ([]byte, bool)
// SetTrickplayFallback records a low-fidelity still (TMDB episode
// still or backdrop, already JPEG at roughly BIF width) used to fill
// not-yet-generated intervals. Real frames replace it as they arrive.
SetTrickplayFallback(releaseID string, jpeg []byte)
}
TrickplayProvider supplies on-the-fly preview thumbnails (Plex "BIF" indexes) for releases as they stream. It is an optional capability: callers reach it through a type assertion or an optional dependency and must tolerate its absence. Implementations only extract from sources handed to EnsureTrickplay (an active playback or warmup session); they never resolve or download a title just for thumbnails.
type TrickplaySource ¶
type TrickplaySource struct {
ReleaseID string
InputURL string
Info MediaInfo
// AvailableUntil is the playback position already read by the client.
// Generators must only fill intervals at or before this point and may
// advance it on later calls as playback progresses.
AvailableUntil time.Duration
}
TrickplaySource identifies one playable source thumbnails can be extracted from: the release being streamed and the loopback URL its bytes are readable through (Playback.InputURL). Info carries the duration and, when known, the container keyframe index used to align extractions to keyframes.
type User ¶
type User struct {
// Timestamps are internal identity metadata and do not change existing wire JSON.
CreatedAt time.Time `json:"-"`
UpdatedAt time.Time `json:"-"`
// Delegated marks short-lived server credentials; these never grant owner access.
Delegated bool `json:"-"`
ID int64 `json:"id"` // local id
PlexID int64 `json:"plexId"`
UUID string `json:"uuid,omitempty"`
Username string `json:"username"`
Title string `json:"title"` // display name
Email string `json:"email,omitempty"`
Thumb string `json:"thumb,omitempty"`
IsOwner bool `json:"isOwner"`
StreamLimit int `json:"streamLimit"` // 0 = server default
MaxContentRating string `json:"maxContentRating"` // "" = unrestricted, e.g. "PG-13", "TV-14"
SubtitleLanguages []string `json:"subtitleLanguages"` // ISO 639-1, preference order
AudioLanguages []string `json:"audioLanguages"`
AllowedSections []int `json:"allowedSections"` // empty = all
}
User is a Plex account with access to this server: the owner or a friend the owner shared with on plex.tv.
type UserPolicySource ¶ added in v0.2.7
UserPolicySource exposes the optional UserPolicy capability.
type UserTargets ¶
UserTargets is either every user ("all" in JSON) or a list of local user ids.
func (UserTargets) Includes ¶
func (u UserTargets) Includes(user *User) bool
Includes reports whether a user (nil = anonymous) is targeted.
func (UserTargets) MarshalJSON ¶
func (u UserTargets) MarshalJSON() ([]byte, error)
func (*UserTargets) UnmarshalJSON ¶
func (u *UserTargets) UnmarshalJSON(b []byte) error
type VariantPlayback ¶
type VariantPlayback interface {
PrepareVariant(ctx context.Context, user *User, key RatingKey, caps ClientCaps, releaseID string) (*PlaySession, error)
}
VariantPlayback is implemented by playback managers that can prepare a session on a specific release (the viewer picked a version). The release is health-checked like any other; when it is unavailable the manager falls back to the normal choice for the client.
type VariantResolver ¶
type VariantResolver interface {
Variants(ctx context.Context, req ResolveRequest, max int) ([]ReleaseVariant, error)
}
VariantResolver lists distinct candidate releases of a title for a client, best first, without health-checking every one of them. Implemented by internal/resolver.
type VibeQuery ¶
type VibeQuery struct {
// Query is the viewer's original text.
Query string `json:"query,omitempty"`
// Title is the human collection title, e.g.
// "90s Thrillers Under 100 Minutes".
Title string `json:"title,omitempty"`
// Filter is the catalogue filter the members are browsed with.
Filter Filter `json:"filter"`
Sort SortOrder `json:"sort,omitempty"`
Desc bool `json:"desc,omitempty"`
// SimilarSeed is the unresolved seed title text of a
// "shows like the office" query; SimilarKey is it resolved.
SimilarSeed string `json:"similarSeed,omitempty"`
SimilarKey RatingKey `json:"similarKey,omitempty"`
// PersonName is an unresolved person name ("christopher nolan
// films"); once resolved it lands in Filter.Person.
PersonName string `json:"personName,omitempty"`
}
VibeQuery is a natural-language ("vibe") search turned into a structured catalogue filter, e.g. "90s thrillers under 100 mins". It backs the ephemeral collections synthesized in search results (additive).
type VibeRefiner ¶
type VibeRefiner interface {
RefineVibe(ctx context.Context, user *User, query string) (VibeQuery, bool, error)
}
VibeRefiner maps an otherwise unparseable vibe query to a VibeQuery (implemented by the optional LLM service). It must be quick, respect ctx, and report ok=false when it cannot help.
type VibeSearcher ¶
type VibeSearcher interface {
VibeCollection(ctx context.Context, user *User, query string) (c *Collection, items []Title, ok bool, err error)
// PromoteEphemeral saves an ephemeral collection as a persisted
// personal smart collection for its owner. ok is false when key is
// not a live ephemeral collection owned by user.
PromoteEphemeral(ctx context.Context, user *User, key RatingKey) (c *Collection, ok bool, err error)
}
VibeSearcher is optionally implemented by the collections engine: it turns a vibe query into a browseable ephemeral collection for the viewer, alongside the collection's top items. ok is false when the query is not a vibe query (plain title searches stay untouched).
type VideoEnhancement ¶ added in v0.2.4
type VideoEnhancement struct {
Backend string `json:"backend,omitempty"`
State string `json:"state,omitempty"` // off, unavailable, ineligible, selected, starting, running, fallback, stopped
Reason string `json:"reason,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
Quality int `json:"quality,omitempty"`
}
VideoEnhancement is an observable plan/run status, never a promise based solely on installed hardware. Only running means enhanced segments have actually been produced in the current run. Fallback always carries a reason.
type VideoEnhancementSupport ¶ added in v0.2.4
type VideoEnhancementSupport struct {
// SetupState is off, checking, installing, ready, or unavailable.
SetupState string `json:"setupState,omitempty"`
Backend string `json:"backend"`
Available bool `json:"available"`
Reason string `json:"reason,omitempty"`
Version string `json:"version,omitempty"`
Protocols []string `json:"protocols,omitempty"`
Active int `json:"active"`
}
VideoEnhancementSupport is detection, not successful execution. Its protocols are the transports verified for this backend version.
type Viewer ¶ added in v0.3.0
type Viewer = User
Viewer is the household member that owns per-viewer state. Its ID is the existing local auth_users ID, independent of any identity provider.
type ViewerActivity ¶
type ViewerActivity struct {
Title Title `json:"title"`
At time.Time `json:"at"`
Completed bool `json:"completed"`
Progress float64 `json:"progress"` // 0..1
}
ViewerActivity is one recent viewing.
type ViewerInvalidator ¶ added in v0.2.7
type ViewerInvalidator interface{ Invalidate(userID int64) }
ViewerInvalidator exposes the optional Invalidate capability.
type ViewerLayout ¶
type ViewerLayout struct {
UserID int64 `json:"userId"`
Pages []LayoutPage `json:"pages"`
}
type ViewerStats ¶
type ViewerStats struct {
UserID int64 `json:"userId"`
LastActive time.Time `json:"lastActive,omitempty"`
Plays30d int `json:"plays30d"`
HoursWatched30d float64 `json:"hoursWatched30d"`
}
ViewerStats is a viewer's recent activity summary.
type WarmProbeWaiter ¶ added in v0.2.52
type WarmProbeWaiter interface {
WaitWarmProbe(ctx context.Context, user *User, caps ClientCaps, key RatingKey, budget time.Duration) (MediaInfo, bool)
}
WarmProbeWaiter is optionally implemented by playback managers that can wait up to a bounded budget for an already-scheduled warm probe (PreResolve) to finish, so the first detail-page open can render the file's real audio and subtitle streams instead of an estimate. It never cancels the background warm-up when the budget expires.
type WarmProber ¶ added in v0.2.49
type WarmProber interface {
WarmProbeInfo(user *User, caps ClientCaps, key RatingKey) (MediaInfo, bool)
}
WarmProber is optionally implemented by playback managers that complete a speculative probe (Prewarm/PreResolve) before Play. WarmProbeInfo returns the probed media info a warm-up already produced for this user/client/key, so metadata and play-queue renders can list the file's real audio and subtitle tracks instead of the single invented audio track of the estimate. ok=false when no warm probe has completed (or it has expired). It never starts a probe or blocks on one in flight.
It complements ResumedTracks, which only covers a viewer's later opens: this covers the first open, once the detail-page warm-up has landed.
type WatchStatus ¶
type WatchStatus struct {
Key RatingKey `json:"key"`
ViewOffset time.Duration `json:"viewOffset"`
ViewCount int `json:"viewCount"`
LastViewedAt time.Time `json:"lastViewedAt,omitempty"`
UserRating float64 `json:"userRating,omitempty"` // 0-10
InWatchlist bool `json:"inWatchlist,omitempty"`
IsFavorite bool `json:"isFavorite,omitempty"` // Derived from the viewer’s favorites set.
IsNotInterested bool `json:"isNotInterested,omitempty"` // Derived from the viewer’s recommendation exclusions.
Duration time.Duration `json:"duration,omitempty"`
UpdatedAt time.Time `json:"updatedAt"`
}
Source Files
¶
- align.go
- background.go
- batch_watch.go
- capabilities.go
- client_override.go
- client_profiles.go
- collectionspec.go
- customformats.go
- debrid.go
- downloads.go
- encoder_input.go
- encoder_retirement.go
- frontend.go
- hls_ladder.go
- homelayout.go
- hubcontext.go
- identity.go
- interfaces.go
- keyframes.go
- libraryfilter.go
- likes.go
- marked_playlists.go
- media_snapshot.go
- neutral_home.go
- personalhooks.go
- personalize.go
- personalize_owner.go
- playback.go
- playbackcore.go
- prewarm.go
- ratingkey.go
- read_retirement.go
- release.go
- release_rules.go
- repair.go
- resolver.go
- row_provenance.go
- safer_rating.go
- session_activity.go
- source_retirement.go
- source_revision.go
- source_revision_unix.go
- streamkey.go
- title_dates.go
- trickplay.go
- types.go
- variants.go
- vibesearch.go
- video_enhancement.go