Add smart playlists with full iTunes 12 import (Phase 1)
Auto-populating, criteria-driven playlists that import faithfully from iTunes. - lintunes/smart.py: recursive SmartCriteria/SmartGroup/SmartRule/SmartLimit model (JSON round-tripping), a shared FIELD_REGISTRY used by both the evaluator and the editor, and evaluate() (match all/any, nested groups, string/int/duration/rating/date/bool ops, "in the last N", limit by items/time/size). Null play/skip dates are treated as the distant past, matching iTunes. - iTunes import via a vendored MIT-licensed binary parser (lintunes/itunes_smart/, from cvzi/itunes_smartplaylist). Nested groups parse and evaluate; blobs we can't represent (MediaKind/iCloud/etc.) flag unsupported and keep the imported snapshot. "loved" is dropped per user pref. - library_manager: create/set/recompute smart playlists (undoable), field-scoped coalesced live recompute hooked into the edit/play/skip/add funnels, a no-op equality guard to avoid Syncthing churn, and manual-edit guards. main.py recomputes on load; conflict_resolver keeps newest criteria for smart lists. - GUI: ❧ glyph painted in the sidebar branch column, read-only track table for smart playlists, New/Edit Smart Playlist menus, and SmartPlaylistEditorDialog (per-field rule rows, match all/any, limits, live updating). Tests: tests/test_round14.py (real captured blobs in tests/smart_blobs.json). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -114,11 +114,18 @@ class TestItunesImporter:
|
||||
xml_path = _make_itunes_xml(tracks, playlists)
|
||||
library, report = import_itunes_xml(xml_path, MUSIC_ROOT, check_files=False)
|
||||
|
||||
assert set(library.playlists.keys()) == {"FOLDER1", "PL1"}
|
||||
# Smart playlists are now imported (the junk blobs can't be parsed, so
|
||||
# the criteria are flagged unsupported and the iTunes snapshot is kept).
|
||||
assert set(library.playlists.keys()) == {"FOLDER1", "PL1", "SMART1"}
|
||||
smart = library.playlists["SMART1"]
|
||||
assert smart.playlist_type.value == "smart"
|
||||
assert smart.smart_criteria is not None and smart.smart_criteria.unsupported
|
||||
assert smart.track_ids == [1] # snapshot fallback
|
||||
# Track 999 doesn't exist — dropped from the playlist
|
||||
assert library.playlists["PL1"].track_ids == [2]
|
||||
assert library.playlists["PL1"].parent_persistent_id == "FOLDER1"
|
||||
assert report.skipped_smart == 1
|
||||
assert report.smart_count == 1
|
||||
assert report.smart_unsupported == 1
|
||||
assert report.skipped_system == 2
|
||||
assert report.playlist_count == 1
|
||||
assert report.folder_count == 1
|
||||
|
||||
Reference in New Issue
Block a user