Initial implementation: Spotify to Tidal playlist migrator - #1
Merged
Conversation
Adds the shared dataclasses (playlist/track/match models), the per-user config/data paths, on-disk JSON snapshot storage for harvested playlists, and small text-handling utilities (Spotify user-id parsing, DevTools token extraction, HTML-to-plain-text).
Reverse-engineers the same internal endpoints open.spotify.com's own web player uses (spclient.wg.spotify.com for a profile's playlist listing, api-partner.spotify.com's GraphQL "pathfinder" API for a playlist's tracks), authenticated with a bearer token + client-token pair copied out of DevTools -- there's no public Web API path left for this since Spotify locked it down.
Adds OAuth login/session persistence, ISRC-first fuzzy track matching against Tidal (rapidfuzz + duration sanity check), and idempotent playlist push (folder/playlist reuse by a locally recorded id, falling back to name lookup only on first push).
PySide6 app with three tabs backed by background QThread workers: Harvest (paste DevTools credentials, browse a profile's playlists, import selected ones), Match (fuzzy-match imported tracks against Tidal, fix mismatches by hand), and Push (create/update the matched playlists on Tidal). Columns are user-resizable and auto-fit to content; selection is native click/ctrl-click/shift-click.
The bare ubuntu-latest runner has none of the shared libraries PySide6's offscreen platform plugin dynamically links against (EGL/GL, xkbcommon, fontconfig, dbus) -- pytest failed to even import PySide6 with "libEGL.so.1: cannot open shared object file". Same requirement applies to the AppImage smoke test in the build job, which also runs with QT_QPA_PLATFORM=offscreen.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A desktop GUI (PySide6) for migrating playlists from Spotify to Tidal in three stages:
Commits
chore: scaffold project tooling and packaging— package layout, ruff/pre-commit/commitizen, CI, AppImage packagingfeat: add core data models and local snapshot store— shared dataclasses, config/data paths, on-disk snapshot storage, text utilitiesfeat: add Spotify client for harvesting playlists— reverse-engineered internal Spotify endpoints (spclient + pathfinder GraphQL)feat: add Tidal client and track matching— OAuth session, fuzzy matching, idempotent pushfeat: add desktop GUI for the harvest, match, and push workflow— the three-tab PySide6 appTest plan
pytest— 149 tests passingruff check/ruff format --check— clean