Files
go-mxl-player/internal/playback/playlist.go
T
2026-09-02 00:03:47 +03:00

128 lines
2.8 KiB
Go

package playback
import (
"errors"
"fmt"
"time"
)
var (
ErrPlaylistFeedUUIDRequired = errors.New("playlist feed UUID is required when its domain is configured")
ErrPlaylistEntryEmpty = errors.New("playlist entry must contain at least one feed")
ErrPlaylistSyncFeedsRequired = errors.New("synchronized playlist entry requires both video and audio feeds")
ErrPlaylistDurationNegative = errors.New("playlist entry duration cannot be negative")
ErrPlaylistFailurePolicy = errors.New("invalid playlist failure policy")
)
type PlaylistFailurePolicy uint8
const (
PlaylistFailureWait PlaylistFailurePolicy = iota
PlaylistFailureNext
)
func (p PlaylistFailurePolicy) String() string {
switch p {
case PlaylistFailureWait:
return "wait"
case PlaylistFailureNext:
return "next"
default:
return fmt.Sprintf("PlaylistFailurePolicy(%d)", uint8(p))
}
}
func (p PlaylistFailurePolicy) Validate() error {
if p != PlaylistFailureWait && p != PlaylistFailureNext {
return ErrPlaylistFailurePolicy
}
return nil
}
type PlaylistFeed struct {
Domain string
UUID string
}
type PlaylistEntry struct {
Name string
Video PlaylistFeed
Audio PlaylistFeed
SyncRequested bool
Duration time.Duration
}
type Playlist struct {
Entries []PlaylistEntry
Loop bool
OnFailure PlaylistFailurePolicy
Retry *RetryPolicy
}
func (f PlaylistFeed) IsConfigured() bool {
return f.UUID != ""
}
func (f PlaylistFeed) Validate() error {
if f.UUID != "" && f.Domain == "" {
return ErrFeedDomainRequired
}
if f.Domain != "" && f.UUID == "" {
return ErrPlaylistFeedUUIDRequired
}
return nil
}
func (e PlaylistEntry) Validate() error {
if err := e.Video.Validate(); err != nil {
return fmt.Errorf("video: %w", err)
}
if err := e.Audio.Validate(); err != nil {
return fmt.Errorf("audio: %w", err)
}
if !e.Video.IsConfigured() && !e.Audio.IsConfigured() {
return ErrPlaylistEntryEmpty
}
if e.SyncRequested && (!e.Video.IsConfigured() || !e.Audio.IsConfigured()) {
return ErrPlaylistSyncFeedsRequired
}
if e.Duration < 0 {
return ErrPlaylistDurationNegative
}
return nil
}
func (p Playlist) Validate() error {
if err := p.OnFailure.Validate(); err != nil {
return err
}
if p.Retry != nil {
if err := p.Retry.Validate(); err != nil {
return fmt.Errorf("playlist retry: %w", err)
}
}
for index, entry := range p.Entries {
if err := entry.Validate(); err != nil {
return fmt.Errorf("playlist entry %d: %w", index, err)
}
}
return nil
}
func (e PlaylistEntry) SessionConfig(retry RetryPolicy) SessionConfig {
return SessionConfig{
Video: FeedConfig{
Domain: e.Video.Domain,
UUID: e.Video.UUID,
Active: e.Video.UUID != "",
},
Audio: FeedConfig{
Domain: e.Audio.Domain,
UUID: e.Audio.UUID,
Active: e.Audio.UUID != "",
},
SyncRequested: e.SyncRequested,
Retry: retry,
}
}