Transferring Music Libraries

Last updated: November 19, 2023

Minim can be used as a free, open-source alternative to services like TuneMyMusic for moving playlists and synchronizing libraries between the supported streaming services.

from minim import qobuz, spotify, tidal

Prerequisites

All clients must be authenticated to access private user information. Assuming the relevant client credentials are stored as environment variables, the recommended client instantiation is as follows:

client_qobuz = qobuz.PrivateAPI(flow="password", browser=True)
client_spotify = spotify.WebAPI(
    flow="pkce",
    scopes=spotify.WebAPI.get_scopes("all"),
    web_framework="http.server",
)
client_tidal = tidal.PrivateAPI(flow="device_code", browser=True)

See also

See Getting Started for more information about setting up clients with user authentication.

Moving playlists

The general process is to

  1. get information about the tracks in the source playlist,

  2. create a new playlist in the destination service, and

  3. find and add the corresponding tracks to the newly-created playlist.

The challenge often lies in the third step. The tracks in the source playlist may not be available in the destination service or it may be difficult finding the matching track in the destination service, especially if its catalog lookup does not support searching by ISRC or UPC.

The following examples provide barebones implementations of the process above for various service pairs. Additional fine-tuning is likely necessary to handle tracks with complex metadata, such as those with multiple or featured artists, remixes, etc.

From Qobuz

We start with a Qobuz playlist with 5 tracks:

QOBUZ_PLAYLIST_ID = 17865119

We can get the playlist information and the items in the playlist using minim.qobuz.PrivateAPI.get_playlist():

qobuz_playlist = client_qobuz.get_playlist(QOBUZ_PLAYLIST_ID)

To Spotify

First, we create a new playlist on Spotify with the same details as the Qobuz playlist using minim.spotify.WebAPI.create_playlist():

new_spotify_playlist = client_spotify.create_playlist(
    qobuz_playlist["name"],
    description=qobuz_playlist["description"],
    public=qobuz_playlist["is_public"],
    collaborative=qobuz_playlist["is_collaborative"],
)

Then, we get the Spotify tracks equivalent to those in the Qobuz playlist. This is a simple process as Spotify allows looking up tracks by their ISRCs with its best-in-class API:

spotify_track_uris = []
for qobuz_track in qobuz_playlist["tracks"]["items"]:
    spotify_track = client_spotify.search(
        f"isrc:{qobuz_track['isrc']}", type="track", limit=1
    )["items"][0]
    spotify_track_uris.append(f"spotify:track:{spotify_track['id']}")

Finally, we add the tracks to the Spotify playlist using minim.spotify.WebAPI.add_playlist_items():

client_spotify.add_playlist_items(
    new_spotify_playlist["id"], spotify_track_uris
)

To TIDAL

First, we create a new playlist on TIDAL with the same details as the Qobuz playlist using minim.tidal.PrivateAPI.create_playlist():

new_tidal_playlist = client_tidal.create_playlist(
    qobuz_playlist["name"],
    description=qobuz_playlist["description"],
    public=qobuz_playlist["is_public"],
)

Then, we try to find TIDAL tracks equivalent to those in the Qobuz playlist. Unfortunately, TIDAL does not support searching by ISRCs, so we have to look up the tracks using their titles and artists. The TIDAL API does, however, return ISRCs so we can confirm that we have the right tracks before adding them to the TIDAL playlist.

tidal_track_ids = []
for qobuz_track in qobuz_playlist["tracks"]["items"]:
    title = qobuz_track["title"]
    if qobuz_track["version"]:
        title += f" {qobuz_track['version']}"
    tidal_track = client_tidal.search(
        f"{qobuz_track['performer']['name']} {title}", type="track", limit=1
    )["items"][0]
    if qobuz_track["isrc"] == tidal_track["isrc"]:
        tidal_track_ids.append(tidal_track["id"])

Finally, we add the tracks to the TIDAL playlist using minim.tidal.PrivateAPI.add_playlist_items():

client_tidal.add_playlist_items(
    new_tidal_playlist["data"]["uuid"], tidal_track_ids
)

From Spotify

We start with a Spotify playlist with 5 tracks:

SPOTIFY_PLAYLIST_ID = "3rw9qY60CEh6dfJauWdxMh"

We can get the playlist information and the items in the playlist using minim.spotify.WebAPI.get_playlist():

spotify_playlist = client_spotify.get_playlist(SPOTIFY_PLAYLIST_ID)

To Qobuz

First, we create a new playlist on Qobuz with the same details as the Spotify playlist using minim.qobuz.PrivateAPI.create_playlist():

new_qobuz_playlist = client_qobuz.create_playlist(
    spotify_playlist["name"],
    description=spotify_playlist["description"],
    public=spotify_playlist["public"],
    collaborative=spotify_playlist["collaborative"],
)

Then, we get the Qobuz tracks equivalent to those in the Spotify playlist. Thankfully, we can search by ISRC on Qobuz, so we can get the correct Qobuz tracks directly if they are available in the Qobuz catalog:

qobuz_track_ids = []
for spotify_track in spotify_playlist["tracks"]["items"]:
    qobuz_track = client_qobuz.search(
        spotify_track["track"]["external_ids"]["isrc"], limit=1
    )["tracks"]["items"][0]
    qobuz_track_ids.append(qobuz_track["id"])

Finally, we add the tracks to the Qobuz playlist using minim.qobuz.PrivateAPI.add_playlist_tracks():

client_qobuz.add_playlist_tracks(new_qobuz_playlist["id"], qobuz_track_ids)

To TIDAL

First, we create a new playlist on TIDAL with the same details as the Spotify playlist:

new_tidal_playlist = client_tidal.create_playlist(
    spotify_playlist["name"],
    description=spotify_playlist["description"],
    public=spotify_playlist["public"],
)

Then, we try to find TIDAL tracks equivalent to those in the Spotify playlist:

tidal_track_ids = []
for spotify_track in spotify_playlist["tracks"]["items"]:
    tidal_track = client_tidal.search(
        f"{spotify_track['track']['artists'][0]['name']} "
        f"{spotify_track['track']['name']}",
        type="track",
        limit=1,
    )["items"][0]
    if spotify_track["track"]["external_ids"]["isrc"] == tidal_track["isrc"]:
        tidal_track_ids.append(tidal_track["id"])

Finally, we add the tracks to the TIDAL playlist:

client_tidal.add_playlist_items(
    new_tidal_playlist["data"]["uuid"], tidal_track_ids
)

From TIDAL

We start with a TIDAL playlist with 5 tracks:

TIDAL_PLAYLIST_UUID = "40052e73-58d4-4abb-bc1c-abace76d2f15"

We can get the playlist information using minim.tidal.PrivateAPI.get_user_playlist() and the items in the playlist using minim.tidal.PrivateAPI.get_playlist_items():

tidal_playlist = client_tidal.get_user_playlist(TIDAL_PLAYLIST_UUID)
tidal_playlist_items = client_tidal.get_playlist_items(TIDAL_PLAYLIST_UUID)[
    "items"
]

To Qobuz

First, we create a new playlist on Qobuz with the same details as the TIDAL playlist:

new_qobuz_playlist = client_qobuz.create_playlist(
    spotify_playlist["name"],
    description=spotify_playlist["description"],
    public=spotify_playlist["public"],
    collaborative=spotify_playlist["collaborative"],
)

Then, we get the Qobuz tracks equivalent to those in the TIDAL playlist:

qobuz_track_ids = []
for tidal_track in tidal_playlist_items:
    qobuz_track = client_qobuz.search(tidal_track["item"]["isrc"], limit=1)[
        "tracks"
    ]["items"][0]
    qobuz_track_ids.append(qobuz_track["id"])

Finally, we add the tracks to the Qobuz playlist:

client_qobuz.add_playlist_tracks(new_qobuz_playlist["id"], qobuz_track_ids)

To Spotify

First, we create a new playlist on Spotify with the same details as the TIDAL playlist:

new_spotify_playlist = client_spotify.create_playlist(
    qobuz_playlist["name"],
    description=qobuz_playlist["description"],
    public=qobuz_playlist["is_public"],
    collaborative=qobuz_playlist["is_collaborative"],
)

Then, we get the Spotify tracks equivalent to those in the TIDAL playlist:

spotify_track_uris = []
for tidal_track in tidal_playlist_items:
    spotify_track = client_spotify.search(
        f"isrc:{tidal_track['item']['isrc']}", type="track", limit=1
    )["items"][0]
    spotify_track_uris.append(f"spotify:track:{spotify_track['id']}")

Finally, we add the tracks to the Spotify playlist:

client_spotify.add_playlist_items(
    new_spotify_playlist["id"], spotify_track_uris
)

Synchronizing favorites

Synchronizing favorite albums, artists, tracks, etc. across services follows a similar procedure as above; we first get information about the entities in the source service and then try to find the corresponding media or people in the destination service. For albums and tracks, we can search using their UPCs and ISRCs, respectively, when available, or their titles and the main artist names. For artists, we can only search using their names.

Sample implementations for synchronizing albums and artists are available below for various service pairs.

From Qobuz

We start by getting the current user’s favorite albums and artists using minim.qobuz.PrivateAPI.get_favorites():

qobuz_favorites = client_qobuz.get_favorites()
qobuz_favorite_albums = qobuz_favorites["albums"]["items"]
qobuz_favorite_artists = qobuz_favorites["artists"]["items"]

To Spotify

The Spotify Web API supports searching for albums by UPC, but sometimes the UPCs returned by Qobuz do not align with those in the Spotify catalog. In those cases, we can search for the albums using their titles and the main artist names. Then, we select the correct album from the search results by matching the album title, main artists, and number of tracks. Finally, we add the albums to the user’s Spotify library using their Spotify album IDs and minim.spotify.WebAPI.save_albums():

spotify_album_ids = []
for qobuz_album in qobuz_favorite_albums:
    try:
        spotify_album = client_spotify.search(
            f"upc:{qobuz_album['upc'][1:]}", "album"
        )["items"][0]
    except IndexError:
        spotify_albums = client_spotify.search(
            f"{qobuz_album['artist']['name']} {qobuz_album['title']}", "album"
        )["items"]
        for spotify_album in spotify_albums:
            if (
                spotify_album["name"] == qobuz_album["title"]
                and spotify_album["artists"][0]["name"]
                == qobuz_album["artist"]["name"]
                and spotify_album["total_tracks"] == qobuz_album["tracks_count"]
            ):
                break
    spotify_album_ids.append(spotify_album["id"])
client_spotify.save_albums(spotify_album_ids)

For artists, we can search for them using their names and add them to the user’s Spotify library using their Spotify artist IDs and minim.spotify.WebAPI.follow_artists():

spotify_artist_ids = []
for qobuz_artist in qobuz_favorite_artists:
    spotify_artist = client_spotify.search(qobuz_artist["name"], "artist")[
        "items"
    ][0]
    spotify_artist_ids.append(spotify_artist["id"])
client_spotify.follow_people(spotify_artist_ids, "artist")

To TIDAL

The private TIDAL API does not support searching for albums by UPC, so we have to search for them using their titles and the main artist names. Then, we select the correct albums by matching UPCs. Finally, we add the albums to the user’s TIDAL library using their TIDAL album IDs and minim.tidal.PrivateAPI.favorite_albums():

tidal_album_ids = []
for qobuz_album in qobuz_favorite_albums:
    tidal_albums = client_tidal.search(
        f"{qobuz_album['artist']['name']} {qobuz_album['title']}", type="album"
    )["items"]
    for tidal_album in tidal_albums:
        if tidal_album["upc"].lstrip("0") == qobuz_album["upc"].lstrip("0"):
            tidal_album_ids.append(tidal_album["id"])
            break
client_tidal.favorite_albums(tidal_album_ids)

For artists, we can search for them using their names and add them to the user’s TIDAL library using their TIDAL artist IDs and minim.tidal.PrivateAPI.favorite_artists():

tidal_artist_ids = []
for qobuz_artist in qobuz_favorite_artists:
    tidal_artist = client_tidal.search(qobuz_artist["name"], type="artist")[
        "items"
    ][0]
    tidal_artist_ids.append(tidal_artist["id"])
client_tidal.favorite_artists(tidal_artist_ids)

From Spotify

We start by getting the current user’s favorite albums and artists using minim.spotify.WebAPI.get_saved_albums() and minim.spotify.WebAPI.get_followed_artists(), respectively:

spotify_favorite_albums = client_spotify.get_saved_albums()["items"]
spotify_favorite_artists = client_spotify.get_followed_artists()["items"]

To Qobuz

The private Qobuz API does not support searching for albums by UPC, so we have to search for them using their titles and the main artist names. Then, we select the correct albums by matching UPCs or the album title, main artists, and number of tracks. Finally, we add the albums to the user’s Qobuz library using their Qobuz album IDs and minim.qobuz.PrivateAPI.favorite_items():

qobuz_album_ids = []
for spotify_album in spotify_favorite_albums:
    qobuz_albums = client_qobuz.search(
        f"{spotify_album['album']['artists'][0]['name']} "
        f"{spotify_album['album']['name']}"
    )["albums"]["items"]
    for qobuz_album in qobuz_albums:
        if spotify_album["album"]["external_ids"]["upc"].lstrip(
            "0"
        ) == qobuz_albums[0]["upc"].lstrip("0") or (
            spotify_album["album"]["name"] == qobuz_album["title"]
            and spotify_album["album"]["artists"][0]["name"]
            == qobuz_album["artist"]["name"]
            and spotify_album["album"]["tracks"]["total"]
            == qobuz_album["tracks_count"]
        ):
            qobuz_album_ids.append(qobuz_album["id"])
            break
client_qobuz.favorite_items(album_ids=qobuz_album_ids)

For artists, we can search for them using their names and add them to the user’s Qobuz library using their Qobuz artist IDs and minim.qobuz.PrivateAPI.favorite_items():

qobuz_artist_ids = []
for spotify_artist in spotify_favorite_artists:
    qobuz_artist = client_qobuz.search(spotify_artist["name"])["artists"][
        "items"
    ][0]
    qobuz_artist_ids.append(qobuz_artist["id"])
client_qobuz.favorite_items(artist_ids=qobuz_artist_ids)

To TIDAL

To search for albums using their titles and the main artist names, select the correct albums by matching UPCs or the album title, main artists, and number of tracks, and add the albums to the user’s TIDAL library,

tidal_album_ids = []
for spotify_album in spotify_favorite_albums:
    tidal_albums = client_tidal.search(
        f"{spotify_album['album']['artists'][0]['name']} "
        f"{spotify_album['album']['name']}",
        type="album",
    )["items"]
    for tidal_album in tidal_albums:
        if tidal_album["upc"].lstrip("0") == spotify_album["album"][
            "external_ids"
        ]["upc"].lstrip("0") or (
            tidal_album["title"] == spotify_album["album"]["name"]
            and tidal_album["artists"][0]["name"]
            == spotify_album["album"]["artists"][0]["name"]
            and tidal_album["numberOfTracks"]
            == spotify_album["album"]["tracks"]["total"]
        ):
            tidal_album_ids.append(tidal_album["id"])
            break
client_tidal.favorite_albums(tidal_album_ids)

To search for artists using their names and add them to the user’s TIDAL library,

tidal_artist_ids = []
for spotify_artist in spotify_favorite_artists:
    tidal_artist = client_tidal.search(spotify_artist["name"], type="artist")[
        "items"
    ][0]
    tidal_artist_ids.append(tidal_artist["id"])
client_tidal.favorite_artists(tidal_artist_ids)

From TIDAL

We start by getting the current user’s favorite albums and artists using minim.tidal.PrivateAPI.get_favorite_albums() and minim.tidal.PrivateAPI.get_favorite_artists(), respectively:

tidal_favorite_albums = client_tidal.get_favorite_albums()["items"]
tidal_favorite_artists = client_tidal.get_favorite_artists()["items"]

To Qobuz

To search for albums using their titles and the main artist names, select the correct albums by matching UPCs or the album title, main artists, and number of tracks, and add the albums to the user’s Qobuz library,

qobuz_album_ids = []
for tidal_album in tidal_favorite_albums:
    qobuz_albums = client_qobuz.search(
        f"{tidal_album['item']['artist']['name']} {tidal_album['item']['title']}"
    )["albums"]["items"]
    for qobuz_album in qobuz_albums:
        if tidal_album["item"]["upc"].lstrip("0") == qobuz_album["upc"].lstrip(
            "0"
        ) or (
            tidal_album["item"]["title"] == qobuz_album["title"]
            and tidal_album["item"]["artist"]["name"]
            == qobuz_album["artist"]["name"]
            and tidal_album["item"]["numberOfTracks"]
            == qobuz_album["tracks_count"]
        ):
            qobuz_album_ids.append(qobuz_album["id"])
            break
client_qobuz.favorite_items(album_ids=qobuz_album_ids)

To search for artists using their names and add them to the user’s Qobuz library,

qobuz_artist_ids = []
for tidal_artist in tidal_favorite_artists:
    qobuz_artist = client_qobuz.search(tidal_artist["item"]["name"])["artists"][
        "items"
    ][0]
    qobuz_artist_ids.append(qobuz_artist["id"])
client_qobuz.favorite_items(artist_ids=qobuz_artist_ids)

To Spotify

To search for albums using their UPCs or titles and the main artist names, select the correct albums by matching the album title, main artists, and number of tracks, and add the albums to the user’s Spotify library,

spotify_album_ids = []
for tidal_album in tidal_favorite_albums:
    try:
        spotify_album = client_spotify.search(
            f"upc:{tidal_album['item']['upc']}", "album"
        )["items"][0]
    except IndexError:
        spotify_albums = client_spotify.search(
            f"{tidal_album['item']['artist']['name']} "
            f"{tidal_album['item']['title']}",
            "album",
        )["items"]
        for spotify_album in spotify_albums:
            if (
                spotify_album["name"] == tidal_album["item"]["title"]
                and spotify_album["artists"][0]["name"]
                == tidal_album["item"]["artist"]["name"]
                and spotify_album["total_tracks"]
                == tidal_album["item"]["numberOfTracks"]
            ):
                break
    spotify_album_ids.append(spotify_album["id"])
client_spotify.save_albums(spotify_album_ids)

To search for artists using their names and add them to the user’s Spotify library,

spotify_artist_ids = []
for tidal_artist in tidal_favorite_artists:
    spotify_artist = client_spotify.search(
        tidal_artist["item"]["name"], "artist"
    )["items"][0]
    spotify_artist_ids.append(spotify_artist["id"])
client_spotify.follow_people(spotify_artist_ids, "artist")