JSON playlist loader

This commit is contained in:
Dmitry Sergeev
2026-09-01 21:58:20 +03:00
parent 3b7662fea7
commit 362ae15867
2 changed files with 274 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
package main
import (
"encoding/json"
"fmt"
"io"
"os"
"time"
"mxl-player/internal/playback"
)
type playlistFile struct {
Entries []playlistFileEntry `json:"entries"`
Loop bool `json:"loop"`
}
type playlistFileEntry struct {
Name string `json:"name"`
Video *playlistFileFeed `json:"video"`
Audio *playlistFileFeed `json:"audio"`
Sync bool `json:"sync"`
Duration string `json:"duration"`
}
type playlistFileFeed struct {
Domain string `json:"domain"`
UUID string `json:"uuid"`
}
func loadPlaylistFile(path string) (playback.Playlist, error) {
file, err := os.Open(path)
if err != nil {
return playback.Playlist{}, fmt.Errorf("open playlist %q: %w", path, err)
}
defer file.Close()
playlist, err := decodePlaylistFile(file)
if err != nil {
return playback.Playlist{}, fmt.Errorf("decode playlist %q: %w", path, err)
}
return playlist, nil
}
func decodePlaylistFile(reader io.Reader) (playback.Playlist, error) {
decoder := json.NewDecoder(reader)
decoder.DisallowUnknownFields()
var file playlistFile
if err := decoder.Decode(&file); err != nil {
return playback.Playlist{}, fmt.Errorf("decode JSON: %w", err)
}
var extra any
if err := decoder.Decode(&extra); err != io.EOF {
if err == nil {
return playback.Playlist{}, fmt.Errorf("decode JSON: multiple root values")
}
return playback.Playlist{}, fmt.Errorf("decode trailing JSON: %w", err)
}
playlist := playback.Playlist{
Entries: make([]playback.PlaylistEntry, len(file.Entries)),
Loop: file.Loop,
}
for index, entry := range file.Entries {
duration := time.Duration(0)
if entry.Duration != "" {
parsed, err := time.ParseDuration(entry.Duration)
if err != nil {
return playback.Playlist{}, fmt.Errorf(
"playlist entry %d duration %q: %w",
index,
entry.Duration,
err,
)
}
duration = parsed
}
playlist.Entries[index] = playback.PlaylistEntry{
Name: entry.Name,
Video: playlistFileFeedToPlayback(entry.Video),
Audio: playlistFileFeedToPlayback(entry.Audio),
SyncRequested: entry.Sync,
Duration: duration,
}
}
if err := playlist.Validate(); err != nil {
return playback.Playlist{}, fmt.Errorf("validate playlist: %w", err)
}
return playlist, nil
}
func playlistFileFeedToPlayback(feed *playlistFileFeed) playback.PlaylistFeed {
if feed == nil {
return playback.PlaylistFeed{}
}
return playback.PlaylistFeed{Domain: feed.Domain, UUID: feed.UUID}
}