Documentation
¶
Overview ¶
Package markers supplies release-duration-specific skip ranges. Remote lookups are opt-in and cached; no submissions are ever sent.
Index ¶
- Constants
- Variables
- func Probe(ctx context.Context, baseURL, apiKey string) error
- type BreakAnalyzer
- func (a *BreakAnalyzer) Analyze(ctx context.Context, in BreakInput) (points []BreakPoint, err error)
- func (a *BreakAnalyzer) CachedBreakPoints(ctx context.Context, in BreakInput) ([]BreakPoint, error)
- func (a *BreakAnalyzer) ObservePoints(ctx context.Context, in BreakInput, points []BreakPoint) error
- type BreakEvidence
- type BreakInput
- type BreakPoint
- type BreakScanPolicy
- type BreakSignal
- type BreakTap
- type Coverage
- type DialogueCue
- type Lookup
- type Marker
- type Options
- type RefreshTarget
- type Service
- func (s *Service) CachedMarkers(ctx context.Context, key core.RatingKey, info core.MediaInfo) ([]Marker, error)
- func (s *Service) Coverage(ctx context.Context, show int64) (Coverage, error)
- func (s *Service) DeletePlugin(ctx context.Context, source string) error
- func (s *Service) Handler() http.Handler
- func (s *Service) Markers(ctx context.Context, key core.RatingKey, info core.MediaInfo) ([]Marker, error)
- func (s *Service) Prune(ctx context.Context) (int64, error)
- func (s *Service) Put(ctx context.Context, key core.RatingKey, d time.Duration, ranges []Marker) error
- func (s *Service) PutPlugin(ctx context.Context, key core.RatingKey, d time.Duration, source string, ...) error
- func (s *Service) RefreshTargets(ctx context.Context) ([]RefreshTarget, error)
- func (s *Service) RememberRefreshTarget(ctx context.Context, key core.RatingKey, duration time.Duration) error
- type Stinger
Constants ¶
const BreakConfidence = 0.90
Variables ¶
var ErrBreakBandwidth = errors.New("act-break pre-air bandwidth budget unavailable")
Functions ¶
Types ¶
type BreakAnalyzer ¶
type BreakAnalyzer struct {
DB *sql.DB
FFmpeg string
OnCost func(video, cpu, wall time.Duration)
ScanPolicy func() BreakScanPolicy
Hardware func() core.HWAccel
// OnEvidence is a trusted local diagnostic observer. The source lease remains
// open during this synchronous call; observers must not close or retain it.
// Nil performs no export and installs no HTTP endpoint.
OnEvidence func(context.Context, BreakInput, BreakEvidence)
}
func (*BreakAnalyzer) Analyze ¶
func (a *BreakAnalyzer) Analyze(ctx context.Context, in BreakInput) (points []BreakPoint, err error)
func (*BreakAnalyzer) CachedBreakPoints ¶
func (a *BreakAnalyzer) CachedBreakPoints(ctx context.Context, in BreakInput) ([]BreakPoint, error)
CachedBreakPoints returns only locally stored positive evidence; no resolve, probe or decode. Full analyses and partial playout facts reinforce each other.
func (*BreakAnalyzer) ObservePoints ¶
func (a *BreakAnalyzer) ObservePoints(ctx context.Context, in BreakInput, points []BreakPoint) error
ObservePoints merges verified facts from partial playout into a separate release cache. It never represents a partial/empty viewing as a full scan.
type BreakEvidence ¶
type BreakEvidence struct {
ProviderStatsKnown bool `json:"providerStatsKnown"`
ProviderRequests int64 `json:"providerRequests"`
ProviderBytes int64 `json:"providerBytes"`
ProviderErrors int64 `json:"providerErrors"`
DecodedThroughMS int64 `json:"decodedThroughMs"`
CoverageComplete bool `json:"coverageComplete"`
Mode string `json:"mode,omitempty"`
Backend string `json:"backend,omitempty"`
AudioCandidates []BreakSignal `json:"audioCandidates,omitempty"`
KeyframeBlack []BreakSignal `json:"keyframeBlack,omitempty"`
CandidateWindows []BreakSignal `json:"candidateWindows,omitempty"`
ReadBytesKnown bool `json:"readBytesKnown"`
Partial bool `json:"partial"`
ReservedBytes int64 `json:"reservedBytes"`
ReadBytes int64 `json:"readBytes"`
Version int `json:"version"`
Key core.RatingKey `json:"key"`
DurationMS int64 `json:"durationMs"`
CacheHit bool `json:"cacheHit"`
Decoded bool `json:"decoded"`
Complete bool `json:"complete"`
Chapters []BreakSignal `json:"chapters"`
Black []BreakSignal `json:"black"`
Silence []BreakSignal `json:"silence"`
Scenes []BreakSignal `json:"scenes"`
Points []BreakPoint `json:"points"`
CPUMS int64 `json:"cpuMs"`
WallMS int64 `json:"wallMs"`
}
BreakEvidence intentionally contains neither source grants nor media. A cache hit reports CacheHit=true, Decoded=false and cached accepted points; historical decode candidates are unavailable unless a local observer saved them earlier. Complete=false candidates are partial and must not enter quality denominators.
type BreakInput ¶
type BreakInput struct {
ShouldYield func() bool `json:"-"`
Drain func(context.Context) error `json:"-"`
ProviderStatsBase *[3]int64 `json:"-"`
Key core.RatingKey `json:"key"`
ReleaseKey string
ReleaseID string
Revision string
URL string `json:"-"`
Info core.MediaInfo `json:"-"`
Close func() `json:"-"`
BytesRead func() int64 `json:"-"`
ReadErrors func() int64 `json:"-"`
ProviderStats func() (int64, int64, int64) `json:"-"`
// contains filtered or unexported fields
}
BreakInput is leased exclusively for background analysis. ReleaseKey must bind the source revision, payload, file and duration, never just a catalogue key. Close releases the source even when a cached analysis is reused.
func PlaybackBreakInput ¶
func PlaybackBreakInput(ps *core.PlaySession) BreakInput
PlaybackBreakInput binds playout observations to the same immutable release key as pre-air analysis, without performing source reads or resolving media.
type BreakPoint ¶
type BreakPoint struct {
AtMS int64 `json:"atMs"`
Source string `json:"source"`
Confidence float64 `json:"confidence"`
}
func ChapterBreaks ¶
func ChapterBreaks(info core.MediaInfo) []BreakPoint
Generic chapter numbers, intros and credits are deliberately not evidence.
func SelectBreaks ¶
func SelectBreaks(points []BreakPoint, duration int64, k int, spacing int64) []BreakPoint
SelectBreaks solves the ordered K-point spacing problem with dynamic programming. Confidence dominates; spacing towards ideal act lengths breaks ties. It returns fewer than K whenever evidence or safe spacing is lacking.
type BreakScanPolicy ¶
type BreakScanPolicy struct {
DailyBytes int64 `json:"dailyBytes,omitempty"`
ReleaseBytes int64 `json:"releaseBytes,omitempty"`
LargeReleaseBytes int64 `json:"largeReleaseBytes,omitempty"`
AllowLarge bool `json:"allowLarge,omitempty"`
}
BreakScanPolicy bounds extra pre-air source reads. Zero uses defaults; negative daily/release limits disable full scans. Chapters/cache bypass it.
type BreakSignal ¶
type BreakSignal struct {
StartMS int64 `json:"startMs"`
EndMS int64 `json:"endMs"`
Score *float64 `json:"score,omitempty"`
ChapterMatch bool `json:"chapterMatch,omitempty"`
}
BreakSignal contains measured source-media times. Score is the actual scdet percent when supplied by ffmpeg, never a synthesized confidence. It is absent for black/silence intervals and chapters, which have no measured score.
type BreakTap ¶
type BreakTap struct {
// contains filtered or unexported fields
}
BreakTap samples already decoded limited-range Y and signed little-endian PCM. It performs no I/O, allocation per frame, buffering of media or extra decode. Every frame samples <=2304 luma values plus its cheap audio RMS envelope. Only verified positive points survive a partial viewing; no empty full-scan cache entry is created from a tune, seek or interrupted programme.
func NewBreakTap ¶
func (*BreakTap) Points ¶
func (t *BreakTap) Points() []BreakPoint
type DialogueCue ¶
DialogueCue is one already-available subtitle cue time (text not needed).
type Lookup ¶ added in v0.3.0
type Lookup struct {
Enabled bool
APIKey string
IntroOff bool
CreditsOff bool
SourceOrder []string
}
Lookup is the live skip-marker configuration. IntroOff and CreditsOff hide those buttons. The zero value offers both.
type Marker ¶
type Marker struct {
Type string `json:"type"`
StartMS int64 `json:"startTimeOffset"`
EndMS int64 `json:"endTimeOffset"`
Final bool `json:"final"`
Source string `json:"source"`
}
func ApplyStingers ¶
ApplyStingers cuts stinger ranges out of credits markers, splitting one credits marker into the pieces before and after each stinger. Pieces under two seconds are dropped (a breath of crawl is not skippable). Afterwards exactly the last credits marker may be Final, and only when it reaches the end of the media — the shape PMS emits.
func FromChapters ¶
FromChapters uses explicit chapter labels only; generic Chapter 01 is not evidence.
type Options ¶
type Options struct {
Config func() Lookup // current IntroDB lookup and which skip buttons are offered
Logger *slog.Logger
DB *sql.DB
Enabled bool
BaseURL string
APIKey string
HTTPClient *http.Client
TTL time.Duration
Now func() time.Time
// Aligner, when set, shifts TheIntroDB markers from the reference
// runtime they were submitted against into the played release's
// timeline (dialogue-based, no video downloaded).
Aligner core.TimelineAligner
// AlignTimeout bounds one marker-shifting alignment (default 10s);
// on failure the unshifted markers are kept.
AlignTimeout time.Duration
// Dialogue supplies already-available subtitle cue times for the
// played release (cached sidecars), used for stinger detection.
Dialogue func(ctx context.Context, key core.RatingKey, info core.MediaInfo) ([]DialogueCue, bool)
}
type RefreshTarget ¶ added in v0.3.3
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
func (*Service) CachedMarkers ¶ added in v0.3.0
func (s *Service) CachedMarkers(ctx context.Context, key core.RatingKey, info core.MediaInfo) ([]Marker, error)
CachedMarkers uses chapters and locally cached ranges only. It never fetches or aligns remote markers, making it safe for non-resolving detail pages.
func (*Service) Coverage ¶
Coverage counts observed cached episodes; it does not imply coverage of the show's entire catalogue or that an official client displayed skip controls.
func (*Service) DeletePlugin ¶ added in v0.3.3
DeletePlugin removes cached results when a plugin is disabled or removed.
func (*Service) Handler ¶
Handler serves GET /shows/{TMDBID}, behind the owner's admin authentication.
func (*Service) Markers ¶
func (s *Service) Markers(ctx context.Context, key core.RatingKey, info core.MediaInfo) ([]Marker, error)
Markers returns the skip ranges for one probed release: chapter and remote markers (shifted into this release's timeline when they were submitted against a different cut), with stinger scenes cut out of the credits ranges.
func (*Service) Prune ¶
Prune deletes expired rows from the remote-lookup cache (markers_cache). An expired row is never served, so this only reclaims space; the next playback re-fetches as it would anyway.
func (*Service) PutPlugin ¶ added in v0.3.3
func (s *Service) PutPlugin(ctx context.Context, key core.RatingKey, d time.Duration, source string, ranges []Marker) error
PutPlugin stores a background result separately for each source.
func (*Service) RefreshTargets ¶ added in v0.3.3
func (s *Service) RefreshTargets(ctx context.Context) ([]RefreshTarget, error)
type Stinger ¶
Stinger is a scene inside the credits range that must not be skipped.
func StingersFromChapters ¶
StingersFromChapters finds post-credits scenes in the chapter layout: explicitly named stinger chapters, and the structural pattern of a short chapter sandwiched after a long credits chapter near the tail.
func StingersFromDialogue ¶
func StingersFromDialogue(cues []DialogueCue, creditsStart, duration time.Duration) []Stinger
StingersFromDialogue finds dialogue clusters that resume well inside the credits range after a long cue gap: the shape of a mid-/post-credits scene. Lyrics running continuously from the credits start never qualify, because their first cue follows the credits start without a long gap and their cues continue without one.