* 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