Create Services for Playlist Export / Import#3387
Create Services for Playlist Export / Import#3387marcelveldt merged 9 commits intomusic-assistant:devfrom
Conversation
|
Why make "include_track_metadata" optional ? I think it is good to have at all times |
|
Overall I think this is a great feature, nice work!
|
I was really worried about performance, specifically in the case of library delete/reload or switching from beta to prod and back again, the ability to match quickly without additional metadata seemed like a savings during export, but honestly after doing some benchmarking I agree. I'll make it the default and get rid of the option. |
|
@marcelveldt-traveling @marcelveldt I've updated to include version field, I also removed the "option" on export, it just always includes the data needed. I'll hang tight until you have some time to think about the long-running process options, going to flip this back to draft until then. |
|
PR for the background tasks controller is now up: |
9a728dd to
1bce226
Compare
178b787 to
1bce226
Compare
Updated to use background task controller :) |
|
OK, inspired by your EXTMA info, I have updated the builtin provider's playlist handling (mainly to fix its inefficiency). |
8b80ef2 to
6ac0c69
Compare
Rewrite export/import to leverage the M3U infrastructure from PR music-assistant#3451: - Export reads stored M3U files directly (already enriched with metadata) - Import writes parsed PlaylistItem objects preserving all extended tags - Background matching searches providers for unavailable URIs using ISRC/MusicBrainz IDs first, then fuzzy title/artist/duration matching - Radio export/import via M3U format - Controller-level API endpoints for playlist and radio export/import - 17 new tests covering scoring logic and radio round-trip
…ists Explicitly find the builtin provider mapping instead of using _select_provider_id, which could pick a non-builtin mapping first (e.g. filesystem) and then reject it.
|
@marcelveldt If you'd like to have a peak here, I think this now in a decent place with your update, once this is in I will add a basic front end that someone can make better :) |
|
Upon re-look @marcelveldt should I break this out to a seperate import_export file in order to try to set up for avoiding init sprawl like has been done for chromecast and spotify? |
Yeah that would be better as the builtin provider is getting big now. We could split it up into dedicated init.py, provider.py, helpers.py, constants.py etc. But we can also do that in a follow-up PR and add this new function first, the refactor next |
Co-authored-by: Marcel van der Veldt <m.vanderveldt@outlook.com>
9824f16 to
47193ef
Compare
Extract MediaItem-to-PlaylistItem conversion into a shared helper (media_item_to_playlist_item) in helpers/playlists.py. Rewrite the controller's export_playlist to fetch tracks from any provider and generate M3U on the fly, removing the builtin-only restriction. Slim the builtin provider's _build_m3u_entry_from_uri to use the shared helper instead of duplicating the conversion logic.
Trim export_playlist docstring per reviewer feedback. Rewrite export_radios to export all library radio stations (any provider) instead of only builtin ones, using the shared helper.
marcelveldt
left a comment
There was a problem hiding this comment.
Nice work @chrisuthe !
Cool QoL feature that people will love
Allows import/export of MA playlists and radio stations via M3U8 format. Export writes full metadata using a rich set of extended M3U tags, and import recreates playlists by parsing those tags and optionally running background "Library Matching" to resolve tracks across providers. Matching uses a tiered strategy: exact ID matching (ISRC/MusicBrainz) first, then fuzzy metadata fallback. Great for backing up your library, transferring between MA instances, or migrating across providers.
A quick test page for exercising the API is available here: https://gist.github.com/chrisuthe/387180c78b8b12ae12b6659c814fa7d2 — save it locally and open in a browser.
New API Commands
music/playlists/export_playlistdb_playlist_idmusic/playlists/import_playlistm3u_data,library_matching(optional, defaultfalse),match_providers(optional, defaultnull)library_matching=true, a background task searches providers to resolve unmatched URIs using a tiered matching strategy. Whenmatch_providersis set (e.g.["spotify", "tidal"]), only those providers are searched — accepts instance IDs or domain names. Whennull, all available providers are searched.music/radio/export_radiosmusic/radio/import_radiosm3u_dataM3U Format
Uses standard
#EXTINFfor compatibility with other players, plus Music Assistant extended tags (ignored by standard players) for rich metadata. All extended tags use||(double-pipe) as the field separator to avoid conflicts with commas in metadata values.Extended Tags
#EXTMAkey=value||key=value#EXTPROVdomain||item_id||instance_id||content_type||sample_rate||bit_depth||bit_rate#EXTARTISTname||provider_domain||item_id||provider_instance#EXTALBUMname||provider_domain||item_id||provider_instance||version#EXTPODCASTname||provider_domain||item_id||provider_instance#EXTIMGtype||path||provider||remotely_accessibleEXTMA fields
name,media_type,isrc,mbid,album,version,podcast,authors,narratorsExample
How Matching Works
When
library_matching=true, each track whose URI can't be resolved (provider not available) is searched across available providers. Matching runs as a background task with progress tracking. Each search result is scored, and the highest-scoring result across all providers wins. If an ISRC or MusicBrainz ID matches (score 10), it returns immediately without searching further providers.A score of 0 means "not a match" — the candidate is rejected. Any score > 0 is a valid match candidate. The highest score wins. If no candidates score > 0, the original (unresolvable) URI is kept in the playlist.
Scoring table
Provider filtering
By default all providers are searched. Use
match_providersto limit the search:{"m3u_data": "...", "library_matching": true, "match_providers": ["spotify", "tidal"]}Accepts provider instance IDs (e.g.
"spotify_1") or domain names (e.g."spotify").Test Plan