joren c131bf6ab1 ye
2026-04-04 20:38:08 +02:00
ye
2026-04-04 20:38:08 +02:00
ye
2026-04-04 20:38:08 +02:00
2026-04-03 21:26:08 +02:00
ye
2026-04-04 20:38:08 +02:00

QTransfer

Spotify -> Qobuz playlist transfer tool in Go.

Features

  • Spotify OAuth login via Authorization Code + PKCE (client secret not required).
  • Manual Spotify callback code entry (paste callback URL/code) enabled by default.
  • Session cache for Spotify/Qobuz credentials and tokens (so you do not need to re-enter each run).
  • Fetches all Spotify playlists and liked songs.
  • Playlist URL mode (--playlist-url) for direct targeted transfers.
  • Monitor mode to detect playlist updates (--monitor) with optional sync-to-Qobuz (--monitor-transfer) and sync modes (--sync-mode).
  • Interactive selection prompt (or non-interactive flags).
  • Creates Qobuz playlists and fills them with best-effort track matches.
  • Transfers liked songs into a dedicated playlist (not favorites).
  • Writes a JSON transfer report with unmatched tracks and errors.

Requirements

  • Go 1.22+
  • Spotify app client ID with redirect URI configured (default: http://127.0.0.1:8888/callback)
  • Qobuz account username/password

Build

go build ./cmd/qtransfer

Usage

./qtransfer login

qtransfer login runs an interactive setup and stores Spotify/Qobuz credentials/tokens in the session file.

After login, run transfers without re-entering credentials:

./qtransfer

For first-time non-interactive usage (without login), you can still pass flags:

./qtransfer \
  --spotify-client-id "<spotify-client-id>" \
  --qobuz-username "<qobuz-user>" \
  --qobuz-password "<qobuz-password>"

Credentials/tokens are cached in ~/.config/qtransfer/session.json by default.

Useful flags

  • --all: transfer all Spotify playlists
  • --liked: include liked songs as a generated Qobuz playlist
  • --playlist "Name" (repeatable): transfer specific playlists by exact name
  • --playlist-url "..." (repeatable): transfer specific Spotify playlists by URL/URI/ID
  • --config sync.toml: TOML config with global options and per-playlist monitor sync jobs
  • --spotify-manual-code=true|false: paste callback URL/code manually or use local callback server
  • --remember-creds=true|false: persist/reuse tokens and credentials in session file
  • --session-file path: custom session file path (default ~/.config/qtransfer/session.json)
  • --monitor: monitor selected playlists for updates
  • --monitor-interval 5m: monitor polling interval
  • --monitor-once: run one monitor check and exit
  • --monitor-transfer: in monitor mode, sync changed playlists to Qobuz
  • --sync-mode append|mirror: append only, or mirror source by recreating target playlist
  • --target-playlist-id 123456: bind single monitored source playlist to an existing Qobuz playlist ID
  • --qobuz-self-test: run Qobuz login/verify/search checks and exit (skips Spotify)
  • --qobuz-self-test-write: when self-test is enabled, also create a test playlist and add one track
  • --qobuz-self-test-query "...": search query used during self-test
  • --non-interactive: fail instead of prompting when no explicit selection is given
  • --dry-run: resolve matches only, do not create playlists or add tracks
  • --report transfer-report.json: report output path
  • --public-playlists: create public Qobuz playlists

Quick auth check without waiting for Spotify:

./qtransfer \
  --qobuz-self-test \
  --qobuz-username "<qobuz-user>" \
  --qobuz-password "<qobuz-password>"

Transfer from direct Spotify playlist URLs:

./qtransfer \
  --spotify-client-id "<spotify-client-id>" \
  --qobuz-username "<qobuz-user>" \
  --qobuz-password "<qobuz-password>" \
  --playlist-url "https://open.spotify.com/playlist/37i9dQZF1DX0XUsuxWHRQd" \
  --playlist-url "spotify:playlist:37i9dQZF1DWY4xHQp97fN6"

Monitor selected playlists for changes:

./qtransfer \
  --spotify-client-id "<spotify-client-id>" \
  --playlist-url "https://open.spotify.com/playlist/37i9dQZF1DX0XUsuxWHRQd" \
  --monitor --monitor-interval 2m

Monitor with append-only sync (never removes from Qobuz):

./qtransfer \
  --playlist-url "https://open.spotify.com/playlist/37i9dQZF1DX0XUsuxWHRQd" \
  --monitor --monitor-transfer --sync-mode append --monitor-interval 2m

Monitor with mirror sync (recreates playlist on change):

./qtransfer \
  --playlist-url "https://open.spotify.com/playlist/37i9dQZF1DX0XUsuxWHRQd" \
  --monitor --monitor-transfer --sync-mode mirror --monitor-interval 2m

Config-file mode:

./qtransfer --config sync.toml

Example sync.toml:

[global]
monitor = true
monitor_transfer = true
monitor_interval = "10m"
sync_mode = "append"
include_liked = true

[[playlist]]
url = "https://open.spotify.com/playlist/37i9dQZF1DX0XUsuxWHRQd"
sync_mode = "append"
target_playlist_id = 61646089

[[playlist]]
url = "spotify:playlist:37i9dQZF1DWY4xHQp97fN6"
sync_mode = "mirror"
enabled = true

Login command:

./qtransfer login

Logout command (removes cached session):

./qtransfer logout

Environment variables

  • SPOTIFY_CLIENT_ID
  • SPOTIFY_REDIRECT_URI (optional)
  • SPOTIFY_SCOPES (optional)
  • QTRANSFER_SPOTIFY_MANUAL_CODE (optional, defaults to true)
  • QTRANSFER_SESSION_FILE (optional)
  • QTRANSFER_REMEMBER_CREDS (optional, defaults to true)
  • QTRANSFER_CONFIG (optional)
  • QTRANSFER_MONITOR (optional)
  • QTRANSFER_MONITOR_ONCE (optional)
  • QTRANSFER_MONITOR_TRANSFER (optional)
  • QTRANSFER_MONITOR_INTERVAL (optional)
  • QTRANSFER_SYNC_MODE (optional: append|mirror)
  • QTRANSFER_TARGET_PLAYLIST_ID (optional, monitor mode only)
  • QTRANSFER_QOBUZ_SELF_TEST (optional)
  • QTRANSFER_QOBUZ_SELF_TEST_WRITE (optional)
  • QTRANSFER_QOBUZ_SELF_TEST_QUERY (optional)
  • QOBUZ_USERNAME
  • QOBUZ_PASSWORD
  • QOBUZ_APP_ID (optional, defaults to reverse-engineered app id)
  • QOBUZ_APP_SECRET (optional, defaults to reverse-engineered app secret)
Description
No description provided
Readme 5.9 MiB
Languages
Go 100%