Cross-Service Playlist Pushing¶
Overview¶
Pushtunes supports pushing playlists directly between services without going through a separate CSV export step. This allows you to:
- Migrate playlists between streaming services (Spotify ↔ YouTube Music)
- Migrate playlists from streaming services to local servers (Spotify/YTM → Subsonic/Jellyfin)
- Migrate playlists from local servers to streaming services (Subsonic/Jellyfin → Spotify/YTM)
- Keep playlists synchronized across multiple services
Note: This feature performs track-by-track matching using similarity algorithms. For best results, use --require-all-tracks to ensure all tracks can be found on both sides before creating the playlist.
Supported Directions¶
- Spotify ↔ YouTube Music: Between streaming services
- Spotify/YTM → Subsonic/Jellyfin: From streaming services to local servers (uses in-memory fuzzy matching)
- Subsonic/Jellyfin → Spotify/YTM: From local servers to streaming services
Requirements¶
Authentication¶
You need to be authenticated with both the source and target services:
Spotify (both as source and target):
YouTube Music (both as source and target):
ytmusicapi browser # Creates browser.json
# Or specify a different file with --ytm-auth=filename.json
Subsonic (both as source and target):
export SUBSONIC_URL=https://your-server.com
export SUBSONIC_USER=your-username
export SUBSONIC_PASS=your-password
Jellyfin (both as source and target):
export JELLYFIN_URL=https://your-server.com
export JELLYFIN_USER=your-username
export JELLYFIN_PASS=your-password
Basic Usage¶
Between Streaming Services¶
# Spotify → YouTube Music
# Note: Spotify requires --source-playlist-id (not --playlist-name)
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm
# YouTube Music → Spotify
pushtunes push playlist --from ytm --playlist-name "Synthwave Mix" --to spotify
To Local Servers (Subsonic/Jellyfin)¶
# Spotify → Subsonic
# Note: Spotify requires --source-playlist-id (not --playlist-name)
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to subsonic
# YouTube Music → Jellyfin
pushtunes push playlist --from ytm --playlist-name "Chill Vibes" --to jellyfin
Note: When pushing to Subsonic/Jellyfin, pushtunes uses in-memory fuzzy matching against your entire music library. Only tracks that exist in your library can be added to playlists.
From Local Servers¶
# Subsonic → Spotify
pushtunes push playlist --from subsonic --playlist-name "My Mix" --to spotify
# Jellyfin → YouTube Music
# Note: Jellyfin requires --source-playlist-id (not --playlist-name)
pushtunes push playlist --from jellyfin --source-playlist-id "8e5d6f1d17423354e83a3c17cae758dc" --to ytm
Strict Matching with --require-all-tracks¶
By default, pushtunes will create a playlist even if some tracks can't be matched (partial success). For cross-service pushing, you probably want to use strict mode to ensure all tracks are found:
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--require-all-tracks
What happens in strict mode:
- All tracks must be matched (either automatically or via mappings)
- If even one track can't be matched, the operation fails
- No partial playlist is created
- You can then use mappings to fix the failures and retry
Without strict mode (default):
- Playlist is created with whatever tracks could be matched
- Missing tracks are skipped
- Useful for migrating large playlists where some items might be unavailable
Using Playlist IDs¶
Spotify (Required)¶
Spotify requires --source-playlist-id when used as a source because Spotify allows multiple playlists with the same name.
Jellyfin requires --source-playlist-id when used as a source for the same reason.
Finding Spotify playlist ID:
1. Open the playlist in Spotify (desktop or web)
2. Click Share → Copy link to playlist
3. The URL looks like: https://open.spotify.com/playlist/37i9dQZF1DXaXB8fQg7xif
4. The ID is the last part: 37i9dQZF1DXaXB8fQg7xif
Or use the Spotify URI:
1. Right-click playlist → Share → Copy Spotify URI
2. The URI looks like: spotify:playlist:37i9dQZF1DXaXB8fQg7xif
3. The ID is after playlist:: 37i9dQZF1DXaXB8fQg7xif
Finding Jellyfin playlist ID:
1. Open the playlist in Jellyfin web UI
2. The URL looks like: https://jellyfin.example.com/web/index.html#!/details?id=8e5d6f1d17423354e83a3c17cae758dc
3. The ID is the value after id=: 8e5d6f1d17423354e83a3c17cae758dc
Examples:
# From Spotify
pushtunes push playlist \
--from spotify \
--source-playlist-id "37i9dQZF1DXaXB8fQg7xif" \
--to ytm \
--require-all-tracks
# From Jellyfin
pushtunes push playlist \
--from jellyfin \
--source-playlist-id "8e5d6f1d17423354e83a3c17cae758dc" \
--to spotify \
--require-all-tracks
YouTube Music (Optional)¶
YouTube Music can use either --playlist-name or --source-playlist-id:
To find a YouTube Music playlist ID:
1. Open playlist in browser
2. URL looks like: https://music.youtube.com/playlist?list=PLrAXtmErZgOeiu...
3. The ID is after list=: PLrAXtmErZgOeiu...
Example with ID:
Example with name:
Working with Mappings¶
When tracks can't be auto-matched (different names, remasters, etc.), use mappings to provide manual matches.
See mappings_complete_example.csv for a comprehensive example file with all columns and common use cases.
Step 1: Export Failed Matches¶
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--require-all-tracks \
--export-csv=mappings-file \
--export-csv-file=playlist_mappings.csv
This creates a template with all tracks that had status not_found or similarity_too_low.
Step 2: Fill in Mappings¶
Edit playlist_mappings.csv:
type,artist,title,spotify_id,ytm_id,spotify_artist,spotify_title,ytm_artist,ytm_title,subsonic_artist,subsonic_title,subsonic_album,jellyfin_artist,jellyfin_title,jellyfin_album
track,"Volkor X","This Means War","","","","","Volkor X","This Really Means War",,,,,
track,"Mitch Murder","Current Events","","","","","Mitch Murder","Current Events (Remastered)",,,,,
For Subsonic/Jellyfin targets, use the subsonic_* and jellyfin_* columns:
type,artist,title,spotify_id,ytm_id,spotify_artist,spotify_title,ytm_artist,ytm_title,subsonic_artist,subsonic_title,subsonic_album,jellyfin_artist,jellyfin_title,jellyfin_album
track,"The Beatles","Let It Be",,,,,,,Beatles,Let It Be,Let It Be (Remastered),,,
track,"Foo Fighters","Best Of You",,,,,,,Foo Fighters,Best of You,Greatest Hits,,,
Step 3: Retry with Mappings¶
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--require-all-tracks \
--mappings-file=playlist_mappings.csv
Now the tracks that couldn't be auto-matched will use your manual mappings. See Mappings for more about this feature.
Conflict Resolution¶
If a playlist with the same name already exists on the target, use --on-conflict.
For Spotify and Jellyfin targets, you can also use --playlist-id to target a specific existing playlist by ID:
# Show differences and abort (default)
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--on-conflict=abort
# Replace entire playlist
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--on-conflict=replace
# Add missing tracks only
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--on-conflict=append
# Add missing, remove extras (full sync)
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--on-conflict=sync
Adjusting Similarity Threshold¶
If too many tracks aren't matching, try lowering the similarity threshold:
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--similarity=0.7 \
--require-all-tracks
Default: 0.8 (80% similarity required) Range: 0.0 to 1.0
Be careful: Lower thresholds may cause incorrect matches!
Example Workflows¶
Safe Cross-Service Migration¶
# Step 1: Try with strict mode
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--require-all-tracks \
--export-csv=mappings-file
# Step 2: Fill in mappings.csv for failed tracks
# Step 3: Retry with mappings
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--require-all-tracks \
--mappings-file=albums_mappings_template.csv
# Step 4: If whatever gods are in charge of music metadata are well-disposed towards you,
# All tracks are matched and playlist is created
Bidirectional Sync¶
# Mirror Spotify playlist to YTM
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--on-conflict=sync
# Mirror YTM playlist to Spotify
pushtunes push playlist --from ytm --playlist-name "Favorites" --to spotify \
--on-conflict=sync
Verbose Debugging¶
pushtunes push playlist --from spotify --source-playlist-id "37i9dQZF1DXaXB8fQg7xif" --to ytm \
--require-all-tracks \
--verbose \
--report=not_found,similarity_too_low
This shows:
- Detailed track matching results (
--verbose) - Full report of failures (
--report)
Limitations¶
- Track availability: Not all tracks available on one service exist on another
- Different versions: Services may have different versions (remaster, live, etc.)
- Metadata differences: Artist names and track titles may differ between services
- Rate limiting: Large playlists may take time due to API rate limits
Tips for Best Results¶
- Always use
--require-all-tracksfor cross-service pushing to ensure completeness - Use playlist IDs when possible for more reliable lookups
- Create mappings for problem tracks instead of lowering similarity threshold
- Test with small playlists first before migrating large collections
- Use
--verboseand--reportto understand matching behavior
Troubleshooting¶
"Playlist not found"¶
- Check playlist name spelling (case-insensitive but must match)
- Try using
--source-playlist-idinstead - Verify you're authenticated (check env vars for Spotify, browser.json for YTM)
"Only X/Y tracks matched"¶
- Use
--export-csv=mappings-fileto see which tracks failed - Review the failures and create manual mappings
- Consider lowering
--similaritythreshold (but be careful)
"No tracks could be matched"¶
- Verify the target service has the music available
- Check if track/artist names are significantly different
- Use mappings to provide manual matches
See Also¶
- Mappings.md - Detailed guide on manual mappings
- Export-CSV.md - CSV export for retry workflows