Files
go-mxl-player/cmd/mxl-player/playlist_runtime.go
T
2026-09-01 21:48:29 +03:00

128 lines
2.7 KiB
Go

package main
import (
"context"
"errors"
"time"
"mxl-player/internal/playback"
)
const playlistReadinessInterval = 10 * time.Millisecond
var (
ErrPlayerPlaybackRequired = errors.New("player playback is required")
ErrPlayerSessionControllerRequired = errors.New("player session controller is required")
ErrPlayerStatusStoreRequired = errors.New("player status store is required")
)
type playerPlaylist struct {
Controller *playback.PlaylistController
Coordinator *playback.PlaylistReadinessCoordinator
Commands chan playback.PlaylistCommand
Readiness chan playback.PlaylistReadiness
}
func newPlayerPlaylist(
playlist playback.Playlist,
retry playback.RetryPolicy,
player *playerPlayback,
) (*playerPlaylist, error) {
if player == nil {
return nil, ErrPlayerPlaybackRequired
}
if player.Controller == nil {
return nil, ErrPlayerSessionControllerRequired
}
if player.Status == nil {
return nil, ErrPlayerStatusStoreRequired
}
commands := make(chan playback.PlaylistCommand, 32)
readiness := make(chan playback.PlaylistReadiness, 8)
controller, err := playback.NewPlaylistController(
playlist,
retry,
player.Commands,
)
if err != nil {
return nil, err
}
coordinator, err := playback.NewPlaylistReadinessCoordinator(
controller,
player.Controller,
player.Status,
readiness,
playlistReadinessInterval,
)
if err != nil {
return nil, err
}
return &playerPlaylist{
Controller: controller,
Coordinator: coordinator,
Commands: commands,
Readiness: readiness,
}, nil
}
func (p *playerPlaylist) Run(ctx context.Context) error {
runCtx, cancel := context.WithCancel(ctx)
defer cancel()
results := make(chan error, 2)
go func() {
results <- p.Controller.Run(runCtx, p.Commands, p.Readiness)
}()
go func() {
results <- p.Coordinator.Run(runCtx)
}()
first := <-results
cancel()
second := <-results
if ctx.Err() != nil {
return ctx.Err()
}
if err := playlistRuntimeError(first); err != nil {
return err
}
if err := playlistRuntimeError(second); err != nil {
return err
}
return nil
}
func (p *playerPlaylist) Select(index int) bool {
return p.enqueue(playback.PlaylistCommand{
Kind: playback.PlaylistSelect,
Index: index,
})
}
func (p *playerPlaylist) Next() bool {
return p.enqueue(playback.PlaylistCommand{Kind: playback.PlaylistNext})
}
func (p *playerPlaylist) Previous() bool {
return p.enqueue(playback.PlaylistCommand{Kind: playback.PlaylistPrevious})
}
func (p *playerPlaylist) enqueue(command playback.PlaylistCommand) bool {
select {
case p.Commands <- command:
return true
default:
return false
}
}
func playlistRuntimeError(err error) error {
if err == nil || errors.Is(err, context.Canceled) {
return nil
}
return err
}