mirror of
https://github.com/navidrome/navidrome.git
synced 2026-08-01 07:21:17 +00:00
* feat(utils): add ParseDuration/FormatDuration with day and week units * feat(criteria): add per-playlist refreshDelay to smart playlist rules * feat(smartplaylist): honor per-playlist refreshDelay in refresh gate * feat(subsonic): compute smart playlist validUntil from effective refresh delay * fix(playlists): reset smart playlist evaluation window when rules change via API * refactor(utils): flatten FormatDuration recursion, single-pass duration regex * fix(playlists): address PR review feedback - Reset EvaluatedAt to nil instead of zero-time on rules change and NSP re-import, so getPlaylist(s) never reports year-1 Changed/validUntil in the window between an edit and the next owner read - Parse negative d/w durations so they are rejected with the consistent "negative duration" error instead of "unknown unit" - Quote input in the negative-duration error, matching the parse error - Gate per-playlist RefreshDelay behind IsSmartPlaylist, matching its doc
77 lines
3.2 KiB
Go
77 lines
3.2 KiB
Go
package model_test
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/navidrome/navidrome/conf"
|
|
"github.com/navidrome/navidrome/conf/configtest"
|
|
"github.com/navidrome/navidrome/model"
|
|
"github.com/navidrome/navidrome/model/criteria"
|
|
"github.com/navidrome/navidrome/tests"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Playlist", func() {
|
|
Describe("ToM3U8()", func() {
|
|
var pls model.Playlist
|
|
BeforeEach(func() {
|
|
pls = model.Playlist{Name: "Mellow sunset"}
|
|
pls.Tracks = model.PlaylistTracks{
|
|
{MediaFile: model.MediaFile{Artist: "Morcheeba feat. Kurt Wagner", Title: "What New York Couples Fight About",
|
|
Duration: 377.84,
|
|
LibraryPath: "/music/library", Path: "Morcheeba/Charango/01-06 What New York Couples Fight About.mp3"}},
|
|
{MediaFile: model.MediaFile{Artist: "A Tribe Called Quest", Title: "Description of a Fool (Groove Armada's Acoustic mix)",
|
|
Duration: 374.49,
|
|
LibraryPath: "/music/library", Path: "Groove Armada/Back to Mine_ Groove Armada/01-01 Description of a Fool (Groove Armada's Acoustic mix).mp3"}},
|
|
{MediaFile: model.MediaFile{Artist: "Lou Reed", Title: "Walk on the Wild Side",
|
|
Duration: 253.1,
|
|
LibraryPath: "/music/library", Path: "Lou Reed/Walk on the Wild Side_ The Best of Lou Reed/01-06 Walk on the Wild Side.m4a"}},
|
|
{MediaFile: model.MediaFile{Artist: "Legião Urbana", Title: "On the Way Home",
|
|
Duration: 163.89,
|
|
LibraryPath: "/music/library", Path: "Legião Urbana/Música p_ acampamentos/02-05 On the Way Home.mp3"}},
|
|
}
|
|
})
|
|
It("generates the correct M3U format", func() {
|
|
tests.SkipOnWindows("path separator bug (#TBD-path-sep-model)")
|
|
expected := `#EXTM3U
|
|
#PLAYLIST:Mellow sunset
|
|
#EXTINF:378,Morcheeba feat. Kurt Wagner - What New York Couples Fight About
|
|
/music/library/Morcheeba/Charango/01-06 What New York Couples Fight About.mp3
|
|
#EXTINF:374,A Tribe Called Quest - Description of a Fool (Groove Armada's Acoustic mix)
|
|
/music/library/Groove Armada/Back to Mine_ Groove Armada/01-01 Description of a Fool (Groove Armada's Acoustic mix).mp3
|
|
#EXTINF:253,Lou Reed - Walk on the Wild Side
|
|
/music/library/Lou Reed/Walk on the Wild Side_ The Best of Lou Reed/01-06 Walk on the Wild Side.m4a
|
|
#EXTINF:164,Legião Urbana - On the Way Home
|
|
/music/library/Legião Urbana/Música p_ acampamentos/02-05 On the Way Home.mp3
|
|
`
|
|
Expect(pls.ToM3U8()).To(Equal(expected))
|
|
})
|
|
})
|
|
|
|
Describe("RefreshDelay", func() {
|
|
BeforeEach(func() {
|
|
DeferCleanup(configtest.SetupConfig())
|
|
conf.Server.SmartPlaylistRefreshDelay = 5 * time.Second
|
|
})
|
|
|
|
It("returns the global config value when rules have no refreshDelay", func() {
|
|
pls := model.Playlist{Rules: &criteria.Criteria{Expression: criteria.All{criteria.Is{"loved": true}}}}
|
|
Expect(pls.RefreshDelay()).To(Equal(5 * time.Second))
|
|
})
|
|
|
|
It("returns the per-playlist value when set", func() {
|
|
pls := model.Playlist{Rules: &criteria.Criteria{
|
|
Expression: criteria.All{criteria.Is{"loved": true}},
|
|
RefreshDelay: 24 * time.Hour,
|
|
}}
|
|
Expect(pls.RefreshDelay()).To(Equal(24 * time.Hour))
|
|
})
|
|
|
|
It("returns the global value for non-smart playlists", func() {
|
|
pls := model.Playlist{}
|
|
Expect(pls.RefreshDelay()).To(Equal(5 * time.Second))
|
|
})
|
|
})
|
|
})
|