MySpotSync is a simple tool to sync .m3u8 playlists with Spotify. It reads one or more .m3u8 files, matches the tracks with Spotify's catalog, and creates/updates corresponding playlists in your Spotify account. It also includes a comparison feature to identify differences between local M3U8 playlists and their Spotify counterparts.
- Parse .m3u8 files - Extract track paths and metadata
- Match tracks with Spotify - Find corresponding tracks in Spotify catalog
- Sync playlists - Create/update Spotify playlists based on .m3u8 content
- Compare playlists - Identify differences between local M3U8 and Spotify playlists
- Dual interfaces:
- CLI - Simple command-line interface for scripting and automation
- TUI - Interactive Textual-based interface for monitoring sync status
-
M3U8Parser
- Read .m3u8 playlist files
- Extract file paths and EXTINF metadata
- Support for absolute and relative paths
-
TrackMatcher
- Extract metadata from audio files (artist, title, album)
- Search Spotify API for matching tracks
- Use fuzzy matching (≥90% similarity) for best results
-
SpotifySync
- OAuth authentication with Spotify
- Create playlists if they don't exist
- Update playlists with matched tracks (batch of 100)
- Handle rate limiting and API errors
-
SpotSyncCLI (Typer CLI)
- Command-line interface for automation
- Support for single or batch playlist syncing
- JSON output option for scripting
- Dry-run mode for safety
-
SpotSyncUI (Textual TUI)
- Interactive file selection
- Real-time sync progress
- Visual display of unmatched tracks
.m3u8 files → Parse → Extract metadata → Match with Spotify → Sync playlists
↓ ↓ ↓ ↓
File paths Artist/Title Track IDs Updated playlists
- Python 3.12 on WSL (Linux)
- Dependencies: spotipy, textual, mutagen (or tinytag), typer, python-Levenshtein
- 100 tracks per playlist update request
- ~10 requests/second (development mode)
- OAuth scopes: playlist-modify-private, playlist-read-private
- Extract metadata from audio files referenced in .m3u8
- Search Spotify: "{artist} {title}"
- Use Levenshtein distance for fuzzy matching
- Fallback to album/year if multiple matches
# Sync a single playlist
spotsync sync "My Playlist.m3u8"
# Sync multiple playlists
spotsync sync "Rock.m3u8" "Jazz.m3u8" "Workout.m3u8"
# Sync with custom Spotify playlist name
spotsync sync "My Playlist.m3u8" --name "Awesome Mix Vol. 1"
# Dry run (show what would be synced without making changes)
spotsync sync "My Playlist.m3u8" --dry-run
# Show unmatched tracks only
spotsync check "My Playlist.m3u8"
# Compare M3U8 with Spotify playlist
spotsync compare "My Playlist.m3u8"
# Compare with specific Spotify playlist name
spotsync compare "My Playlist.m3u8" --spotify-name "Different Name"
# Compare with different output formats
spotsync compare "My Playlist.m3u8" --format json
spotsync compare "My Playlist.m3u8" --format summary
# Compare with custom matching threshold
spotsync compare "My Playlist.m3u8" --threshold 0.75- Launch MySpotSync TUI with
spotsyncorspotsync tui - Select one or more .m3u8 files
- Review playlist names (derived from .m3u8 filenames)
- Start sync process
- View results and unmatched tracks
# Create virtual environment with uv
uv venv .venv
source .venv/bin/activate
# Install dependencies
uv pip install spotipy textual mutagen typer python-Levenshtein
# Register Spotify app at https://developer.spotify.com/dashboard
# Then configure credentials:
export SPOTIPY_CLIENT_ID='your_client_id'
export SPOTIPY_CLIENT_SECRET='your_client_secret'
export SPOTIPY_REDIRECT_URI='http://127.0.0.1:8888/callback'
# Install MySpotSync in development mode
uv pip install -e .
# Run MySpotSync
spotsync # Opens TUI
spotsync sync "playlist.m3u8" # CLI modespotsync/
├── __init__.py
├── m3u8_parser.py # Parse .m3u8 files
├── track_matcher.py # Match local tracks with Spotify
├── spotify_sync.py # Spotify API integration
├── cli.py # CLI interface (using Typer)
├── ui.py # Textual TUI
├── main.py # Entry point (routes to CLI or TUI)
├── pyproject.toml # Package configuration
└── README.md # Basic documentation
- Unmatched tracks: Listed in output for manual review
- API rate limits: Automatic retry with backoff
- Invalid file paths: Skip and report
- Missing metadata: Use filename as fallback
# Claude can easily use these commands:
# Quick sync of a playlist
spotsync sync "/path/to/playlist.m3u8"
# Check what would be synced without making changes
spotsync sync "/path/to/playlist.m3u8" --dry-run
# Get JSON output for processing
spotsync sync "/path/to/playlist.m3u8" --json
# Sync and get only summary
spotsync sync "/path/to/playlist.m3u8" --quiet
# Force update (replace entire playlist)
spotsync sync "/path/to/playlist.m3u8" --force
# Compare playlists
spotsync compare "/path/to/playlist.m3u8"
spotsync compare "/path/to/playlist.m3u8" --spotify-name "My Spotify List"
spotsync compare "/path/to/playlist.m3u8" --format json > comparison.json