Documentation
¶
Overview ¶
Package livetv implements owner-defined virtual channels and IPTV playout. Ether supplies neither programming nor IPTV accounts.
Index ¶
- Constants
- Variables
- func AddonInputID(channelID string, n int) string
- func BuiltinDescriptors() []extend.Descriptor
- func CleanInputHeaders(in map[string]string) map[string]string
- func DaypartPreset(name string) (int, int, error)
- func WithChannelMemo(ctx context.Context) context.Context
- type Block
- type BreakPattern
- type BreakPoint
- type Channel
- type ChannelBatch
- type ChannelCounts
- type ChannelGroup
- type ChannelLook
- type ChannelPage
- type ChannelPageQuery
- type ChannelScreens
- type ChannelSummary
- type ChannelUsage
- type ChannelViewers
- type ClockSlot
- type Fetched
- type GuideAIClient
- type GuideAIStats
- type GuideChannel
- type GuideCommitSelection
- type GuideCoverage
- type GuideMatchChange
- type GuideMatchRequest
- type GuideMatchResult
- type Item
- type KindRegistry
- func (r *KindRegistry) Classify(src Source) (SourceKind, bool)
- func (r *KindRegistry) Descriptors() []extend.Descriptor
- func (r *KindRegistry) Kinds() []SourceKind
- func (r *KindRegistry) Lookup(id string) (SourceKind, bool)
- func (r *KindRegistry) Register(k SourceKind) error
- func (r *KindRegistry) Unregister(id string)
- type MaintenanceDiagnostics
- type Options
- type PersonalIngredient
- type PersonalPolicy
- type PersonalRecipe
- type PinnedSlot
- type PlexLineup
- type Policy
- type PreviewSession
- type ProgramSource
- type Programme
- type ProviderAccount
- type ReelClip
- type ReelSnapshot
- type Service
- func (s *Service) AcquireProvider(ctx context.Context, id string) (func(), error)
- func (s *Service) AdoptAddonSource(ctx context.Context, id, kind string) error
- func (s *Service) AllowedChannel(ctx context.Context, u *core.User, key string) (Channel, error)
- func (s *Service) AllowedChannelCached(ctx context.Context, u *core.User, id string, ...) error
- func (s *Service) AllowedChannels(ctx context.Context, u *core.User) ([]Channel, error)
- func (s *Service) AllowedChannelsForIDs(ctx context.Context, u *core.User, ids []string) ([]Channel, error)
- func (s *Service) AuthenticateMediaGrant(r *http.Request, active func(context.Context, int64) *core.User) (*core.User, bool)
- func (s *Service) Channel(ctx context.Context, id string) (Channel, error)
- func (s *Service) ChannelForViewer(ctx context.Context, u *core.User, id string) (Channel, error)
- func (s *Service) ChannelPage(ctx context.Context, q ChannelPageQuery) (ChannelPage, error)
- func (s *Service) ChannelPermitted(ctx context.Context, u *core.User, id string) (bool, error)
- func (s *Service) ChannelSummaries(ctx context.Context) ([]ChannelSummary, error)
- func (s *Service) Channels(ctx context.Context) ([]Channel, error)
- func (s *Service) Close() error
- func (s *Service) Coverage(ctx context.Context) ([]GuideCoverage, error)
- func (s *Service) DeleteChannel(ctx context.Context, id string) error
- func (s *Service) DeleteSource(ctx context.Context, id string) error
- func (s *Service) Failover(ctx context.Context, id string, u *core.User) error
- func (s *Service) GraphicsRequests(ctx context.Context, lookID string) []core.ClipRequest
- func (s *Service) Guide(ctx context.Context, u *core.User, from, until time.Time) ([]Programme, error)
- func (s *Service) GuideChannels(ctx context.Context, q, source string, limit int) ([]GuideChannel, error)
- func (s *Service) GuideForChannels(ctx context.Context, u *core.User, from, until time.Time, ids []string) ([]Programme, error)
- func (s *Service) GuideWindow() (from, until time.Time)
- func (s *Service) Handler() http.Handler
- func (s *Service) HomeHub(ctx context.Context, u *core.User, limit int) (core.Hub, error)
- func (s *Service) ImportProgress(id string) (SourceProgress, bool)
- func (s *Service) ImportSource(ctx context.Context, src Source) (Source, error)
- func (s *Service) ImportUpload(ctx context.Context, id, part string, body io.Reader) (Source, error)
- func (s *Service) KindRegistry() *KindRegistry
- func (s *Service) LegacyStremioSources(ctx context.Context) ([]Source, error)
- func (s *Service) LineupChanged() time.Time
- func (s *Service) LineupChangedFor(u *core.User) time.Time
- func (s *Service) LiveUsage(_ context.Context) (Usage, error)
- func (s *Service) MaintenanceDiagnostics() MaintenanceDiagnostics
- func (s *Service) MatchGuides(ctx context.Context, req GuideMatchRequest) (GuideMatchResult, error)
- func (s *Service) MigrateSecrets(ctx context.Context) (int, error)
- func (s *Service) Now() time.Time
- func (s *Service) OnNow(ctx context.Context, u *core.User, now, until time.Time) ([]Channel, []Programme, error)
- func (s *Service) OnNowN(ctx context.Context, u *core.User, now, until time.Time, limit int) ([]Channel, []Programme, error)
- func (s *Service) ParseSourceGuide(ctx context.Context, src Source, channels []Channel, r io.Reader) (XMLGuide, error)
- func (s *Service) PersonalChanged(viewer int64)
- func (s *Service) PlexLineups(ctx context.Context, country, postal string) ([]PlexLineup, error)
- func (s *Service) Policies(ctx context.Context) ([]Policy, error)
- func (s *Service) Policy(ctx context.Context, userID int64) (Policy, error)
- func (s *Service) ProgrammesSnapshot(ctx context.Context, u *core.User, id string, from, until time.Time, ...) ([]Programme, error)
- func (s *Service) ReelChannelIDs(ctx context.Context) (map[string][]string, error)
- func (s *Service) RefreshGraphics(ctx context.Context)
- func (s *Service) RefreshGuide(ctx context.Context) error
- func (s *Service) RefreshSource(ctx context.Context, id string) (Source, error)
- func (s *Service) RefreshVOD(ctx context.Context, id string) (err error)
- func (s *Service) RegisterSourceKind(k SourceKind) error
- func (s *Service) ResolveStreamSource(ctx context.Context, c Channel, src StreamSource) (string, http.Header, error)
- func (s *Service) Rundown(ctx context.Context, id string, viewer int64) ([]Programme, error)
- func (s *Service) SaveChannel(ctx context.Context, c Channel) (Channel, error)
- func (s *Service) SavePendingSource(ctx context.Context, src Source) (Source, error)
- func (s *Service) SavePolicy(ctx context.Context, p Policy) error
- func (s *Service) ServeDASH(w http.ResponseWriter, r *http.Request, id string, u *core.User) error
- func (s *Service) ServeDASHPart(w http.ResponseWriter, r *http.Request, id string, u *core.User, rep, n int, ...)
- func (s *Service) ServeHTTP(w http.ResponseWriter, r *http.Request, id string, u *core.User) error
- func (s *Service) ServePlaylist(w http.ResponseWriter, r *http.Request, id string, u *core.User)
- func (s *Service) ServeRelaySegment(w http.ResponseWriter, r *http.Request, id string, n int, u *core.User)
- func (s *Service) ServeResource(w http.ResponseWriter, r *http.Request, id, key string, u *core.User)
- func (s *Service) ServeXMLTV(w http.ResponseWriter, r *http.Request, u *core.User)
- func (s *Service) Session(ctx context.Context, id string, u *core.User) (SessionInfo, error)
- func (s *Service) Sessions(ctx context.Context, u *core.User) []SessionInfo
- func (s *Service) SetChannelViewers(ctx context.Context, channelID string, change ChannelViewers) error
- func (s *Service) SetOnChange(fn func())
- func (s *Service) SetStreamOpener(...)
- func (s *Service) SourceChannels(ctx context.Context, sourceID string) ([]Channel, error)
- func (s *Service) SourceKindOf(src Source) string
- func (s *Service) Sources(ctx context.Context) ([]Source, error)
- func (s *Service) Stop(ctx context.Context, id string, u *core.User) error
- func (s *Service) StreamSourceStatuses(ctx context.Context, channelID string) ([]StreamSourceStatus, error)
- func (s *Service) StyleChannelIDs(ctx context.Context) (map[string][]string, error)
- func (s *Service) TranscodeFor(string) (core.HLSSession, bool)
- func (s *Service) Tune(ctx context.Context, u *core.User, channelID string, caps core.ClientCaps) (SessionInfo, error)
- func (s *Service) TuneWithSession(ctx context.Context, u *core.User, channelID string, caps core.ClientCaps, ...) (result SessionInfo, resultErr error)
- func (s *Service) UnregisterSourceKind(id string)
- func (s *Service) UpdateChannels(ctx context.Context, change ChannelBatch) (int, error)
- func (s *Service) VODSearch(ctx context.Context, req core.SearchRequest) ([]core.Release, error)
- func (s *Service) ViewingSessions() []*core.PlaySession
- func (s *Service) VisibleTo(ctx context.Context, u *core.User) bool
- type SessionInfo
- type SnapshotView
- type Source
- type SourceAuth
- type SourceDescribe
- type SourceGroup
- type SourceKind
- type SourceProgress
- type SourceUsage
- type StreamSource
- type StreamSourceStatus
- type Timeline
- type TimelineDaypart
- type TimelineElement
- type TuneError
- type Usage
- type VODIndexer
- func (v *VODIndexer) FetchNZB(ctx context.Context, r core.Release) ([]byte, error)
- func (v *VODIndexer) HasDirectSources() bool
- func (v *VODIndexer) HasTorrentIndexer() bool
- func (v *VODIndexer) MissingSources() error
- func (v *VODIndexer) Name() string
- func (v *VODIndexer) ResolveTorrent(ctx context.Context, r core.Release) (core.Release, error)
- func (v *VODIndexer) Search(ctx context.Context, r core.SearchRequest) ([]core.Release, error)
- func (v *VODIndexer) SearchRescue(ctx context.Context, r core.SearchRequest) ([]core.Release, error)
- func (v *VODIndexer) SearchRescueWith(ctx context.Context, r core.SearchRequest, arrived func([]core.Release)) ([]core.Release, error)
- func (v *VODIndexer) SearchWith(ctx context.Context, r core.SearchRequest, arrived func([]core.Release)) ([]core.Release, error)
- type VODStatus
- type VirtualDASHError
- type XMLGuide
Constants ¶
const AddonInputPrefix = "stremio-"
Add-on channel sources (Stremio `tv` add-ons, installed as plugins) own their channels' inputs, which carry AddonInputPrefix in their ids:
- a refresh replaces them, keeping the owner's enabled flags and any input the owner added to the channel;
- channels new to the source are matched to guides after the import;
- their URLs and request headers can repeat the add-on's configuration (often a debrid key), so the owner API never returns them.
const MaxChannelInputs = 16
MaxChannelInputs bounds one channel's stream inputs.
const Provider = "tv.plex.providers.epg.xmltv:1"
Variables ¶
var ErrProviderBusy = fmt.Errorf("every connection this IPTV provider allows is in use: %w", core.ErrStreamLimit)
ErrProviderBusy reports that every connection the provider allows is in use by other channels.
var ErrProviderPaced = fmt.Errorf("this IPTV source has started as many streams this hour as its owner allows: %w", core.ErrStreamLimit)
ErrProviderPaced reports that the source's hourly allowance of new provider streams is spent.
Functions ¶
func AddonInputID ¶ added in v0.3.3
AddonInputID is the id of a channel's n-th add-on input (from 0).
func BuiltinDescriptors ¶ added in v0.3.3
func BuiltinDescriptors() []extend.Descriptor
BuiltinDescriptors returns descriptors for the built-in kinds.
func CleanInputHeaders ¶ added in v0.3.3
CleanInputHeaders keeps the request headers an input may carry, with canonical names: no headers the HTTP stack or the proxy manages, no line breaks, at most 16. It returns nil when none remain.
func DaypartPreset ¶
DaypartPreset supplies editable starting times; saved values are authoritative.
Types ¶
type Block ¶
type Block struct {
ID string `json:"id,omitempty"`
Preset string `json:"preset,omitempty"`
Breaks *ChannelLook `json:"breaks,omitempty"`
// Start and End are minutes after midnight in Timezone, or UTC when
// the channel has no timezone. End may be 1440. Days empty means every
// day, which is how channels saved before the weekly grid behave.
// Days are Go weekdays: 0 Sunday … 6 Saturday, in that same zone.
Start int `json:"start"`
End int `json:"end"`
Days []int `json:"days,omitempty"`
// Name is a short grid label such as "Cartoons". It does not change
// what plays. Known preset names are translated in the console.
Name string `json:"name,omitempty"`
Items []Item `json:"items"`
Shuffle bool `json:"shuffle"`
Mode string `json:"mode,omitempty"` // order, shuffle, random, marathon, newest
Align string `json:"align,omitempty"` // hour, half
Fit string `json:"fit,omitempty"` // cut, pad
RepeatDays int `json:"repeatDays,omitempty"`
Filler []Item `json:"filler,omitempty"`
MarathonKey core.RatingKey `json:"marathonKey,omitempty"`
Collection core.RatingKey `json:"collection,omitempty"`
Filter *core.Filter `json:"filter,omitempty"`
Sources []ProgramSource `json:"sources,omitempty"`
Watched string `json:"watched,omitempty"`
}
type BreakPattern ¶
type BreakPattern struct {
Preset string `json:"preset,omitempty"`
Seconds int `json:"seconds"`
MinSeconds int `json:"minSeconds"`
MaxSeconds int `json:"maxSeconds"`
Spots int `json:"spots"`
MinSpots int `json:"minSpots"`
MaxSpots int `json:"maxSpots"`
PodsPerHalfHour int `json:"podsPerHalfHour"`
Inside bool `json:"inside"`
NoRepeatMinutes int `json:"noRepeatMinutes"`
StationID bool `json:"stationId"`
BumperStyle string `json:"bumperStyle"`
ClockAlignment string `json:"clockAlignment"`
}
BreakPattern is opt-in. Bounds apply to whole pods, including bumpers.
func EraBreakPattern ¶
func EraBreakPattern(era string) (BreakPattern, bool)
func (BreakPattern) Validate ¶
func (p BreakPattern) Validate() error
type BreakPoint ¶
type Channel ¶
type Channel struct {
Pins []PinnedSlot `json:"pins,omitempty"`
Clock []ClockSlot `json:"clock,omitempty"`
DVRMinutes int `json:"dvrMinutes,omitempty"`
Personal *PersonalRecipe `json:"personal,omitempty"`
Screens *ChannelScreens `json:"screens,omitempty"`
Look *ChannelLook `json:"look,omitempty"`
Health string `json:"health,omitempty"`
Transcode bool `json:"transcode"` // IPTV: normalize codecs through the transcoder
ID string `json:"id"`
// Private channels are hidden from every viewer whose policy does not
// grant them: a restricted viewer needs it in Channels, an unrestricted
// one in Granted. Owners always see them.
Private bool `json:"private,omitempty"`
Number string `json:"number"`
Name string `json:"name"`
Kind string `json:"kind"` // virtual or iptv
Enabled bool `json:"enabled"`
Favorite bool `json:"favorite"`
Logo string `json:"logo,omitempty"`
LogoMatched bool `json:"logoMatched,omitempty"`
Rating string `json:"rating,omitempty"`
SourceID string `json:"sourceId,omitempty"`
GuideID string `json:"guideId,omitempty"`
TvgName string `json:"tvgName,omitempty"` // provider's label; a guide-matching hint
StreamURL string `json:"streamUrl,omitempty"` // owner API only
StreamSources []StreamSource `json:"streamSources,omitempty"` // ordered inputs; independent of channel/guide identity
Group string `json:"group,omitempty"`
CustomGroup bool `json:"customGroup,omitempty"` // preserve owner grouping on provider refresh
Epoch time.Time `json:"epoch"`
Seed int64 `json:"seed"`
Shuffle bool `json:"shuffle"`
Items []Item `json:"items"`
Blocks []Block `json:"blocks,omitempty"`
// Collection/Filter/Sources are expanded into a stable item snapshot when saved.
Collection core.RatingKey `json:"collection,omitempty"`
Filter *core.Filter `json:"filter,omitempty"`
Sources []ProgramSource `json:"sources,omitempty"`
Watched string `json:"watched,omitempty"` // household: watched, unwatched
// Mode, Align, Fit, RepeatDays and Filler are the base playout. Empty
// Mode keeps Shuffle as the original engine: false resumes in order from
// Epoch, true is one stable shuffle. Timezone empty means block minutes
// are UTC, every day.
Mode string `json:"mode,omitempty"`
Align string `json:"align,omitempty"`
Fit string `json:"fit,omitempty"`
RepeatDays int `json:"repeatDays,omitempty"`
Filler []Item `json:"filler,omitempty"`
Fallback []Item `json:"fallback,omitempty"`
OffAir bool `json:"offAir,omitempty"`
MarathonKey core.RatingKey `json:"marathonKey,omitempty"`
Timezone string `json:"timezone,omitempty"`
// GuideSourceID names the source whose XMLTV supplies GuideID's
// programmes. Empty means SourceID. Virtual channels ignore it.
GuideSourceID string `json:"guideSourceId,omitempty"`
// ProviderNumber is the number the source gave this channel at the last
// import (Xtream num, M3U tvg-chno, or the position in the owner's group
// order). While Number still equals it the channel follows the
// provider's renumbering; an owner edit makes Number differ and sticks.
ProviderNumber string `json:"providerNumber,omitempty"`
// contains filtered or unexported fields
}
type ChannelBatch ¶ added in v0.3.4
type ChannelBatch struct {
IDs []string `json:"ids"`
Enabled *bool `json:"enabled,omitempty"`
Favorite *bool `json:"favorite,omitempty"`
Group *string `json:"group,omitempty"`
}
ChannelBatch changes only the named fields, preserving stream credentials, programming and concurrent edits to unrelated fields. All IDs commit together.
type ChannelCounts ¶ added in v0.3.4
type ChannelGroup ¶ added in v0.3.4
type ChannelLook ¶
type ChannelLook struct {
MomentAssets map[string]string `json:"momentAssets,omitempty"`
BreakPlacement string `json:"breakPlacement,omitempty"`
Tonight *bool `json:"tonight,omitempty"`
Bug *core.BugSettings `json:"bug,omitempty"`
BreakPattern *BreakPattern `json:"breakPattern,omitempty"`
LookID string `json:"lookId"`
Ident bool `json:"ident"`
UpNext bool `json:"upNext"`
Placement string `json:"placement,omitempty"`
Breaks string `json:"breaks,omitempty"`
BreakEvery int `json:"breakEvery,omitempty"`
BreakContent string `json:"breakContent,omitempty"`
ReelID string `json:"reelId,omitempty"`
SegmentIDs []string `json:"segmentIds,omitempty"`
BreakSeconds int `json:"breakSeconds,omitempty"`
OffAir bool `json:"offAir"`
Overlays string `json:"overlays,omitempty"`
AllowUnratedSegments bool `json:"allowUnratedSegments,omitempty"`
Tagline string `json:"tagline,omitempty"`
Accent string `json:"accent,omitempty"`
}
type ChannelPage ¶ added in v0.3.4
type ChannelPage struct {
Channels []Channel `json:"channels"`
Total int `json:"total"`
Counts ChannelCounts `json:"counts"`
Groups []ChannelGroup `json:"groups"`
Coverage map[string]bool `json:"coverage"`
NextNumber string `json:"nextNumber"`
}
type ChannelPageQuery ¶ added in v0.3.4
type ChannelScreens ¶
type ChannelScreens struct {
OffAir string `json:"offAir,omitempty"`
NoSignal string `json:"noSignal,omitempty"`
}
ChannelScreens overrides the server defaults. Empty values follow them.
type ChannelSummary ¶ added in v0.3.4
type ChannelSummary struct {
ID string `json:"id"`
Number string `json:"number"`
Name string `json:"name"`
Kind string `json:"kind"`
Private bool `json:"private,omitempty"`
Enabled bool `json:"enabled"`
Favorite bool `json:"favorite"`
Rating string `json:"rating,omitempty"`
Logo string `json:"logo,omitempty"`
SourceID string `json:"sourceId,omitempty"`
GuideID string `json:"guideId,omitempty"`
GuideSourceID string `json:"guideSourceId,omitempty"`
Group string `json:"group,omitempty"`
// contains filtered or unexported fields
}
ChannelSummary is the console lineup identity: everything the list, search and guide rows need, without stream URLs, items or programming.
type ChannelUsage ¶ added in v0.3.4
ChannelUsage is one channel being watched.
type ChannelViewers ¶ added in v0.3.2
type ChannelViewers struct {
Allow []int64 `json:"allow,omitempty"`
Deny []int64 `json:"deny,omitempty"`
}
ChannelViewers changes which viewers may watch one channel by editing their policies. Allowing a restricted viewer adds the channel to their list; allowing an unrestricted one grants a private channel (a public one they already see). Denying a private channel removes it from the list or the grants. Denying a public channel to an unrestricted viewer restricts them to every other channel they can see now, so they stop receiving new channels automatically. A viewer with Live TV disabled keeps it disabled.
type Fetched ¶ added in v0.3.3
type Fetched struct {
Channels []Channel
Guide XMLGuide
// AddonInputs marks channels whose inputs an add-on owns (ids carry
// AddonInputPrefix); see addon_streams.go.
AddonInputs bool
// ProviderNumbers marks a lineup whose every number comes from the
// provider. Channels imported before provider numbers were recorded
// then take the provider's number instead of keeping a generated one.
ProviderNumbers bool
}
Fetched is what a source kind yields on import or refresh: channels (with their ordered stream inputs) and guide data. ImportSource persists it atomically, preserving owner mapping, numbering and access rules.
type GuideAIClient ¶
type GuideAIClient interface {
Enabled() bool
ChatGuide(context.Context, string, string) (string, error)
}
GuideAIClient is the owner's shared LLM connection; tests supply an offline fake.
type GuideAIStats ¶
type GuideAIStats struct {
Configured bool `json:"configured"`
EstimatedCalls int `json:"estimatedCalls"`
InputTokens int `json:"inputTokens"`
Calls int `json:"calls"`
Cached int `json:"cached"`
Deferred int `json:"deferred"`
ElapsedMS int64 `json:"elapsedMs"`
}
Input and output are bounded separately. Provider prices vary, so estimates expose calls and a conservative token ceiling rather than invented currency.
type GuideChannel ¶
type GuideChannel struct {
SourceID string `json:"sourceId"`
SourceName string `json:"sourceName"`
SourceKind string `json:"sourceKind,omitempty"`
GuideID string `json:"guideId"`
Name string `json:"name"`
Logo string `json:"logo"`
Programmes int `json:"programmes"`
Until *time.Time `json:"until,omitempty"`
}
GuideChannel is an XMLTV <channel> (or programme channel id) stored for a source. Programmes counts programmes that have not yet ended; Until is the end of the last stored programme.
type GuideCommitSelection ¶
type GuideCommitSelection struct {
ChannelID string `json:"channelId"`
GuideSourceID string `json:"guideSourceId"`
GuideID string `json:"guideId"`
ExpectedGuideSourceID string `json:"expectedGuideSourceId"`
ExpectedGuideID string `json:"expectedGuideId"`
ProposalKey string `json:"proposalKey,omitempty"`
}
Only mapping fields are written or retained in an undo receipt. Names, stream credentials and unrelated owner edits never enter this journal.
type GuideCoverage ¶
type GuideMatchChange ¶
type GuideMatchChange struct {
Confidence float64 `json:"confidence,omitempty"`
Reason string `json:"reason,omitempty"`
ProposalKey string `json:"proposalKey,omitempty"`
ChannelID string `json:"channelId"`
ChannelName string `json:"channelName"`
GuideSourceID string `json:"guideSourceId"`
GuideSourceName string `json:"guideSourceName"`
GuideID string `json:"guideId"`
GuideName string `json:"guideName"`
Method string `json:"method"` // "id", "name" or "alias"
ReviewRegion bool `json:"reviewRegion,omitempty"`
}
type GuideMatchRequest ¶
type GuideMatchRequest struct {
Selections []GuideCommitSelection `json:"selections,omitempty"`
UndoToken string `json:"undoToken,omitempty"`
GuideSourceID string `json:"guideSourceId,omitempty"`
AI string `json:"ai,omitempty"` // estimate, propose, or apply; AI never writes without apply.
ProposalKeys map[string]string `json:"proposalKeys,omitempty"`
ChannelIDs []string `json:"channelIds,omitempty"`
Overwrite bool `json:"overwrite"`
DryRun bool `json:"dryRun"`
// Reviewed is set by the owner route for explicitly accepted proposals, never by imports.
Reviewed bool `json:"-"`
}
type GuideMatchResult ¶
type GuideMatchResult struct {
UndoToken string `json:"undoToken,omitempty"`
AI *GuideAIStats `json:"ai,omitempty"`
Matched int `json:"matched"`
Unmatched int `json:"unmatched"`
Skipped int `json:"skipped"` // already had guide data and overwrite was false
// Ambiguous and RegionRejected count name matches the matcher refused:
// several guide ids or playlist rows share the name, or the declared
// regions contradict.
Ambiguous int `json:"ambiguous"`
RegionRejected int `json:"regionRejected"`
DryRun bool `json:"dryRun"`
Changes []GuideMatchChange `json:"changes"`
}
type Item ¶
type Item struct {
BreakAvailableAfterMS int64 `json:"breakAvailableAfterMs,omitempty"`
SourceID string `json:"sourceId,omitempty"`
BreakReleaseID string `json:"breakReleaseId,omitempty"`
BreakRevision string `json:"breakRevision,omitempty"`
BreakPoints []BreakPoint `json:"breakPoints,omitempty"`
BreakPointsMS []int64 `json:"breakPointsMs,omitempty"`
ReelID string `json:"reelId,omitempty"`
ReelClipID string `json:"reelClipId,omitempty"`
EpisodeTitle string `json:"episodeTitle,omitempty"`
ShowTitle string `json:"showTitle,omitempty"`
Art string `json:"art,omitempty"`
Genres []string `json:"genres,omitempty"`
GUID string `json:"guid,omitempty"`
ShowGUID string `json:"showGuid,omitempty"`
MediaType string `json:"mediaType,omitempty"`
Premiere bool `json:"premiere,omitempty"`
Live bool `json:"live,omitempty"`
Key core.RatingKey `json:"key"`
Title string `json:"title"`
DurationMS int64 `json:"durationMs"`
Summary string `json:"summary,omitempty"`
Rating string `json:"rating,omitempty"`
Thumb string `json:"thumb,omitempty"`
// Show metadata keeps episodes in season order inside a shuffle,
// marathon or newest-first playout. Zero values are movies and items
// saved before weekly scheduling, which stay in their stored order.
ShowKey core.RatingKey `json:"showKey,omitempty"`
Season int `json:"season,omitempty"`
Episode int `json:"episode,omitempty"`
ReleasedMS int64 `json:"releasedMs,omitempty"`
// Slate is "offair" for a guide entry that fills a gap. It is not a
// catalogue title and is never stored on a channel.
Slate string `json:"slate,omitempty"`
}
type KindRegistry ¶ added in v0.3.3
type KindRegistry struct {
// contains filtered or unexported fields
}
KindRegistry holds the Live TV source kinds. Safe for concurrent use.
func NewKindRegistry ¶ added in v0.3.3
func NewKindRegistry() *KindRegistry
NewKindRegistry returns a registry holding the built-in kinds.
func (*KindRegistry) Classify ¶ added in v0.3.3
func (r *KindRegistry) Classify(src Source) (SourceKind, bool)
Classify returns the first registered kind that recognises src, in registration order (xtream and plugin kinds before m3u, so an Xtream login or plugin source is never mistaken for a plain playlist URL).
func (*KindRegistry) Descriptors ¶ added in v0.3.3
func (r *KindRegistry) Descriptors() []extend.Descriptor
Descriptors returns the liveTVSource descriptors for every kind.
func (*KindRegistry) Kinds ¶ added in v0.3.3
func (r *KindRegistry) Kinds() []SourceKind
func (*KindRegistry) Lookup ¶ added in v0.3.3
func (r *KindRegistry) Lookup(id string) (SourceKind, bool)
func (*KindRegistry) Register ¶ added in v0.3.3
func (r *KindRegistry) Register(k SourceKind) error
func (*KindRegistry) Unregister ¶ added in v0.3.3
func (r *KindRegistry) Unregister(id string)
Unregister removes a runtime source kind by id.
type MaintenanceDiagnostics ¶
type MaintenanceDiagnostics struct {
PanicCount uint64 `json:"panicCount"`
LastPanicAt time.Time `json:"lastPanicAt,omitzero"`
LastPanicSite string `json:"lastPanicSite,omitempty"`
LastPanicMessage string `json:"lastPanicMessage,omitempty"`
}
MaintenanceDiagnostics retains every recovered panic even when repeated stack logging is throttled. The owner diagnostics endpoint exposes it.
type Options ¶
type Options struct {
VODChanged func() // provider index or connection changed
// BreakInput opens an exclusive background playback source, never a viewer session.
// The final argument is an identity captured from an admitted save, never
// a request context. The callback must revalidate it on each background run.
BreakInput func(context.Context, core.RatingKey, int64) (markers.BreakInput, error)
BreakAnalyzer *markers.BreakAnalyzer
GuideAI GuideAIClient
Reels func(context.Context, string) (ReelSnapshot, error)
InputUser func(context.Context) (*core.User, error)
StyleScreens func(string) *config.LiveTVScreens
Watchlist interface{ Generation() uint64 }
Picker core.PersonalPicker
State core.State
Users interface {
Users(context.Context) ([]core.User, error)
}
PersonalChanged func(int64)
Graphics core.ChannelGraphics
PlexGuideToken func() string
PlexGuideURL string // test endpoint
CanPlay func(*core.User, bool, time.Time) bool
StreamLimit func(*core.User) int
DB *sql.DB
Catalog core.Catalog
Collections core.Collections
Playback core.Playback
Transcoder core.Transcoder
HTTPClient *http.Client
LogoHTTP *http.Client // optional test transport for the logo index; nil uses the guarded client
LogoIndexURL func() string
HealthSweepMinutes func() int // 0 defaults to 15; negative disables
Now func() time.Time
// Logger receives credential-safe import, playback and delivery diagnostics.
Logger *slog.Logger
// Allowed applies additional owner title/genre policies to every surface.
Allowed func(*core.User, *core.Title) bool
// Warm resolves/primes a title without opening a viewer stream.
Warm func(context.Context, core.RatingKey, time.Duration) error
// Availability is the resolver's cached playability. Known-unavailable
// titles are left out of the guide; unknown titles stay in place.
Availability core.AvailabilitySource
// Sealer protects source credentials at rest (secrets.go); nil stores
// them as given.
Sealer config.FieldSealer
// Kinds overrides the source-kind registry; nil uses the built-ins.
Kinds *KindRegistry
}
type PersonalIngredient ¶
type PersonalPolicy ¶
type PersonalRecipe ¶
type PersonalRecipe struct {
Ingredients []PersonalIngredient `json:"ingredients"`
PauseWhenAway bool `json:"pauseWhenAway"`
NameFormat string `json:"nameFormat"`
RepeatHours int `json:"repeatHours"`
NightMaxMinutes int `json:"nightMaxMinutes"`
}
type PinnedSlot ¶
type PinnedSlot struct {
ID string `json:"id"`
Name string `json:"name"`
Start int `json:"start"`
End int `json:"end"`
Days []int `json:"days,omitempty"`
Date string `json:"date,omitempty"`
Sources []ProgramSource `json:"sources,omitempty"`
Items []Item `json:"items,omitempty"`
Mode string `json:"mode,omitempty"`
RepeatDays int `json:"repeatDays,omitempty"`
Breaks *ChannelLook `json:"breaks,omitempty"`
}
type PlexLineup ¶ added in v0.3.4
type Policy ¶
type Policy struct {
Personal *PersonalPolicy `json:"personal,omitempty"`
UserID int64 `json:"userId"`
Disabled bool `json:"disabled"`
// Transcode forces IPTV compatibility conversion for this viewer on new tunes.
// It does not change channel settings or another viewer's playback.
Transcode bool `json:"transcode"`
// Restricted limits the viewer to Channels (none when empty), private
// ones included. Unrestricted viewers see every public channel, including
// ones added later, plus the private channels in Granted; Channels is
// empty.
Restricted bool `json:"restricted"`
Channels []string `json:"channels,omitempty"`
Granted []string `json:"granted,omitempty"`
Favorites []string `json:"favorites,omitempty"`
MaxRating string `json:"maxRating,omitempty"`
// contains filtered or unexported fields
}
Policy is one viewer's Live TV access. It is the only channel allow-list: the owner edits it from the viewer's page and from each channel.
type PreviewSession ¶
type PreviewSession struct {
ID string `json:"id"`
Playlist string `json:"playlist"`
ActiveSourceID string `json:"activeSourceId,omitempty"`
ActiveSourceName string `json:"activeSourceName,omitempty"`
Programme *Programme `json:"programme,omitempty"`
}
PreviewSession is what the owner UI needs to play a tuned channel. Stream URLs never leave the server; the playlist is relative to the livetv API.
type ProgramSource ¶ added in v0.3.0
type ProgramSource struct {
StartDate string `json:"startDate,omitempty"`
ID string `json:"id,omitempty"`
Kind string `json:"kind,omitempty"`
ShowKey core.RatingKey `json:"showKey,omitempty"`
StartSeason int `json:"startSeason,omitempty"`
StartEpisode int `json:"startEpisode,omitempty"`
Order string `json:"order,omitempty"`
Strip bool `json:"strip,omitempty"`
SegmentID string `json:"segmentId,omitempty"`
Personal *PersonalRecipe `json:"personal,omitempty"`
Sources []ProgramSource `json:"sources,omitempty"`
Name string `json:"name,omitempty"`
Weight int `json:"weight,omitempty"`
Items []Item `json:"items,omitempty"`
Collection core.RatingKey `json:"collection,omitempty"`
Filter *core.Filter `json:"filter,omitempty"`
Watched string `json:"watched,omitempty"`
}
ProgramSource is one weighted part of a mix. Weight 0 means 1. Watched is "", "watched" or "unwatched" for the whole household.
type Programme ¶
type Programme struct {
BlockID string `json:"blockId,omitempty"`
SourceID string `json:"sourceId,omitempty"`
Pinned bool `json:"pinned,omitempty"`
Rule string `json:"rule,omitempty"`
Reason string `json:"reason,omitempty"`
Lens string `json:"lens,omitempty"`
ID string `json:"id"`
ChannelID string `json:"channelId"`
Start time.Time `json:"start"`
End time.Time `json:"end"`
Item Item `json:"item"`
// contains filtered or unexported fields
}
type ProviderAccount ¶ added in v0.3.4
type ProviderAccount struct {
Status string `json:"status,omitempty"`
Trial bool `json:"trial,omitempty"`
ExpiresAt *time.Time `json:"expiresAt,omitempty"`
MaxConnections int `json:"maxConnections,omitempty"`
ActiveConnections int `json:"activeConnections"`
Formats []string `json:"formats,omitempty"`
CheckedAt time.Time `json:"checkedAt"`
}
ProviderAccount is what an IPTV panel reports about the owner's login.
type ReelSnapshot ¶
type ReelSnapshot struct {
ID string
Anchor time.Time
Order string
Repeat time.Duration
Clips []ReelClip
}
ReelSnapshot is copied from saved On Air metadata outside request/tick paths. Anchor is the persisted saved-revision timestamp, never the query window.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) AcquireProvider ¶
AcquireProvider shares the live tap budget with each VOD HTTP request. A lease lasts until the response body closes, including cancelled seeks.
func (*Service) AdoptAddonSource ¶ added in v0.3.3
AdoptAddonSource moves a legacy Stremio source onto an add-on's channel source kind, in place. The source keeps its id, name and refresh setting; the add-on link is dropped (the plugin record holds it now). Channels are untouched: the add-on channel source mints the same channel and input ids, so numbers, enabled flags, favourites, ratings, guide matches and transcode settings carry over. A source that already moved is left alone.
func (*Service) AllowedChannel ¶ added in v0.3.4
AllowedChannel resolves one channel by id or number and applies the same policy check as AllowedChannels without loading the lineup. Plex tune used the whole list only to find the requested channel.
func (*Service) AllowedChannelCached ¶ added in v0.3.0
func (s *Service) AllowedChannelCached(ctx context.Context, u *core.User, id string, cached func(context.Context, core.RatingKey) (*core.Title, error)) error
AllowedChannelCached checks one channel and its current programme using local title facts only. Missing programme title or inherited show facts fail closed. The supplied lookup must not perform network or release resolution.
func (*Service) AllowedChannels ¶
func (*Service) AllowedChannelsForIDs ¶
func (s *Service) AllowedChannelsForIDs(ctx context.Context, u *core.User, ids []string) ([]Channel, error)
AllowedChannelsForIDs checks a guide's selected channels without waiting for unrelated channels to finish their background preparation.
func (*Service) AuthenticateMediaGrant ¶ added in v0.3.0
func (s *Service) AuthenticateMediaGrant(r *http.Request, active func(context.Context, int64) *core.User) (*core.User, bool)
AuthenticateMediaGrant authorizes GET and HEAD media for the session that minted the stream grant. It does not accept account tokens and it does not authorize session control.
func (*Service) ChannelForViewer ¶
ChannelForViewer resolves channel identity for metadata after guide filtering.
func (*Service) ChannelPage ¶ added in v0.3.4
func (s *Service) ChannelPage(ctx context.Context, q ChannelPageQuery) (ChannelPage, error)
ChannelPage returns one page of full channel records for the console list and guide, plus the totals and groups the page needs to lay out the rest.
func (*Service) ChannelPermitted ¶ added in v0.3.0
ChannelPermitted decides one channel. A memo on ctx, when present, answers repeat checks for the same channel without another guide read. Callers that are not looking at a live channel must not call this.
func (*Service) ChannelSummaries ¶ added in v0.3.4
func (s *Service) ChannelSummaries(ctx context.Context) ([]ChannelSummary, error)
ChannelSummaries returns the whole lineup in display order. The result is shared and must be treated as read-only.
func (*Service) Coverage ¶
func (s *Service) Coverage(ctx context.Context) ([]GuideCoverage, error)
Coverage reports, for every channel, how many programmes the guide has in the next 24 hours and when its guide data runs out.
func (*Service) DeleteChannel ¶
func (*Service) Failover ¶
Failover is owned by the shared input planner, which retries without changing the viewer's output clock.
func (*Service) GraphicsRequests ¶
GraphicsRequests is a background-only planning snapshot. Empty lookID limits it to watched/clock channels, with at least three minutes of looks and fifteen minutes of plugin segments. Near boundaries sort first across all channels so a long future rundown cannot fill the render queue ahead of an imminent element. A lookID requests static clips for every channel using that saved look.
func (*Service) GuideChannels ¶
func (s *Service) GuideChannels(ctx context.Context, q, source string, limit int) ([]GuideChannel, error)
GuideChannels searches stored XMLTV channels. Every word of q must appear, in any order, in the name, a display name or the guide id, so "fox phoenix" finds "FOX LOCAL Phoenix". Exact matches rank first, then channels that still have listings ahead, then by name.
func (*Service) GuideForChannels ¶ added in v0.3.4
func (s *Service) GuideForChannels(ctx context.Context, u *core.User, from, until time.Time, ids []string) ([]Programme, error)
GuideForChannels builds the guide for the requested channels only. The console sends the rows it can see; nil means the whole lineup (XMLTV).
func (*Service) GuideWindow ¶ added in v0.3.3
GuideWindow is the span of listings an import keeps: a day back and two weeks ahead of now.
func (*Service) Handler ¶
Handler is the owner management API. Mount behind the application's owner authentication and CSRF middleware; it deliberately cannot authenticate Plex tokens on its own. Streaming uses the separately authenticated Plex adapter.
func (*Service) HomeHub ¶
HomeHub is the domain-level row used by the owner's final-layout preview. The Plex adapter preserves its own channel/tune metadata for this row ID; these synthetic keys are never sent to catalogue playback.
func (*Service) ImportProgress ¶ added in v0.3.4
func (s *Service) ImportProgress(id string) (SourceProgress, bool)
ImportProgress returns a live snapshot for the owner endpoint.
func (*Service) ImportSource ¶
ImportSource atomically replaces source programming and logs the outcome. Owner changes to mapping, enabled state, channel numbering, favourites and restrictions survive refresh.
func (*Service) ImportUpload ¶ added in v0.2.49
func (s *Service) ImportUpload(ctx context.Context, id, part string, body io.Reader) (Source, error)
ImportUpload streams a raw playlist or guide body (gzip is decompressed while reading) into an existing source.
func (*Service) KindRegistry ¶ added in v0.3.3
func (s *Service) KindRegistry() *KindRegistry
KindRegistry exposes this service's source-kind registry.
func (*Service) LegacyStremioSources ¶ added in v0.3.3
LegacyStremioSources returns the sources still on the built-in Stremio kind, with their add-on links opened, for the start-up migration.
func (*Service) LineupChanged ¶ added in v0.3.0
LineupChanged is the DVR refreshedAt clients poll. It moves whenever the channel set changes, including twice in the same wall-clock second.
func (*Service) LiveUsage ¶ added in v0.3.4
LiveUsage reports current viewing and provider usage. It reads only in-memory state. Source limits come from the console’s existing source snapshot; this poll must never deserialize stored playlists or guides.
func (*Service) MaintenanceDiagnostics ¶
func (s *Service) MaintenanceDiagnostics() MaintenanceDiagnostics
func (*Service) MatchGuides ¶
func (s *Service) MatchGuides(ctx context.Context, req GuideMatchRequest) (GuideMatchResult, error)
MatchGuides maps IPTV channels to guide channels from any source: an exact tvg-id wins, then a case-insensitive id, then a normalized display name. Only guide channels with upcoming programmes are considered, and disabled channels only when listed in ChannelIDs. Without Overwrite, channels that already have programmes in the next 24 hours are left alone.
func (*Service) MigrateSecrets ¶ added in v0.2.4
MigrateSecrets seals source secrets stored in plaintext and returns how many rows it rewrote. A row is replaced only if unchanged since read (safe to rerun on any node); a row that does not open is left untouched and reported in the error.
func (*Service) OnNow ¶ added in v0.3.0
func (s *Service) OnNow(ctx context.Context, u *core.User, now, until time.Time) ([]Channel, []Programme, error)
OnNow is the bounded guide used to build a live row: one policy read, then at most the current and next programme for each enabled channel.
func (*Service) OnNowN ¶ added in v0.3.0
func (s *Service) OnNowN(ctx context.Context, u *core.User, now, until time.Time, limit int) ([]Channel, []Programme, error)
OnNowN stops after limit allowed channels. Home uses it so a large guide does not query a programme window for every channel on the request.
func (*Service) ParseSourceGuide ¶ added in v0.3.3
func (s *Service) ParseSourceGuide(ctx context.Context, src Source, channels []Channel, r io.Reader) (XMLGuide, error)
ParseSourceGuide reads an XMLTV guide (plain or gzip) for a source kind's Fetch: listings outside the guide window are dropped, as are channels that are neither among channels nor mapped to src by the owner.
func (*Service) PersonalChanged ¶
PersonalChanged invalidates only this viewer; recomposition remains throttled.
func (*Service) PlexLineups ¶ added in v0.3.4
func (*Service) Policies ¶ added in v0.3.2
Policies lists every stored viewer policy. Viewers without one see every channel.
func (*Service) ProgrammesSnapshot ¶
func (*Service) ReelChannelIDs ¶
func (*Service) RefreshGraphics ¶
RefreshGraphics refreshes saved reel metadata after a graphics/reel revision. App wiring may invoke it in its existing background invalidation flow.
func (*Service) RefreshGuide ¶
RefreshGuide is the owner-save hook for look and schedule changes. Viewer reads never call this method. The background worker also refreshes availability.
func (*Service) RefreshSource ¶
RefreshSource re-imports a stored source. On failure the existing channels and guide are kept and the error is recorded on the source.
func (*Service) RefreshVOD ¶
RefreshVOD streams large lists into a transaction. Unchanged revisions keep cached details; a failed refresh never removes the previous index.
func (*Service) RegisterSourceKind ¶ added in v0.3.3
func (s *Service) RegisterSourceKind(k SourceKind) error
RegisterSourceKind adds a source kind to this service.
func (*Service) ResolveStreamSource ¶ added in v0.3.3
func (s *Service) ResolveStreamSource(ctx context.Context, c Channel, src StreamSource) (string, http.Header, error)
ResolveStreamSource resolves a channel's stream input at tune time. HTTP(S) URLs return directly; plugin:// inputs delegate to the installed stream opener under its Open deadline.
func (*Service) SaveChannel ¶
func (*Service) SavePendingSource ¶ added in v0.2.49
SavePendingSource stores a named source that will receive a file upload next. A body that already has a playlist or guide is imported instead.
func (*Service) ServeDASHPart ¶
func (*Service) ServeHTTP ¶ added in v0.3.0
ServeHTTP writes Plex for Mac's protocol=http Matroska stream for a live session, when the decision can convert the channel.
func (*Service) ServePlaylist ¶
ServePlaylist writes the shared broadcast view or the owner's unchanged IPTV passthrough/relay view when continuous output is disabled.
func (*Service) ServeRelaySegment ¶
func (*Service) ServeResource ¶
func (*Service) ServeXMLTV ¶
func (*Service) SetChannelViewers ¶ added in v0.3.2
func (*Service) SetOnChange ¶ added in v0.3.0
func (s *Service) SetOnChange(fn func())
SetOnChange registers the Plex lineup refresh. Save, delete and source import call it after the database commit.
func (*Service) SetStreamOpener ¶ added in v0.3.3
func (s *Service) SetStreamOpener(fn func(ctx context.Context, c Channel, src StreamSource) (string, http.Header, error))
SetStreamOpener installs a lazy stream resolver for plugin:// stream inputs.
func (*Service) SourceChannels ¶ added in v0.3.3
SourceChannels returns the stored channels of one source, inputs unredacted (for a source kind's Fetch).
func (*Service) SourceKindOf ¶ added in v0.3.3
SourceKindOf classifies a saved source ("xtream", "guideOnly", "m3u").
func (*Service) StreamSourceStatuses ¶
func (s *Service) StreamSourceStatuses(ctx context.Context, channelID string) ([]StreamSourceStatus, error)
StreamSourceStatuses is owner-only health, without source URLs or upstream errors that might contain credentials. Transient failures never ban a source.
func (*Service) StyleChannelIDs ¶
StyleChannelIDs reads the invalidated lineup index, never programme payloads.
func (*Service) TranscodeFor ¶
func (s *Service) TranscodeFor(string) (core.HLSSession, bool)
TranscodeFor is unused by shared broadcasts: decoder retries are owned by their planner and never swap a viewer's encoder input.
func (*Service) Tune ¶
func (s *Service) Tune(ctx context.Context, u *core.User, channelID string, caps core.ClientCaps) (SessionInfo, error)
func (*Service) TuneWithSession ¶
func (s *Service) TuneWithSession(ctx context.Context, u *core.User, channelID string, caps core.ClientCaps, clientSessionID string) (result SessionInfo, resultErr error)
TuneWithSession preserves the client's playback-session identity independently of the server's stream, subscription and activity identities.
func (*Service) UnregisterSourceKind ¶ added in v0.3.3
UnregisterSourceKind removes a runtime source kind from this service.
func (*Service) UpdateChannels ¶ added in v0.3.4
func (*Service) ViewingSessions ¶
func (s *Service) ViewingSessions() []*core.PlaySession
ViewingSessions reports one trusted reservation unit per live viewer. It is used by ordinary playback's limit accounting, including HLS passthrough viewers that do not own an ffmpeg/source session.
type SessionInfo ¶
type SessionInfo struct {
ActiveSourceID string `json:"activeSourceId,omitempty"`
// Plex's rolling subscription identity is numeric; the stream UUID remains
// separate. These are ephemeral identities, scoped to this service lifetime.
SubscriptionID int64 `json:"-"`
ActivityID string `json:"-"`
ClientSessionID string `json:"-"`
MediaInfo *core.MediaInfo `json:"-"` // Actual source analysis for native clients.
ID string `json:"id"`
UserID int64 `json:"userId"`
Channel Channel `json:"channel"`
Programme *Programme `json:"programme,omitempty"`
StartedAt time.Time `json:"startedAt"`
}
type SnapshotView ¶
type SnapshotView string
SnapshotView selects an existing immutable representation. All Programme fields (including source/block provenance) survive the time-indexed read.
const ( SnapshotRaw SnapshotView = "raw" SnapshotPlayback SnapshotView = "playback" SnapshotGuide SnapshotView = "guide" SnapshotTimeline SnapshotView = "timeline" )
type Source ¶
type Source struct {
// LiveTV defaults to true for existing connections; VOD is opt-in.
LiveTV *bool `json:"useLiveTV,omitempty"`
VOD bool `json:"useVOD,omitempty"`
VODStatus *VODStatus `json:"vodStatus,omitempty"`
LineupID string `json:"lineupId,omitempty"`
Country string `json:"country,omitempty"`
PostalCode string `json:"postalCode,omitempty"`
PlexCursor int `json:"plexCursor,omitempty"`
ID string `json:"id"`
Name string `json:"name"`
Kind string `json:"kind,omitempty"` // a source kind id, e.g. plugin:<id>/channels
PlaylistURL string `json:"playlistUrl,omitempty"`
GuideURL string `json:"guideUrl,omitempty"`
// Inline uploads are supplied on import and are not returned by GET.
Playlist string `json:"playlist,omitempty"`
Guide string `json:"guide,omitempty"`
UpdatedAt time.Time `json:"updatedAt"`
// Auth authenticates playlist, guide and stream requests to the provider.
// Secrets are redacted by the owner API (see auth.go).
Auth *SourceAuth `json:"auth,omitempty"`
// RefreshHours caps the time between automatic refreshes of URL-backed
// sources: 0 uses the 6 hour default, a negative value means manual
// refresh only. Sources also refresh before mapped listings run out.
// Inline uploads never refresh automatically.
RefreshHours int `json:"refreshHours,omitempty"`
// LastError/LastErrorAt/RefreshFailures record failed refreshes; a
// successful import clears them. Existing data is kept on failure.
LastError string `json:"lastError,omitempty"`
LastErrorAt *time.Time `json:"lastErrorAt,omitempty"`
RefreshFailures int `json:"refreshFailures,omitempty"`
// SkippedVOD counts VOD entries (Xtream /movie/ and /series/ streams)
// the last playlist import left out. It is persisted with the source so
// the console can report what the import dropped.
SkippedVOD int `json:"skippedVod,omitempty"`
// Read-only statistics computed by Sources(); ignored on import.
HasPlaylist bool `json:"hasPlaylist"`
HasGuide bool `json:"hasGuide"`
ChannelCount int `json:"channelCount"`
GuideChannelCount int `json:"guideChannelCount"`
ProgrammeCount int `json:"programmeCount"`
GuideFrom *time.Time `json:"guideFrom,omitempty"`
GuideUntil *time.Time `json:"guideUntil,omitempty"`
NextRefresh *time.Time `json:"nextRefresh,omitempty"`
// Account is the provider's report on this login (Xtream panels),
// refreshed with the lineup. Read-only.
Account *ProviderAccount `json:"account,omitempty"`
// Groups are the provider's channel groups from the last refresh, in
// provider order, including the ones the owner excludes. Read-only.
Groups []SourceGroup `json:"groups,omitempty"`
// ExcludeGroups are group names the owner leaves out; their channels
// are not imported at all. NewGroups "exclude" adds each group that
// first appears on a refresh to ExcludeGroups; "" includes it.
// HideAdult leaves out every group the provider flags as adult.
ExcludeGroups []string `json:"excludeGroups,omitempty"`
NewGroups string `json:"newGroups,omitempty"`
HideAdult bool `json:"hideAdult,omitempty"`
// GroupOrder is the owner's group order. Empty keeps the provider's
// order and numbers; otherwise channels are numbered 1… down the
// listed groups (unlisted groups follow in provider order).
GroupOrder []string `json:"groupOrder,omitempty"`
// Provider etiquette for the source's streams. MaxConnections caps
// simultaneous provider connections below what the panel allows (0 uses
// the panel's limit; it can never raise it). TuneGapSeconds is the least
// time between two new provider streams: 0 is the default (2 s on a
// connection-limited account, none otherwise), negative turns it off.
// TunesPerHour caps new provider streams per hour; 0 is no cap.
MaxConnections int `json:"maxConnections,omitempty"`
TuneGapSeconds int `json:"tuneGapSeconds,omitempty"`
TunesPerHour int `json:"tunesPerHour,omitempty"`
}
type SourceAuth ¶
type SourceAuth struct {
// Type: "" (none), "basic", "bearer", "headers" or "xtream".
Type string `json:"type,omitempty"`
Username string `json:"username,omitempty"`
Password string `json:"password,omitempty"` // secret
Token string `json:"token,omitempty"` // secret (bearer)
// UserAgent and Referer apply to every type; many providers reject
// unknown clients.
UserAgent string `json:"userAgent,omitempty"`
Referer string `json:"referer,omitempty"`
// Headers are extra request headers (cookies, API keys); values are secret.
Headers map[string]string `json:"headers,omitempty"`
// Xtream Codes: the panel URL. Playlist and guide URLs are derived from
// it and the credentials, and never returned by the API.
Server string `json:"server,omitempty"`
// Output selects the Xtream stream format: "ts" (default) or "m3u8".
Output string `json:"output,omitempty"`
}
SourceAuth is how Ether authenticates to an IPTV or guide provider. It is used for the source's playlist and guide fetches and, through upstreamHeaders, for the streams of channel inputs that belong to it.
type SourceDescribe ¶ added in v0.3.3
type SourceDescribe struct {
Label extend.Text
Hint extend.Text
Icon string
Order int
Editor string
Params []extend.ParamField
YieldsChannels bool
YieldsGuide bool
}
SourceDescribe carries the console-facing description of a source kind.
type SourceGroup ¶ added in v0.3.4
type SourceGroup struct {
Name string `json:"name"`
Channels int `json:"channels"`
Adult bool `json:"adult,omitempty"`
// Excluded reports whether the owner's rules leave this group out.
Excluded bool `json:"excluded,omitempty"`
}
SourceGroup is one provider channel group.
type SourceKind ¶ added in v0.3.3
type SourceKind interface {
ID() string
Describe() SourceDescribe
Matches(src Source) bool
// Fetch fills src.Playlist/src.Guide from URLs as needed (so they are
// stored for the next refresh) and returns the parsed result.
Fetch(ctx context.Context, s *Service, src *Source) (Fetched, error)
}
SourceKind is one Live TV source kind: how the console describes it, how a saved Source is recognised as this kind, and how it yields channels, inputs and guide data. Fetch runs on import/refresh only, never on a request path; playback reads stored channels.
To add a kind: implement SourceKind and register it (built-ins in builtinSourceKinds; runtime kinds such as plugin channel sources, which include Stremio `tv` add-ons, via Service.RegisterSourceKind). Then serve the result of KindRegistry.Descriptors through the extend registry. A kind that needs its own Source fields beyond playlist/guide/auth must extend Source additively and classify in Matches before "m3u".
type SourceProgress ¶ added in v0.3.4
type SourceProgress struct {
Phase string `json:"phase"` // starting, playlist, guide, saving
Read int64 `json:"read"`
Total int64 `json:"total,omitempty"`
Channels int `json:"channels,omitempty"`
Programmes int `json:"programmes,omitempty"`
SavedChannels int `json:"savedChannels,omitempty"`
SavedProgrammes int `json:"savedProgrammes,omitempty"`
Started time.Time `json:"started"`
Updated time.Time `json:"updated"`
}
SourceProgress is the owner-visible progress of one manual source import. Read counts bytes the panel has sent, so a multi-gigabyte guide can be watched while it downloads.
type SourceUsage ¶ added in v0.3.4
type SourceUsage struct {
SourceID string `json:"sourceId"`
// Open is how many provider connections Ether holds now.
Open int `json:"open"`
// StartsLastHour counts stream starts reserved in the last hour.
StartsLastHour int `json:"startsLastHour"`
}
SourceUsage is one source's provider connections and stream starts.
type StreamSource ¶
type StreamSource struct {
ID string `json:"id"`
Name string `json:"name"`
URL string `json:"url"`
Enabled bool `json:"enabled"`
Priority int `json:"priority"` // smaller first; equal priorities retain list order
// AuthSourceID names the source whose provider credentials this input
// uses; empty means the channel's own source.
AuthSourceID string `json:"authSourceId,omitempty"`
// Headers are request headers this input needs (a Stremio stream's
// proxy headers), sent after the source's own.
Headers map[string]string `json:"headers,omitempty"`
}
StreamSource is one independently replaceable input to a channel. EPG, numbering, favourites and viewer policy belong to Channel, never to an input.
type StreamSourceStatus ¶
type StreamSourceStatus struct {
ID string `json:"id"`
State string `json:"state"`
Failures int `json:"failures"`
LastChecked time.Time `json:"lastChecked,omitempty"`
LastPlayed time.Time `json:"lastPlayed,omitempty"`
RetryAfter time.Time `json:"retryAfter,omitempty"`
LastError string `json:"lastError,omitempty"`
}
type Timeline ¶
type Timeline struct {
ChannelID string `json:"channelId"`
Timezone string `json:"timezone"`
Now int64 `json:"now"`
Dayparts []TimelineDaypart `json:"dayparts"`
Elements []TimelineElement `json:"elements"`
}
type TimelineDaypart ¶
type TimelineElement ¶
type TimelineElement struct {
ID string `json:"id"`
Kind string `json:"kind"`
Start int64 `json:"start"`
End int64 `json:"end"`
Title string `json:"title"`
Subtitle string `json:"subtitle,omitempty"`
MediaType string `json:"mediaType,omitempty"`
BlockID string `json:"blockId,omitempty"`
SourceID string `json:"sourceId,omitempty"`
Pinned bool `json:"pinned"`
BreakPoints []BreakPoint `json:"breakPoints,omitempty"`
Art string `json:"art"`
Rule string `json:"rule"`
Children []TimelineElement `json:"children,omitempty"`
}
type TuneError ¶ added in v0.3.4
type TuneError struct {
Code string
Stage string
UpstreamStatus int
RetryAfter time.Duration
// contains filtered or unexported fields
}
TuneError retains machine-readable evidence without retaining a provider URL, response body or headers in its printable message. Unwrap preserves existing cancellation, availability and stream-limit handling.
type Usage ¶ added in v0.3.4
type Usage struct {
// Sessions counts live tunes; Viewers the distinct viewers behind them.
Sessions int `json:"sessions"`
Viewers int `json:"viewers"`
Watching []ChannelUsage `json:"watching"`
Sources []SourceUsage `json:"sources"`
}
Usage is the Live TV console's live picture: who is watching which channel, and how much of each provider's allowance Ether is using.
type VODIndexer ¶
VODIndexer adds indexed provider files to the aggregate source contract.
func (*VODIndexer) HasDirectSources ¶
func (v *VODIndexer) HasDirectSources() bool
func (*VODIndexer) HasTorrentIndexer ¶
func (v *VODIndexer) HasTorrentIndexer() bool
func (*VODIndexer) MissingSources ¶
func (v *VODIndexer) MissingSources() error
func (*VODIndexer) Name ¶
func (v *VODIndexer) Name() string
func (*VODIndexer) ResolveTorrent ¶
func (*VODIndexer) Search ¶
func (v *VODIndexer) Search(ctx context.Context, r core.SearchRequest) ([]core.Release, error)
func (*VODIndexer) SearchRescue ¶
func (v *VODIndexer) SearchRescue(ctx context.Context, r core.SearchRequest) ([]core.Release, error)
func (*VODIndexer) SearchRescueWith ¶
func (v *VODIndexer) SearchRescueWith(ctx context.Context, r core.SearchRequest, arrived func([]core.Release)) ([]core.Release, error)
func (*VODIndexer) SearchWith ¶
func (v *VODIndexer) SearchWith(ctx context.Context, r core.SearchRequest, arrived func([]core.Release)) ([]core.Release, error)
type VirtualDASHError ¶ added in v0.3.0
type VirtualDASHError struct {
Err error
// Message is the client-facing reason when it is more specific than Err.
Message string
}
VirtualDASHError is a virtual channel that could not produce DASH. Plex turns it into a decision document. A bare 503 is what Plex Web reports as s1001 (Network), which hides the reason and blocks fallback.
func (*VirtualDASHError) Error ¶ added in v0.3.0
func (e *VirtualDASHError) Error() string
func (*VirtualDASHError) Unwrap ¶ added in v0.3.0
func (e *VirtualDASHError) Unwrap() error
type XMLGuide ¶
type XMLGuide struct {
Channels map[string]Channel
Programmes []Programme
// Names holds every display-name of each XMLTV channel, in order.
Names map[string][]string
// LateChannels counts <channel> elements that appeared after the first
// <programme>. A valid guide has none; they are skipped rather than
// buffered, so name candidates they declare are missed.
LateChannels int
}
Source Files
¶
- addon_streams.go
- auth.go
- break_tap.go
- breaks.go
- broadcast.go
- broadcast_frames.go
- broadcast_http.go
- broadcast_intro.go
- broadcast_overlay.go
- broadcast_plan.go
- broadcast_policy.go
- broadcast_queue.go
- broadcast_registry.go
- broadcast_schedule.go
- broadcast_signal.go
- broadcast_start.go
- broadcast_views.go
- bulk.go
- channel_access.go
- channel_access_migrate.go
- channel_cache.go
- channel_memo.go
- channel_warm.go
- compact_programmes.go
- dash.go
- dash_virtual.go
- diagnostics.go
- graphics_requests.go
- groups.go
- guide.go
- guide_ai.go
- guide_compile.go
- guide_review.go
- guide_snapshot.go
- guide_timeline_snapshot.go
- handler.go
- health_sweep.go
- http.go
- hubs.go
- import.go
- input_relay.go
- input_relay_dash.go
- iptv_compat.go
- limit.go
- lineup.go
- logos.go
- maintenance.go
- media_grant.go
- media_headers.go
- numbering.go
- onair.go
- onair_clock.go
- personal.go
- personal_index.go
- personal_rundown.go
- playout.go
- plexguide.go
- pods.go
- preview.go
- probe_live.go
- programming.go
- programming_migrate.go
- progress.go
- proxy.go
- reels.go
- schedule.go
- secrets.go
- service.go
- slate.go
- snapshot_fingerprint.go
- source_expand.go
- sourcekinds.go
- stream_sources.go
- timeline.go
- types.go
- upstream_tap.go
- usage.go
- viewer_lifecycle.go
- virtual_tune.go
- vod.go
- warm_recent.go
- xtream.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package livetvtest supplies deterministic runner fakes for protocol adapters.
|
Package livetvtest supplies deterministic runner fakes for protocol adapters. |