package playback import "errors" type PlaylistCommandKind uint8 const ( PlaylistSelect PlaylistCommandKind = iota + 1 PlaylistNext PlaylistPrevious ) type PlaylistCommand struct { Kind PlaylistCommandKind Index int } type PlaylistState struct { CurrentIndex int HasSelection bool } var ( ErrPlaylistEmpty = errors.New("playlist is empty") ErrPlaylistIndexOutOfRange = errors.New("playlist index is out of range") ErrPlaylistNoSelection = errors.New("playlist has no selected entry") ErrUnknownPlaylistCommand = errors.New("unknown playlist command") ) func ApplyPlaylistCommand( playlist Playlist, current PlaylistState, command PlaylistCommand, ) (PlaylistState, error) { if err := playlist.Validate(); err != nil { return current, err } if len(playlist.Entries) == 0 { return current, ErrPlaylistEmpty } lastIndex := len(playlist.Entries) - 1 switch command.Kind { case PlaylistSelect: if command.Index < 0 || command.Index > lastIndex { return current, ErrPlaylistIndexOutOfRange } return PlaylistState{CurrentIndex: command.Index, HasSelection: true}, nil case PlaylistNext: if !current.HasSelection { return PlaylistState{CurrentIndex: 0, HasSelection: true}, nil } if current.CurrentIndex < 0 || current.CurrentIndex > lastIndex { return current, ErrPlaylistIndexOutOfRange } if current.CurrentIndex == lastIndex { if playlist.Loop { return PlaylistState{CurrentIndex: 0, HasSelection: true}, nil } return current, nil } return PlaylistState{CurrentIndex: current.CurrentIndex + 1, HasSelection: true}, nil case PlaylistPrevious: if !current.HasSelection { index := 0 if playlist.Loop { index = lastIndex } return PlaylistState{CurrentIndex: index, HasSelection: true}, nil } if current.CurrentIndex < 0 || current.CurrentIndex > lastIndex { return current, ErrPlaylistIndexOutOfRange } if current.CurrentIndex == 0 { if playlist.Loop { return PlaylistState{CurrentIndex: lastIndex, HasSelection: true}, nil } return current, nil } return PlaylistState{CurrentIndex: current.CurrentIndex - 1, HasSelection: true}, nil default: return current, ErrUnknownPlaylistCommand } } func (s PlaylistState) Entry(playlist Playlist) (PlaylistEntry, bool) { if !s.HasSelection || s.CurrentIndex < 0 || s.CurrentIndex >= len(playlist.Entries) { return PlaylistEntry{}, false } return playlist.Entries[s.CurrentIndex], true } func ApplyPlaylistSelection( playlist Playlist, current PlaylistState, command PlaylistCommand, retry RetryPolicy, ) ( next PlaylistState, sessionCommand SessionCommand, apply bool, err error, ) { next, err = ApplyPlaylistCommand(playlist, current, command) if err != nil { return current, SessionCommand{}, false, err } apply = command.Kind == PlaylistSelect || next != current if !apply { return next, SessionCommand{}, false, nil } entry, ok := next.Entry(playlist) if !ok { return current, SessionCommand{}, false, ErrPlaylistNoSelection } session := entry.SessionConfig(retry) if err := session.Validate(); err != nil { return current, SessionCommand{}, false, err } return next, SessionCommand{ Kind: CommandSetSession, Session: session, }, true, nil }