Documentation
¶
Index ¶
- Variables
- func MapEpisodes(metadata []Metadata, serverURL string) []*domain.MediaItem
- func MapLibraries(dirs []Directory) []domain.Library
- func MapLibraryContent(metadata []Metadata, serverURL string) []domain.ListItem
- func MapMediaItem(m Metadata, serverURL string) domain.MediaItem
- func MapMovies(metadata []Metadata, serverURL string) []*domain.MediaItem
- func MapOnDeck(metadata []Metadata, serverURL string) []*domain.MediaItem
- func MapPlaylists(metadata []Metadata, serverURL string) []*domain.Playlist
- func MapSeasons(metadata []Metadata, serverURL string) []*domain.Season
- func MapShows(metadata []Metadata, serverURL string) []*domain.Show
- type APIResponse
- type AuthClient
- type AuthFlow
- type AuthResult
- type Client
- func (c *Client) AddToPlaylist(ctx context.Context, playlistID string, itemIDs []string) error
- func (c *Client) CreatePlaylist(ctx context.Context, title string, itemIDs []string) (*domain.Playlist, error)
- func (c *Client) DeletePlaylist(ctx context.Context, playlistID string) error
- func (c *Client) FetchIdentity(ctx context.Context) error
- func (c *Client) GetContinueWatching(ctx context.Context) ([]*domain.MediaItem, error)
- func (c *Client) GetEpisodes(ctx context.Context, seasonID string) ([]*domain.MediaItem, error)
- func (c *Client) GetLibraries(ctx context.Context) ([]domain.Library, error)
- func (c *Client) GetMediaItem(ctx context.Context, itemID string) (*domain.MediaItem, error)
- func (c *Client) GetMixedContent(ctx context.Context, libID string, offset, limit int) ([]domain.ListItem, int, error)
- func (c *Client) GetMovies(ctx context.Context, libID string, offset, limit int) ([]*domain.MediaItem, int, error)
- func (c *Client) GetPlaylistItems(ctx context.Context, playlistID string) ([]*domain.MediaItem, error)
- func (c *Client) GetPlaylists(ctx context.Context) ([]*domain.Playlist, error)
- func (c *Client) GetSeasons(ctx context.Context, showID string) ([]*domain.Season, error)
- func (c *Client) GetShows(ctx context.Context, libID string, offset, limit int) ([]*domain.Show, int, error)
- func (c *Client) MarkPlayed(ctx context.Context, itemID string) error
- func (c *Client) MarkUnplayed(ctx context.Context, itemID string) error
- func (c *Client) RemoveFromPlaylist(ctx context.Context, playlistID string, itemID string) error
- func (c *Client) ResolvePlayable(ctx context.Context, itemID string) (domain.PlayableMedia, error)
- func (c *Client) Search(ctx context.Context, query string) ([]*domain.MediaItem, error)
- func (c *Client) UpdateProgress(ctx context.Context, itemID string, positionMs int64) error
- type Directory
- type Guid
- type Media
- type MediaContainer
- type Metadata
- type PINCheckResponse
- type PINResponse
- type Part
- type PlaylistMetadata
- type Rating
- type Stream
Constants ¶
This section is empty.
Variables ¶
var ( // ErrPINExpired indicates the authentication PIN has expired ErrPINExpired = errors.New("authentication PIN has expired") // ErrServerOffline indicates the media server is unreachable ErrServerOffline = errors.New("media server is unreachable") )
Plex-specific errors
Functions ¶
func MapEpisodes ¶
MapEpisodes converts Plex metadata to domain media items (episodes)
func MapLibraries ¶
MapLibraries converts Plex directories to domain libraries
func MapLibraryContent ¶
MapLibraryContent converts Plex metadata to domain.ListItem for mixed libraries. This handles both movies and shows in a single response, returning them as a polymorphic slice that the UI can display uniformly.
func MapMediaItem ¶
MapMediaItem converts a single Plex metadata to domain media item
func MapPlaylists ¶
MapPlaylists converts Plex metadata to domain playlists
func MapSeasons ¶
MapSeasons converts Plex metadata to domain seasons
Types ¶
type APIResponse ¶
type APIResponse struct {
MediaContainer MediaContainer `json:"MediaContainer"`
}
APIResponse wraps the MediaContainer for JSON unmarshaling
type AuthClient ¶
type AuthClient struct {
// contains filtered or unexported fields
}
AuthClient handles Plex authentication
func NewAuthClient ¶
func NewAuthClient(logger *slog.Logger) *AuthClient
NewAuthClient creates a new authentication client
func (*AuthClient) CheckPIN ¶
func (a *AuthClient) CheckPIN(ctx context.Context, pinID int) (token string, claimed bool, err error)
CheckPIN polls for PIN claim status and returns the auth token
func (*AuthClient) WaitForPIN ¶
func (a *AuthClient) WaitForPIN(ctx context.Context, pinID int, timeout time.Duration) (string, error)
WaitForPIN polls for PIN claim with exponential backoff
type AuthFlow ¶
type AuthFlow struct {
// contains filtered or unexported fields
}
AuthFlow handles Plex PIN-based authentication
func NewAuthFlow ¶
NewAuthFlow creates a new Plex authentication flow
type AuthResult ¶
AuthResult contains the result of a successful Plex authentication
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client implements domain.LibraryRepository, domain.SearchRepository, domain.MetadataRepository, and domain.Scrobbler for Plex
func (*Client) AddToPlaylist ¶
AddToPlaylist adds items to an existing playlist
func (*Client) CreatePlaylist ¶
func (c *Client) CreatePlaylist(ctx context.Context, title string, itemIDs []string) (*domain.Playlist, error)
CreatePlaylist creates a new playlist with the given title and initial items. Plex does not support creating empty playlists, so at least one itemID is required.
func (*Client) DeletePlaylist ¶
DeletePlaylist deletes a playlist
func (*Client) FetchIdentity ¶
FetchIdentity fetches and stores the server's machineIdentifier
func (*Client) GetContinueWatching ¶ added in v1.1.0
GetContinueWatching returns items that are currently in progress or "on deck". Note: Plex's /library/onDeck follows "next unwatched episode" semantics, which includes episodes you haven't started yet but are next in a show's sequence. This differs from Jellyfin's /Resume which only returns items with an active playback position.
func (*Client) GetEpisodes ¶
GetEpisodes returns all episodes for a season
func (*Client) GetLibraries ¶
GetLibraries returns all available libraries
func (*Client) GetMediaItem ¶
GetMediaItem returns detailed metadata for a specific item
func (*Client) GetMixedContent ¶
func (c *Client) GetMixedContent(ctx context.Context, libID string, offset, limit int) ([]domain.ListItem, int, error)
GetMixedContent returns paginated content (movies AND shows) from a library. Note: Plex doesn't truly support "mixed" libraries at the API level like Jellyfin, so this method fetches all items and returns both types. For pure movie or show libraries, this still works but is less efficient than GetMovies/GetShows.
func (*Client) GetMovies ¶
func (c *Client) GetMovies(ctx context.Context, libID string, offset, limit int) ([]*domain.MediaItem, int, error)
GetMovies returns movies from a movie library with pagination support Returns (items, totalSize, error) Note: If limit=0, Plex uses its default page size (typically 50-100). The SERVICE layer is responsible for pagination loops if "all" items are needed.
func (*Client) GetPlaylistItems ¶
func (c *Client) GetPlaylistItems(ctx context.Context, playlistID string) ([]*domain.MediaItem, error)
GetPlaylistItems returns all items in a playlist
func (*Client) GetPlaylists ¶
GetPlaylists returns all user playlists
func (*Client) GetSeasons ¶
GetSeasons returns all seasons for a TV show
func (*Client) GetShows ¶
func (c *Client) GetShows(ctx context.Context, libID string, offset, limit int) ([]*domain.Show, int, error)
GetShows returns TV shows from a show library with pagination support Returns (items, totalSize, error) Note: If limit=0, Plex uses its default page size (typically 50-100). The SERVICE layer is responsible for pagination loops if "all" items are needed.
func (*Client) MarkPlayed ¶
MarkPlayed marks an item as fully watched
func (*Client) MarkUnplayed ¶
MarkUnplayed marks an item as unwatched
func (*Client) RemoveFromPlaylist ¶
RemoveFromPlaylist removes an item from a playlist. Plex requires the playlist-specific entry ID (playlistItemID), not the media's ratingKey. This method fetches playlist items to resolve the correct entry ID internally.
func (*Client) ResolvePlayable ¶ added in v1.0.1
ResolvePlayable returns a direct playback URL plus any external subtitle tracks for an item.
type Directory ¶
type Directory struct {
Art string `json:"art,omitempty"`
Composite string `json:"composite,omitempty"`
Thumb string `json:"thumb,omitempty"`
Key string `json:"key"`
Type string `json:"type"`
Title string `json:"title"`
UpdatedAt int64 `json:"updatedAt,omitempty"`
CreatedAt int64 `json:"createdAt,omitempty"`
ContentChangedAt int64 `json:"contentChangedAt,omitempty"`
}
Directory represents a library section
type Guid ¶
type Guid struct {
ID string `json:"id"` // e.g. "imdb://tt1234567", "tmdb://12345", "tvdb://12345"
}
Guid represents an external identifier (IMDB, TMDB, TVDB, etc.)
type Media ¶
type Media struct {
ID int `json:"id"`
Duration int `json:"duration,omitempty"`
Bitrate int `json:"bitrate,omitempty"`
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
AudioChannels int `json:"audioChannels,omitempty"`
AudioCodec string `json:"audioCodec,omitempty"`
VideoCodec string `json:"videoCodec,omitempty"`
VideoResolution string `json:"videoResolution,omitempty"`
Container string `json:"container,omitempty"`
VideoFrameRate string `json:"videoFrameRate,omitempty"`
Part []Part `json:"Part,omitempty"`
}
Media represents media information (video streams, codecs, etc.)
type MediaContainer ¶
type MediaContainer struct {
Size int `json:"size"`
TotalSize int `json:"totalSize,omitempty"`
Offset int `json:"offset,omitempty"`
AllowSync bool `json:"allowSync,omitempty"`
Identifier string `json:"identifier,omitempty"`
LibrarySectionID int `json:"librarySectionID,omitempty"`
LibrarySectionTitle string `json:"librarySectionTitle,omitempty"`
LibrarySectionUUID string `json:"librarySectionUUID,omitempty"`
MediaTagPrefix string `json:"mediaTagPrefix,omitempty"`
MediaTagVersion int `json:"mediaTagVersion,omitempty"`
Directory []Directory `json:"Directory,omitempty"`
Metadata []Metadata `json:"Metadata,omitempty"`
}
MediaContainer is the root container for Plex API responses
type Metadata ¶
type Metadata struct {
RatingKey string `json:"ratingKey"`
Key string `json:"key"`
ParentRatingKey string `json:"parentRatingKey,omitempty"`
GrandparentRatingKey string `json:"grandparentRatingKey,omitempty"`
GUID string `json:"guid,omitempty"` // Plex internal GUID
Guids []Guid `json:"Guid,omitempty"` // External IDs (IMDB, TMDB, TVDB)
Studio string `json:"studio,omitempty"`
Type string `json:"type"`
Title string `json:"title"`
GrandparentKey string `json:"grandparentKey,omitempty"`
ParentKey string `json:"parentKey,omitempty"`
GrandparentTitle string `json:"grandparentTitle,omitempty"`
ParentTitle string `json:"parentTitle,omitempty"`
ContentRating string `json:"contentRating,omitempty"`
Summary string `json:"summary,omitempty"`
Index int `json:"index,omitempty"`
ParentIndex int `json:"parentIndex,omitempty"`
Rating float64 `json:"rating,omitempty"` // Critic rating
Ratings []Rating `json:"Rating,omitempty"` // External ratings
AudienceRating float64 `json:"audienceRating,omitempty"` // Audience rating
ViewOffset int `json:"viewOffset,omitempty"`
LastViewedAt int64 `json:"lastViewedAt,omitempty"`
Year int `json:"year,omitempty"`
Tagline string `json:"tagline,omitempty"`
Thumb string `json:"thumb,omitempty"`
Art string `json:"art,omitempty"`
ParentThumb string `json:"parentThumb,omitempty"`
GrandparentThumb string `json:"grandparentThumb,omitempty"`
GrandparentArt string `json:"grandparentArt,omitempty"`
Duration int `json:"duration,omitempty"`
OriginallyAvailableAt string `json:"originallyAvailableAt,omitempty"`
AddedAt int64 `json:"addedAt,omitempty"`
UpdatedAt int64 `json:"updatedAt,omitempty"`
TitleSort string `json:"titleSort,omitempty"`
ViewCount int `json:"viewCount,omitempty"`
ChildCount int `json:"childCount,omitempty"`
LeafCount int `json:"leafCount,omitempty"`
ViewedLeafCount int `json:"viewedLeafCount,omitempty"`
LibrarySectionID int `json:"librarySectionID,omitempty"`
LibrarySectionKey string `json:"librarySectionKey,omitempty"`
LibrarySectionTitle string `json:"librarySectionTitle,omitempty"`
PlaylistItemID int `json:"playlistItemID,omitempty"`
Media []Media `json:"Media,omitempty"`
}
Metadata represents a media item (movie, show, season, or episode)
type PINCheckResponse ¶
type PINCheckResponse struct {
ID int `json:"id"`
Code string `json:"code"`
AuthToken string `json:"authToken"`
ExpiresAt string `json:"expiresAt"`
}
PINCheckResponse represents the response from PIN check
type PINResponse ¶
type PINResponse struct {
ID int `json:"id"`
Code string `json:"code"`
Product string `json:"product"`
Trusted bool `json:"trusted"`
ClientID string `json:"clientIdentifier"`
AuthToken string `json:"authToken,omitempty"`
ExpiresAt string `json:"expiresAt"`
}
PINResponse represents the response from PIN generation
type Part ¶
type Part struct {
ID int `json:"id"`
Key string `json:"key"`
Duration int `json:"duration,omitempty"`
File string `json:"file,omitempty"`
Size int64 `json:"size,omitempty"`
Container string `json:"container,omitempty"`
Stream []Stream `json:"Stream,omitempty"`
}
Part represents a media file part
type PlaylistMetadata ¶
type PlaylistMetadata struct {
RatingKey string `json:"ratingKey"`
Key string `json:"key"`
GUID string `json:"guid,omitempty"` // Plex internal GUID
Guids []Guid `json:"Guid,omitempty"` // External IDs
Type string `json:"type"`
Title string `json:"title"`
Summary string `json:"summary,omitempty"`
Smart int `json:"smart"` // 1 = smart playlist, 0 = regular
PlaylistType string `json:"playlistType"`
Composite string `json:"composite,omitempty"`
Duration int `json:"duration,omitempty"`
LeafCount int `json:"leafCount,omitempty"`
AddedAt int64 `json:"addedAt,omitempty"`
UpdatedAt int64 `json:"updatedAt,omitempty"`
}
PlaylistMetadata represents a Plex playlist
type Rating ¶
type Rating struct {
Image string `json:"image,omitempty"` // e.g. "imdb://image.rating"
Type string `json:"type,omitempty"`
Value float64 `json:"value,omitempty"`
}
Rating represents a rating from an external source
type Stream ¶ added in v1.0.1
type Stream struct {
ID int `json:"id"`
StreamType int `json:"streamType"`
Key string `json:"key,omitempty"` // e.g. "/library/streams/12345" for external subs
Codec string `json:"codec,omitempty"`
Format string `json:"format,omitempty"`
Language string `json:"language,omitempty"`
LanguageCode string `json:"languageCode,omitempty"`
LanguageTag string `json:"languageTag,omitempty"`
DisplayTitle string `json:"displayTitle,omitempty"`
ExtendedDisplayTitle string `json:"extendedDisplayTitle,omitempty"`
Title string `json:"title,omitempty"`
Default flexBool `json:"default,omitempty"`
Forced flexBool `json:"forced,omitempty"`
Selected flexBool `json:"selected,omitempty"`
External flexBool `json:"external,omitempty"`
}
Stream represents a video, audio, or subtitle stream inside a Plex Part. streamType: 1 = video, 2 = audio, 3 = subtitle.