feat(M003/S02): smart playlist integration — play_count and days_since_played fields

Backend:
- Added play_count and days_since_played to rule engine field whitelist
- days_since_played uses julianday() expression with COALESCE for NULL handling
- Never-played tracks (NULL last_played) match 'greater_than' but not 'less_than'
- Added PlayCount + LastPlayed to library.Track struct
- Evaluate query selects play_count and last_played from track_metadata
- Added play_count to sort field options

Frontend:
- Added play_count and days_since_played to field and numeric field lists
- Added play_count to sort options

All 49 rule engine + 15 service tests pass unchanged.
This commit is contained in:
2026-03-21 15:26:43 -04:00
parent 9bf2bbab2e
commit 9c85cfcc7b
3 changed files with 94 additions and 2 deletions
@@ -26,6 +26,8 @@ const FIELDS: string[] = [
'library',
'track_number',
'disc_number',
'play_count',
'days_since_played',
];
const NUMERIC_FIELDS = new Set([
@@ -39,6 +41,8 @@ const NUMERIC_FIELDS = new Set([
'library',
'track_number',
'disc_number',
'play_count',
'days_since_played',
]);
const TEXT_OPERATORS = [
@@ -59,7 +63,7 @@ const NUMERIC_OPERATORS = [
'between',
];
const SORT_FIELDS = ['title', 'artist', 'album', 'year', 'duration', 'random'];
const SORT_FIELDS = ['title', 'artist', 'album', 'year', 'duration', 'play_count', 'random'];
// ── Helpers ─────────────────────────────────────────────────────────