Getting Started#

Installation#

Minim is a Python package and can be installed from source using pip, the package installer for Python.

Note

Minim will be coming to PyPI and conda-forge once the PEP 541 request is resolved!

  1. Grab a copy of the Minim repository:

    git clone https://github.com/bbye98/minim.git
    
  2. Enter the repository directory:

    cd minim
    
  3. Optional: Create a virtual environment to prevent dependency conflicts.

    Conda

    • Create an environment named minim and install the required dependencies using one of the following commands:

      conda create -n minim --file requirements_minimal.txt  # required dependencies only
      conda env create -f environment.yml                    # all dependencies
      
    • Activate the environment:

      conda activate minim
      

    venv

    • Create an environment named minim:

      python -m venv minim
      
    • Activate the environment using one of the following commands:

      source minim/bin/activate        # POSIX: bash or zsh
      minim\Scripts\activate.bat       # Windows: cmd.exe
      minim\Scripts\Activate.ps1       # Windows: PowerShell
      
    • The required dependencies will be installed automatically alongside Minim in the next step. To install all dependencies instead:

      python -m pip install -r requirements.txt
      

    virtualenv

    • Create an environment named minim:

      virtualenv minim
      
    • Activate the environment using one of the following commands:

      source minim/bin/activate        # Linux or macOS
      .\minim\Scripts\activate         # Windows
      
    • The required dependencies will be installed automatically alongside Minim in the next step. To install all dependencies instead:

      python -m pip install -r requirements.txt
      
  4. Install Minim (and required dependencies, if you have not already done so) using pip:

    python -m pip install -e .
    
  5. Try importing Minim in Python:

    python -c "import minim"
    

    If no errors like ModuleNotFoundError: No module named 'minim' are raised, you have successfully installed Minim!

Usage#

Music service APIs#

from minim import itunes, qobuz, spotify, tidal

Currently, clients for iTunes Search API, Qobuz API, Spotify Web API, and TIDAL APIs have been implemented. Other than the iTunes Search API, which does not require client credentials or support user authentication and can be used out of the box, the other APIs have a few additional prerequisite steps before they can be used. If you authenticate via Minim, the tokens and their related information will be cached and updated automatically as they expire and are refreshed.

iTunes Search API (minim.itunes.SearchAPI)#

To use the iTunes Search API, simply create a client by instantiating a minim.itunes.SearchAPI object with no arguments:

client_itunes = itunes.SearchAPI()

Private Qobuz API (minim.qobuz.PrivateAPI)#

If you already have a user authentication token, you can provide it and its accompanying app credentials to the client as keyword arguments auth_token, app_id, and app_secret, respectively, and skip this section.

To use the Qobuz API without user authentication, simply create a client by instantiating a minim.qobuz.PrivateAPI object with no arguments:

client_qobuz = qobuz.PrivateAPI()

To use the Qobuz API with user authentication and get access to all public and protected endpoints, you can pass flow="password" and provide your Qobuz email and password as keyword arguments email and password to the constructor:

client_qobuz = qobuz.PrivateAPI(flow="password", email=<QOBUZ_EMAIL>, password=<QOBUZ_PASSWORD>)

which will authenticate you via a POST request to and retrieve the user authentication token from the Qobuz Web Player, or specify browser=True to have Minim spawn a web browser with the Qobuz Web Player login page:

client_qobuz = qobuz.PrivateAPI(flow="password", browser=True)

which you can use to log in normally.

Private Spotify Lyrics Service (minim.spotify.PrivateLyricsService)#

If you already have a user access token, you can provide it and optionally its accompanying expiry time and sp_dc cookie to the client as keyword arguments access_token, expiry, and sp_dc, respectively, and skip this section.

To use the Spotify Lyrics service,

  1. Launch a web browser and log into the Spotify Web Player.

  2. Find the sp_dc cookie in your web browser’s storage.

    • For Chromium-based browsers, press F12 to open DevTools and navigate to Application > Storage > Cookies > https://open.spotify.com.

    • For Firefox, press Shift + F9 to open Storage Inspector and nagivate to Storage > Cookies > https://open.spotify.com.

  3. Create a client by instantiating a minim.spotify.WebAPI object with the sp_dc cookie as a keyword argument:

    client_spotify_lyrics = spotify.PrivateLyricsService(sp_dc=<SPOTIFY_SP_DC>)
    

    or store the sp_dc cookie as an environment variable SPOTIFY_SP_DC and call the constructor with no arguments:

client_spotify_lyrics = spotify.PrivateLyricsService()

Spotify Web API (minim.spotify.WebAPI)#

If you already have an access token, you can provide it and optionally its accompanying refresh token, expiry time, and client credentials to the client as keyword arguments access_token, refresh_token, expiry, client_id, and client_secret, respectively, and skip this section.

First, register a Spotify application here and grab its client credentials. For the redirect URI, use http://localhost:8888/callback. You can replace 8888 with an open port of your choice, but you will need to pass port=<SPOTIFY_PORT> when you create a client.

To use the Spotify Web API without user authentication, you can provide the client credentials as keyword arguments client_id and client_secret to the constructor:

client_spotify = spotify.WebAPI(client_id=<SPOTIFY_CLIENT_ID>, 
                                client_secret=<SPOTIFY_CLIENT_SECRET>)

or store the client credentials as environment variables SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET and call the constructor with no arguments:

client_spotify = spotify.WebAPI()

To use the Spotify Web API with user authentication,

  1. Get the necessary authorization scopes using spotify.WebAPI.get_scopes():

scopes = spotify.WebAPI.get_scopes("all")
  1. Create a client with flow="pkce", the client credentials in client_id and client_secret, the authorization scopes in scopes, and optionally framework="http.server" to automate the authorization code retrieval process:

    client_spotify = spotify.WebAPI(client_id=<SPOTIFY_CLIENT_ID>, 
                                    client_secret=<SPOTIFY_CLIENT_SECRET>,
                                    flow="pkce", scopes=scopes, framework="http.server")
    
  2. If framework=None, open the authorization URL in a web browser.

  3. Log into your Spotify account and authorize Minim by clicking Agree.

  4. If framework=None, copy and paste the redirect URI into the prompt.

TIDAL API (minim.tidal.API)#

If you already have a client-only access token, you can provide it and optionally its accompanying refresh token, expiry time, and client credentials to the client as keyword arguments access_token, refresh_token, expiry, client_id, and client_secret, respectively, and skip this section.

First, register a TIDAL application here and jot down the client credentials.

To use the TIDAL API, you can provide the client credentials as keyword arguments client_id and client_secret to the minim.tidal.API constructor:

client_tidal = tidal.API(client_id=<TIDAL_CLIENT_ID>, client_secret=<TIDAL_CLIENT_SECRET>)

or store the client credentials as environment variables TIDAL_CLIENT_ID and TIDAL_CLIENT_SECRET and create a client with no arguments:

client_tidal = tidal.API()

Private TIDAL API (minim.tidal.PrivateAPI)#

If you already have an access token, you can provide it and optionally its accompanying refresh token, expiry time, and client credentials to the client as keyword arguments access_token, refresh_token, expiry, client_id, and client_secret, respectively, and skip this section.

To use the TIDAL API without user authentication, simply create a client by instantiating a minim.tidal.PrivateAPI object with no arguments:

client_tidal_private = tidal.PrivateAPI()

To use the TIDAL API with user authentication,

  1. Get client credentials from the TIDAL Web Player or the Android, iOS, macOS, and Windows applications by using a web debugging proxy tool to intercept web traffic.

  2. Create a client with the client credentials in client_id and client_secret and optionally browser=True to automatically open a web browser for the authorization flow. Use the authorization code with PKCE flow:

    client_tidal_private = tidal.PrivateAPI(client_id=<TIDAL_CLIENT_ID>, 
                                            client_secret=<TIDAL_CLIENT_SECRET>,
                                            flow="pkce", browser=True)
    

    if you obtained client credentials from the TIDAL Web Player or the desktop applications, or the device code flow:

    client_tidal_private = tidal.PrivateAPI(client_id=<TIDAL_CLIENT_ID>, 
                                            client_secret=<TIDAL_CLIENT_SECRET>,
                                            flow="device", browser=True)
    

    if you obtained client credentials from the Android or iOS applications.

  3. Follow the instructions in the console (browser=False) or the web browser (browser=True) to log into your TIDAL account and authorize Minim.

Examples#

Searching for artists#

Each of the APIs has a search() method that can be used to search for and retrieve information about an artist, such as the EDM group Galantis:

iTunes Search API#
client_itunes.search("Galantis", entity="musicArtist", limit=1)["results"][0]
Hide code cell output
{'wrapperType': 'artist',
 'artistType': 'Artist',
 'artistName': 'Galantis',
 'artistLinkUrl': 'https://music.apple.com/us/artist/galantis/543322169?uo=4',
 'artistId': 543322169,
 'amgArtistId': 2616267,
 'primaryGenreName': 'Dance',
 'primaryGenreId': 17}
Private Qobuz API#
client_qobuz.search("Galantis", limit=1, strict=True)["artists"]["items"][0]
Hide code cell output
{'picture': 'https://static.qobuz.com/images/artists/covers/small/8dcf30e5c8e30281ecbb13b0886426c8.jpg',
 'image': {'small': 'https://static.qobuz.com/images/artists/covers/small/8dcf30e5c8e30281ecbb13b0886426c8.jpg',
  'medium': 'https://static.qobuz.com/images/artists/covers/medium/8dcf30e5c8e30281ecbb13b0886426c8.jpg',
  'large': 'https://static.qobuz.com/images/artists/covers/large/8dcf30e5c8e30281ecbb13b0886426c8.jpg',
  'extralarge': 'https://static.qobuz.com/images/artists/covers/large/8dcf30e5c8e30281ecbb13b0886426c8.jpg',
  'mega': 'https://static.qobuz.com/images/artists/covers/large/8dcf30e5c8e30281ecbb13b0886426c8.jpg'},
 'name': 'Galantis',
 'slug': 'galantis',
 'albums_count': 126,
 'id': 865362}
Spotify Web API#
client_spotify.search("Galantis", "artist", limit=1)["items"][0]
Hide code cell output
{'external_urls': {'spotify': 'https://open.spotify.com/artist/4sTQVOfp9vEMCemLw50sbu'},
 'followers': {'href': None, 'total': 3313284},
 'genres': ['dance pop', 'edm', 'pop', 'pop dance'],
 'href': 'https://api.spotify.com/v1/artists/4sTQVOfp9vEMCemLw50sbu',
 'id': '4sTQVOfp9vEMCemLw50sbu',
 'images': [{'height': 640,
   'url': 'https://i.scdn.co/image/ab6761610000e5eb7bda087d6fb48d481efd3344',
   'width': 640},
  {'height': 320,
   'url': 'https://i.scdn.co/image/ab676161000051747bda087d6fb48d481efd3344',
   'width': 320},
  {'height': 160,
   'url': 'https://i.scdn.co/image/ab6761610000f1787bda087d6fb48d481efd3344',
   'width': 160}],
 'name': 'Galantis',
 'popularity': 71,
 'type': 'artist',
 'uri': 'spotify:artist:4sTQVOfp9vEMCemLw50sbu'}
TIDAL API#
client_tidal.search("Galantis", "US", type="ARTISTS", limit=1)["artists"][0]
Hide code cell output
{'resource': {'id': '4676988',
  'name': 'Galantis',
  'picture': [{'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/1024x256.jpg',
    'width': 1024,
    'height': 256},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/1080x720.jpg',
    'width': 1080,
    'height': 720},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/160x107.jpg',
    'width': 160,
    'height': 107},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/160x160.jpg',
    'width': 160,
    'height': 160},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/320x214.jpg',
    'width': 320,
    'height': 214},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/320x320.jpg',
    'width': 320,
    'height': 320},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/480x480.jpg',
    'width': 480,
    'height': 480},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/640x428.jpg',
    'width': 640,
    'height': 428},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/750x500.jpg',
    'width': 750,
    'height': 500},
   {'url': 'https://resources.tidal.com/images/a627e21c/60f7/4e90/b2bb/e50b178c4f0b/750x750.jpg',
    'width': 750,
    'height': 750}],
  'tidalUrl': 'https://tidal.com/browse/artist/4676988'},
 'id': '4676988',
 'status': 200,
 'message': 'success'}
Private TIDAL API#
client_tidal_private.search("Galantis", type="artist", limit=1)["items"][0]
Hide code cell output
{'id': 4676988,
 'name': 'Galantis',
 'artistTypes': ['ARTIST', 'CONTRIBUTOR'],
 'url': 'http://www.tidal.com/artist/4676988',
 'picture': 'a627e21c-60f7-4e90-b2bb-e50b178c4f0b',
 'popularity': 72,
 'artistRoles': [{'categoryId': -1, 'category': 'Artist'},
  {'categoryId': 11, 'category': 'Performer'},
  {'categoryId': 3, 'category': 'Engineer'},
  {'categoryId': 10, 'category': 'Production team'},
  {'categoryId': 1, 'category': 'Producer'},
  {'categoryId': 2, 'category': 'Songwriter'}],
 'mixes': {'ARTIST_MIX': '000202a7e72fd90d0c0df2ed56ddea'}}
Searching for tracks#

The search() methods can also be used to search for and retrieve information about a track, such as “Everybody Talks” by Neon Trees:

iTunes Search API#
client_itunes.search("Everybody Talks", media="music", limit=1)["results"][0]
Hide code cell output
{'wrapperType': 'track',
 'kind': 'song',
 'artistId': 350172836,
 'collectionId': 1443469527,
 'trackId': 1443469581,
 'artistName': 'Neon Trees',
 'collectionName': 'Picture Show',
 'trackName': 'Everybody Talks',
 'collectionCensoredName': 'Picture Show',
 'trackCensoredName': 'Everybody Talks',
 'artistViewUrl': 'https://music.apple.com/us/artist/neon-trees/350172836?uo=4',
 'collectionViewUrl': 'https://music.apple.com/us/album/everybody-talks/1443469527?i=1443469581&uo=4',
 'trackViewUrl': 'https://music.apple.com/us/album/everybody-talks/1443469527?i=1443469581&uo=4',
 'previewUrl': 'https://audio-ssl.itunes.apple.com/itunes-assets/AudioPreview122/v4/5c/29/bf/5c29bf6b-ca2c-4e8b-2be6-c51a282c7dae/mzaf_1255557534804450018.plus.aac.p.m4a',
 'artworkUrl30': 'https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/80/e3/95/80e39565-35f9-2496-c6f8-6572490c4a7b/12UMGIM12509.rgb.jpg/30x30bb.jpg',
 'artworkUrl60': 'https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/80/e3/95/80e39565-35f9-2496-c6f8-6572490c4a7b/12UMGIM12509.rgb.jpg/60x60bb.jpg',
 'artworkUrl100': 'https://is1-ssl.mzstatic.com/image/thumb/Music115/v4/80/e3/95/80e39565-35f9-2496-c6f8-6572490c4a7b/12UMGIM12509.rgb.jpg/100x100bb.jpg',
 'collectionPrice': 6.99,
 'trackPrice': 1.29,
 'releaseDate': '2011-12-19T12:00:00Z',
 'collectionExplicitness': 'explicit',
 'trackExplicitness': 'explicit',
 'discCount': 1,
 'discNumber': 1,
 'trackCount': 12,
 'trackNumber': 3,
 'trackTimeMillis': 177280,
 'country': 'USA',
 'currency': 'USD',
 'primaryGenreName': 'Alternative',
 'contentAdvisoryRating': 'Explicit',
 'isStreamable': True}
Private Qobuz API#
track_qobuz = client_qobuz.search("Everybody Talks", "ReleaseName", limit=1, 
                                  strict=True)["tracks"]["items"][0]
track_qobuz
Hide code cell output
{'maximum_bit_depth': 16,
 'copyright': '2022 Arko Boom 2022 Arko Boom',
 'performers': 'Arko Boom, MainArtist - Arkos Todd, Songwriter, ComposerLyricist',
 'audio_info': {'replaygain_track_peak': 1, 'replaygain_track_gain': -3.06},
 'performer': {'name': 'Arko Boom', 'id': 15899504},
 'album': {'image': {'small': 'https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_230.jpg',
   'thumbnail': 'https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_50.jpg',
   'large': 'https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_600.jpg'},
  'maximum_bit_depth': 16,
  'media_count': 1,
  'artist': {'image': None,
   'name': 'Arko Boom',
   'id': 15899504,
   'albums_count': 0,
   'slug': 'arko-boom',
   'picture': None},
  'upc': '0859766309663',
  'released_at': 1665180000,
  'label': {'name': 'Arko Boom',
   'id': 4026379,
   'albums_count': 1,
   'supplier_id': 95,
   'slug': 'arko-boom'},
  'title': 'Speedy',
  'qobuz_id': 178369185,
  'version': None,
  'duration': 536,
  'parental_warning': False,
  'tracks_count': 4,
  'popularity': 0,
  'genre': {'path': [133],
   'color': '#0070ef',
   'name': 'Hip-Hop/Rap',
   'id': 133,
   'slug': 'rap-hip-hop'},
  'maximum_channel_count': 2,
  'id': 'ilfmuz10e7vfc',
  'maximum_sampling_rate': 44.1,
  'previewable': True,
  'sampleable': True,
  'displayable': True,
  'streamable': True,
  'streamable_at': 1689231600,
  'downloadable': False,
  'purchasable_at': None,
  'purchasable': False,
  'release_date_original': '2022-10-08',
  'release_date_download': '2022-10-08',
  'release_date_stream': '2022-10-08',
  'release_date_purchase': '2022-10-08',
  'hires': False,
  'hires_streamable': False},
 'work': None,
 'composer': {'name': 'Arkos Todd', 'id': 15899505},
 'isrc': 'TCAGM2280786',
 'title': 'Everybody Talks',
 'version': None,
 'duration': 127,
 'parental_warning': False,
 'track_number': 2,
 'maximum_channel_count': 2,
 'id': 178369187,
 'media_number': 1,
 'maximum_sampling_rate': 44.1,
 'release_date_original': '2022-10-08',
 'release_date_download': '2022-10-08',
 'release_date_stream': '2022-10-08',
 'release_date_purchase': '2022-10-08',
 'purchasable': True,
 'streamable': True,
 'previewable': True,
 'sampleable': True,
 'downloadable': True,
 'displayable': True,
 'purchasable_at': 1689231600,
 'streamable_at': 1689231600,
 'hires': False,
 'hires_streamable': False}
Spotify Web API#
track_spotify = client_spotify.search("Everybody Talks", "track", 
                                      limit=1)["items"][0]
track_spotify
Hide code cell output
{'album': {'album_type': 'single',
  'artists': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/2p4FqHnazRucYQHyDCdBrJ'},
    'href': 'https://api.spotify.com/v1/artists/2p4FqHnazRucYQHyDCdBrJ',
    'id': '2p4FqHnazRucYQHyDCdBrJ',
    'name': 'Simple Plan',
    'type': 'artist',
    'uri': 'spotify:artist:2p4FqHnazRucYQHyDCdBrJ'}],
  'available_markets': ['AR',
   'AU',
   'AT',
   'BE',
   'BO',
   'BR',
   'BG',
   'CA',
   'CL',
   'CO',
   'CR',
   'CY',
   'CZ',
   'DK',
   'DO',
   'DE',
   'EC',
   'EE',
   'SV',
   'FI',
   'FR',
   'GR',
   'GT',
   'HN',
   'HK',
   'HU',
   'IS',
   'IE',
   'IT',
   'LV',
   'LT',
   'LU',
   'MY',
   'MT',
   'MX',
   'NL',
   'NZ',
   'NI',
   'NO',
   'PA',
   'PY',
   'PE',
   'PH',
   'PL',
   'PT',
   'SG',
   'SK',
   'ES',
   'SE',
   'CH',
   'TW',
   'TR',
   'UY',
   'US',
   'GB',
   'AD',
   'LI',
   'MC',
   'ID',
   'JP',
   'TH',
   'VN',
   'RO',
   'IL',
   'ZA',
   'SA',
   'AE',
   'BH',
   'QA',
   'OM',
   'KW',
   'EG',
   'MA',
   'DZ',
   'TN',
   'LB',
   'JO',
   'PS',
   'IN',
   'BY',
   'KZ',
   'MD',
   'UA',
   'AL',
   'BA',
   'HR',
   'ME',
   'MK',
   'RS',
   'SI',
   'KR',
   'BD',
   'PK',
   'LK',
   'GH',
   'KE',
   'NG',
   'TZ',
   'UG',
   'AG',
   'AM',
   'BS',
   'BB',
   'BZ',
   'BT',
   'BW',
   'BF',
   'CV',
   'CW',
   'DM',
   'FJ',
   'GM',
   'GE',
   'GD',
   'GW',
   'GY',
   'HT',
   'JM',
   'KI',
   'LS',
   'LR',
   'MW',
   'MV',
   'ML',
   'MH',
   'FM',
   'NA',
   'NR',
   'NE',
   'PW',
   'PG',
   'WS',
   'SM',
   'ST',
   'SN',
   'SC',
   'SL',
   'SB',
   'KN',
   'LC',
   'VC',
   'SR',
   'TL',
   'TO',
   'TT',
   'TV',
   'VU',
   'AZ',
   'BN',
   'BI',
   'KH',
   'CM',
   'TD',
   'KM',
   'GQ',
   'SZ',
   'GA',
   'GN',
   'KG',
   'LA',
   'MO',
   'MR',
   'MN',
   'NP',
   'RW',
   'TG',
   'UZ',
   'ZW',
   'BJ',
   'MG',
   'MU',
   'MZ',
   'AO',
   'CI',
   'DJ',
   'ZM',
   'CD',
   'CG',
   'IQ',
   'LY',
   'TJ',
   'VE',
   'ET',
   'XK'],
  'external_urls': {'spotify': 'https://open.spotify.com/album/0FYXzgvAXjFLt3qlMSjgnm'},
  'href': 'https://api.spotify.com/v1/albums/0FYXzgvAXjFLt3qlMSjgnm',
  'id': '0FYXzgvAXjFLt3qlMSjgnm',
  'images': [{'height': 640,
    'url': 'https://i.scdn.co/image/ab67616d0000b2732ca4b19368b5685180eba2cc',
    'width': 640},
   {'height': 300,
    'url': 'https://i.scdn.co/image/ab67616d00001e022ca4b19368b5685180eba2cc',
    'width': 300},
   {'height': 64,
    'url': 'https://i.scdn.co/image/ab67616d000048512ca4b19368b5685180eba2cc',
    'width': 64}],
  'name': 'Summer Paradise (feat. MKTO)',
  'release_date': '2013-05-28',
  'release_date_precision': 'day',
  'total_tracks': 1,
  'type': 'album',
  'uri': 'spotify:album:0FYXzgvAXjFLt3qlMSjgnm'},
 'artists': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/2p4FqHnazRucYQHyDCdBrJ'},
   'href': 'https://api.spotify.com/v1/artists/2p4FqHnazRucYQHyDCdBrJ',
   'id': '2p4FqHnazRucYQHyDCdBrJ',
   'name': 'Simple Plan',
   'type': 'artist',
   'uri': 'spotify:artist:2p4FqHnazRucYQHyDCdBrJ'},
  {'external_urls': {'spotify': 'https://open.spotify.com/artist/2l35CQqtYRh3d8ZIiBep4v'},
   'href': 'https://api.spotify.com/v1/artists/2l35CQqtYRh3d8ZIiBep4v',
   'id': '2l35CQqtYRh3d8ZIiBep4v',
   'name': 'MKTO',
   'type': 'artist',
   'uri': 'spotify:artist:2l35CQqtYRh3d8ZIiBep4v'}],
 'available_markets': ['AR',
  'AU',
  'AT',
  'BE',
  'BO',
  'BR',
  'BG',
  'CA',
  'CL',
  'CO',
  'CR',
  'CY',
  'CZ',
  'DK',
  'DO',
  'DE',
  'EC',
  'EE',
  'SV',
  'FI',
  'FR',
  'GR',
  'GT',
  'HN',
  'HK',
  'HU',
  'IS',
  'IE',
  'IT',
  'LV',
  'LT',
  'LU',
  'MY',
  'MT',
  'MX',
  'NL',
  'NZ',
  'NI',
  'NO',
  'PA',
  'PY',
  'PE',
  'PH',
  'PL',
  'PT',
  'SG',
  'SK',
  'ES',
  'SE',
  'CH',
  'TW',
  'TR',
  'UY',
  'US',
  'GB',
  'AD',
  'LI',
  'MC',
  'ID',
  'JP',
  'TH',
  'VN',
  'RO',
  'IL',
  'ZA',
  'SA',
  'AE',
  'BH',
  'QA',
  'OM',
  'KW',
  'EG',
  'MA',
  'DZ',
  'TN',
  'LB',
  'JO',
  'PS',
  'IN',
  'BY',
  'KZ',
  'MD',
  'UA',
  'AL',
  'BA',
  'HR',
  'ME',
  'MK',
  'RS',
  'SI',
  'KR',
  'BD',
  'PK',
  'LK',
  'GH',
  'KE',
  'NG',
  'TZ',
  'UG',
  'AG',
  'AM',
  'BS',
  'BB',
  'BZ',
  'BT',
  'BW',
  'BF',
  'CV',
  'CW',
  'DM',
  'FJ',
  'GM',
  'GE',
  'GD',
  'GW',
  'GY',
  'HT',
  'JM',
  'KI',
  'LS',
  'LR',
  'MW',
  'MV',
  'ML',
  'MH',
  'FM',
  'NA',
  'NR',
  'NE',
  'PW',
  'PG',
  'WS',
  'SM',
  'ST',
  'SN',
  'SC',
  'SL',
  'SB',
  'KN',
  'LC',
  'VC',
  'SR',
  'TL',
  'TO',
  'TT',
  'TV',
  'VU',
  'AZ',
  'BN',
  'BI',
  'KH',
  'CM',
  'TD',
  'KM',
  'GQ',
  'SZ',
  'GA',
  'GN',
  'KG',
  'LA',
  'MO',
  'MR',
  'MN',
  'NP',
  'RW',
  'TG',
  'UZ',
  'ZW',
  'BJ',
  'MG',
  'MU',
  'MZ',
  'AO',
  'CI',
  'DJ',
  'ZM',
  'CD',
  'CG',
  'IQ',
  'LY',
  'TJ',
  'VE',
  'ET',
  'XK'],
 'disc_number': 1,
 'duration_ms': 233578,
 'explicit': False,
 'external_ids': {'isrc': 'USAT21301442'},
 'external_urls': {'spotify': 'https://open.spotify.com/track/56fljzsnWxuCp70LBsMuPD'},
 'href': 'https://api.spotify.com/v1/tracks/56fljzsnWxuCp70LBsMuPD',
 'id': '56fljzsnWxuCp70LBsMuPD',
 'is_local': False,
 'name': 'Summer Paradise (feat. MKTO) - Single Version',
 'popularity': 50,
 'preview_url': 'https://p.scdn.co/mp3-preview/7aa533eb72f82503c6443d7d78f7b892482041bc?cid=01697952269c49b0bd33af2cf4e2e1e1',
 'track_number': 1,
 'type': 'track',
 'uri': 'spotify:track:56fljzsnWxuCp70LBsMuPD'}
TIDAL API#
client_tidal.search("Everybody Talks", "US", type="TRACKS", limit=1)["tracks"][0]
Hide code cell output
{'resource': {'artifactType': 'track',
  'id': '14492425',
  'title': 'Everybody Talks',
  'artists': [{'id': '3665225',
    'name': 'Neon Trees',
    'picture': [{'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/1024x256.jpg',
      'width': 1024,
      'height': 256},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/1080x720.jpg',
      'width': 1080,
      'height': 720},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/160x107.jpg',
      'width': 160,
      'height': 107},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/160x160.jpg',
      'width': 160,
      'height': 160},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/320x214.jpg',
      'width': 320,
      'height': 214},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/320x320.jpg',
      'width': 320,
      'height': 320},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/480x480.jpg',
      'width': 480,
      'height': 480},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/640x428.jpg',
      'width': 640,
      'height': 428},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/750x500.jpg',
      'width': 750,
      'height': 500},
     {'url': 'https://resources.tidal.com/images/e6f17398/759e/45a0/9673/6ded6811e199/750x750.jpg',
      'width': 750,
      'height': 750}],
    'main': True}],
  'album': {'id': '14492422',
   'title': 'Picture Show',
   'imageCover': [{'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/1080x1080.jpg',
     'width': 1080,
     'height': 1080},
    {'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/1280x1280.jpg',
     'width': 1280,
     'height': 1280},
    {'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/160x160.jpg',
     'width': 160,
     'height': 160},
    {'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/320x320.jpg',
     'width': 320,
     'height': 320},
    {'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/640x640.jpg',
     'width': 640,
     'height': 640},
    {'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/750x750.jpg',
     'width': 750,
     'height': 750},
    {'url': 'https://resources.tidal.com/images/1c2d7c90/034e/485a/be1f/24a669c7e6ee/80x80.jpg',
     'width': 80,
     'height': 80}],
   'videoCover': []},
  'duration': 177,
  'trackNumber': 3,
  'volumeNumber': 1,
  'isrc': 'USUM71119189',
  'copyright': 'A Mercury Records Release; ℗ 2011 UMG Recordings, Inc.',
  'mediaMetadata': {'tags': ['LOSSLESS']},
  'properties': {'content': ['explicit']},
  'tidalUrl': 'https://tidal.com/browse/track/14492425'},
 'id': '14492425',
 'status': 200,
 'message': 'success'}
Private TIDAL API#
track_tidal_private = client_tidal_private.search("Everybody Talks", 
                                                  type="track", 
                                                  limit=1)["items"][0]
track_tidal_private
Hide code cell output
{'id': 14492425,
 'title': 'Everybody Talks',
 'duration': 177,
 'replayGain': -11.7,
 'peak': 0.999969,
 'allowStreaming': True,
 'streamReady': True,
 'adSupportedStreamReady': True,
 'djReady': True,
 'stemReady': False,
 'streamStartDate': '2012-04-17T00:00:00.000+0000',
 'premiumStreamingOnly': False,
 'trackNumber': 3,
 'volumeNumber': 1,
 'version': None,
 'popularity': 55,
 'copyright': 'A Mercury Records Release; ℗ 2011 UMG Recordings, Inc.',
 'url': 'http://www.tidal.com/track/14492425',
 'isrc': 'USUM71119189',
 'editable': False,
 'explicit': True,
 'audioQuality': 'LOSSLESS',
 'audioModes': ['STEREO'],
 'mediaMetadata': {'tags': ['LOSSLESS']},
 'artist': {'id': 3665225,
  'name': 'Neon Trees',
  'type': 'MAIN',
  'picture': 'e6f17398-759e-45a0-9673-6ded6811e199'},
 'artists': [{'id': 3665225,
   'name': 'Neon Trees',
   'type': 'MAIN',
   'picture': 'e6f17398-759e-45a0-9673-6ded6811e199'}],
 'album': {'id': 14492422,
  'title': 'Picture Show',
  'cover': '1c2d7c90-034e-485a-be1f-24a669c7e6ee',
  'vibrantColor': '#f8af88',
  'videoCover': None},
 'mixes': {'TRACK_MIX': '0019768c833a193c29829e5bf473fc'}}
Creating, modifying, and deleting a personal playlist#

If the clients are authenticated, you can create and modify user playlists. As an example, we will create a private playlist named “Minim”, make it public, add “Everybody Talks” by Neon Trees to it, and then delete it.

Private Qobuz API#
playlist_qobuz = client_qobuz.create_playlist(
    "Minim", 
    description="A playlist created using Minim.",
    public=False
)
client_qobuz.update_playlist(playlist_qobuz["id"], public=True)
client_qobuz.add_playlist_tracks(playlist_qobuz["id"], track_qobuz["id"])
playlist_qobuz = client_qobuz.get_playlist(playlist_qobuz["id"])
playlist_qobuz["owner"] = None  # remove personal identifying information
playlist_qobuz
Hide code cell output
{'owner': None,
 'users_count': 0,
 'images150': ['https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_150.jpg'],
 'images': ['https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_50.jpg'],
 'is_collaborative': False,
 'description': 'A playlist created using Minim.',
 'created_at': 1709932746,
 'images300': ['https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_300.jpg'],
 'duration': 127,
 'updated_at': 1709932747,
 'published_to': None,
 'genres': [],
 'tracks_count': 1,
 'public_at': 1709932747,
 'name': 'Minim',
 'is_public': True,
 'published_from': None,
 'id': 20129861,
 'slug': 'minim',
 'is_featured': False,
 'tracks': {'offset': 0,
  'limit': 50,
  'total': 1,
  'items': [{'maximum_bit_depth': 16,
    'copyright': '2022 Arko Boom 2022 Arko Boom',
    'performers': 'Arko Boom, MainArtist - Arkos Todd, Songwriter, ComposerLyricist',
    'audio_info': {'replaygain_track_peak': 1, 'replaygain_track_gain': -3.06},
    'performer': {'name': 'Arko Boom', 'id': 15899504},
    'album': {'image': {'small': 'https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_230.jpg',
      'thumbnail': 'https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_50.jpg',
      'large': 'https://static.qobuz.com/images/covers/fc/7v/ilfmuz10e7vfc_600.jpg'},
     'maximum_bit_depth': 16,
     'media_count': 1,
     'artist': {'image': None,
      'name': 'Arko Boom',
      'id': 15899504,
      'albums_count': 0,
      'slug': 'arko-boom',
      'picture': None},
     'upc': '0859766309663',
     'released_at': 1665180000,
     'label': {'name': 'Arko Boom',
      'id': 4026379,
      'albums_count': 1,
      'supplier_id': 95,
      'slug': 'arko-boom'},
     'title': 'Speedy',
     'qobuz_id': 178369185,
     'version': None,
     'duration': 536,
     'parental_warning': False,
     'tracks_count': 4,
     'popularity': 0,
     'genre': {'path': [133],
      'color': '#0070ef',
      'name': 'Hip-Hop/Rap',
      'id': 133,
      'slug': 'rap-hip-hop'},
     'maximum_channel_count': 2,
     'id': 'ilfmuz10e7vfc',
     'maximum_sampling_rate': 44.1,
     'previewable': True,
     'sampleable': True,
     'displayable': True,
     'streamable': True,
     'streamable_at': 1689231600,
     'downloadable': False,
     'purchasable_at': None,
     'purchasable': False,
     'release_date_original': '2022-10-08',
     'release_date_download': '2022-10-08',
     'release_date_stream': '2022-10-08',
     'release_date_purchase': '2022-10-08',
     'hires': False,
     'hires_streamable': False},
    'work': None,
    'composer': {'name': 'Arkos Todd', 'id': 15899505},
    'isrc': 'TCAGM2280786',
    'title': 'Everybody Talks',
    'version': None,
    'duration': 127,
    'parental_warning': False,
    'track_number': 2,
    'maximum_channel_count': 2,
    'id': 178369187,
    'media_number': 1,
    'maximum_sampling_rate': 44.1,
    'release_date_original': '2022-10-08',
    'release_date_download': '2022-10-08',
    'release_date_stream': '2022-10-08',
    'release_date_purchase': '2022-10-08',
    'purchasable': True,
    'streamable': True,
    'previewable': True,
    'sampleable': True,
    'downloadable': True,
    'displayable': True,
    'purchasable_at': 1689231600,
    'streamable_at': 1689231600,
    'hires': False,
    'hires_streamable': False,
    'position': 1,
    'created_at': 1709932747,
    'playlist_track_id': 4380248914}]}}
client_qobuz.delete_playlist(playlist_qobuz["id"])
Spotify Web API#
playlist_spotify = client_spotify.create_playlist(
    "Minim", 
    description="A playlist created using Minim.",
    public=False
)
client_spotify.change_playlist_details(playlist_spotify["id"], public=True)
client_spotify.add_playlist_items(playlist_spotify["id"], 
                                  [f"spotify:track:{track_spotify['id']}"])
playlist_spotify = client_spotify.get_playlist(playlist_spotify["id"])
# remove personal identifying information
playlist_spotify["owner"] = playlist_spotify["tracks"]["items"][0]["added_by"] = None
playlist_spotify
Hide code cell output
{'collaborative': False,
 'description': 'A playlist created using Minim.',
 'external_urls': {'spotify': 'https://open.spotify.com/playlist/2RXNjt9HUFnQD8VlVrE1QM'},
 'followers': {'href': None, 'total': 0},
 'href': 'https://api.spotify.com/v1/playlists/2RXNjt9HUFnQD8VlVrE1QM',
 'id': '2RXNjt9HUFnQD8VlVrE1QM',
 'images': [{'height': None,
   'url': 'https://i.scdn.co/image/ab67616d00001e022ca4b19368b5685180eba2cc',
   'width': None}],
 'name': 'Minim',
 'owner': None,
 'primary_color': None,
 'public': True,
 'snapshot_id': 'MSw3OWUwNmUwYTY4ZjRjZjcxMzEyNzA5NDRlMTliMzk5NDZmNTdjMTQ3',
 'tracks': {'href': 'https://api.spotify.com/v1/playlists/2RXNjt9HUFnQD8VlVrE1QM/tracks?offset=0&limit=100',
  'items': [{'added_at': '2024-03-08T21:19:11Z',
    'added_by': None,
    'is_local': False,
    'primary_color': None,
    'track': {'preview_url': 'https://p.scdn.co/mp3-preview/7aa533eb72f82503c6443d7d78f7b892482041bc?cid=01697952269c49b0bd33af2cf4e2e1e1',
     'available_markets': ['AR',
      'AU',
      'AT',
      'BE',
      'BO',
      'BR',
      'BG',
      'CA',
      'CL',
      'CO',
      'CR',
      'CY',
      'CZ',
      'DK',
      'DO',
      'DE',
      'EC',
      'EE',
      'SV',
      'FI',
      'FR',
      'GR',
      'GT',
      'HN',
      'HK',
      'HU',
      'IS',
      'IE',
      'IT',
      'LV',
      'LT',
      'LU',
      'MY',
      'MT',
      'MX',
      'NL',
      'NZ',
      'NI',
      'NO',
      'PA',
      'PY',
      'PE',
      'PH',
      'PL',
      'PT',
      'SG',
      'SK',
      'ES',
      'SE',
      'CH',
      'TW',
      'TR',
      'UY',
      'US',
      'GB',
      'AD',
      'LI',
      'MC',
      'ID',
      'JP',
      'TH',
      'VN',
      'RO',
      'IL',
      'ZA',
      'SA',
      'AE',
      'BH',
      'QA',
      'OM',
      'KW',
      'EG',
      'MA',
      'DZ',
      'TN',
      'LB',
      'JO',
      'PS',
      'IN',
      'BY',
      'KZ',
      'MD',
      'UA',
      'AL',
      'BA',
      'HR',
      'ME',
      'MK',
      'RS',
      'SI',
      'KR',
      'BD',
      'PK',
      'LK',
      'GH',
      'KE',
      'NG',
      'TZ',
      'UG',
      'AG',
      'AM',
      'BS',
      'BB',
      'BZ',
      'BT',
      'BW',
      'BF',
      'CV',
      'CW',
      'DM',
      'FJ',
      'GM',
      'GE',
      'GD',
      'GW',
      'GY',
      'HT',
      'JM',
      'KI',
      'LS',
      'LR',
      'MW',
      'MV',
      'ML',
      'MH',
      'FM',
      'NA',
      'NR',
      'NE',
      'PW',
      'PG',
      'WS',
      'SM',
      'ST',
      'SN',
      'SC',
      'SL',
      'SB',
      'KN',
      'LC',
      'VC',
      'SR',
      'TL',
      'TO',
      'TT',
      'TV',
      'VU',
      'AZ',
      'BN',
      'BI',
      'KH',
      'CM',
      'TD',
      'KM',
      'GQ',
      'SZ',
      'GA',
      'GN',
      'KG',
      'LA',
      'MO',
      'MR',
      'MN',
      'NP',
      'RW',
      'TG',
      'UZ',
      'ZW',
      'BJ',
      'MG',
      'MU',
      'MZ',
      'AO',
      'CI',
      'DJ',
      'ZM',
      'CD',
      'CG',
      'IQ',
      'LY',
      'TJ',
      'VE',
      'ET',
      'XK'],
     'explicit': False,
     'type': 'track',
     'episode': False,
     'track': True,
     'album': {'available_markets': ['AR',
       'AU',
       'AT',
       'BE',
       'BO',
       'BR',
       'BG',
       'CA',
       'CL',
       'CO',
       'CR',
       'CY',
       'CZ',
       'DK',
       'DO',
       'DE',
       'EC',
       'EE',
       'SV',
       'FI',
       'FR',
       'GR',
       'GT',
       'HN',
       'HK',
       'HU',
       'IS',
       'IE',
       'IT',
       'LV',
       'LT',
       'LU',
       'MY',
       'MT',
       'MX',
       'NL',
       'NZ',
       'NI',
       'NO',
       'PA',
       'PY',
       'PE',
       'PH',
       'PL',
       'PT',
       'SG',
       'SK',
       'ES',
       'SE',
       'CH',
       'TW',
       'TR',
       'UY',
       'US',
       'GB',
       'AD',
       'LI',
       'MC',
       'ID',
       'JP',
       'TH',
       'VN',
       'RO',
       'IL',
       'ZA',
       'SA',
       'AE',
       'BH',
       'QA',
       'OM',
       'KW',
       'EG',
       'MA',
       'DZ',
       'TN',
       'LB',
       'JO',
       'PS',
       'IN',
       'BY',
       'KZ',
       'MD',
       'UA',
       'AL',
       'BA',
       'HR',
       'ME',
       'MK',
       'RS',
       'SI',
       'KR',
       'BD',
       'PK',
       'LK',
       'GH',
       'KE',
       'NG',
       'TZ',
       'UG',
       'AG',
       'AM',
       'BS',
       'BB',
       'BZ',
       'BT',
       'BW',
       'BF',
       'CV',
       'CW',
       'DM',
       'FJ',
       'GM',
       'GE',
       'GD',
       'GW',
       'GY',
       'HT',
       'JM',
       'KI',
       'LS',
       'LR',
       'MW',
       'MV',
       'ML',
       'MH',
       'FM',
       'NA',
       'NR',
       'NE',
       'PW',
       'PG',
       'WS',
       'SM',
       'ST',
       'SN',
       'SC',
       'SL',
       'SB',
       'KN',
       'LC',
       'VC',
       'SR',
       'TL',
       'TO',
       'TT',
       'TV',
       'VU',
       'AZ',
       'BN',
       'BI',
       'KH',
       'CM',
       'TD',
       'KM',
       'GQ',
       'SZ',
       'GA',
       'GN',
       'KG',
       'LA',
       'MO',
       'MR',
       'MN',
       'NP',
       'RW',
       'TG',
       'UZ',
       'ZW',
       'BJ',
       'MG',
       'MU',
       'MZ',
       'AO',
       'CI',
       'DJ',
       'ZM',
       'CD',
       'CG',
       'IQ',
       'LY',
       'TJ',
       'VE',
       'ET',
       'XK'],
      'type': 'album',
      'album_type': 'single',
      'href': 'https://api.spotify.com/v1/albums/0FYXzgvAXjFLt3qlMSjgnm',
      'id': '0FYXzgvAXjFLt3qlMSjgnm',
      'images': [{'url': 'https://i.scdn.co/image/ab67616d0000b2732ca4b19368b5685180eba2cc',
        'width': 640,
        'height': 640},
       {'url': 'https://i.scdn.co/image/ab67616d00001e022ca4b19368b5685180eba2cc',
        'width': 300,
        'height': 300},
       {'url': 'https://i.scdn.co/image/ab67616d000048512ca4b19368b5685180eba2cc',
        'width': 64,
        'height': 64}],
      'name': 'Summer Paradise (feat. MKTO)',
      'release_date': '2013-05-28',
      'release_date_precision': 'day',
      'uri': 'spotify:album:0FYXzgvAXjFLt3qlMSjgnm',
      'artists': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/2p4FqHnazRucYQHyDCdBrJ'},
        'href': 'https://api.spotify.com/v1/artists/2p4FqHnazRucYQHyDCdBrJ',
        'id': '2p4FqHnazRucYQHyDCdBrJ',
        'name': 'Simple Plan',
        'type': 'artist',
        'uri': 'spotify:artist:2p4FqHnazRucYQHyDCdBrJ'}],
      'external_urls': {'spotify': 'https://open.spotify.com/album/0FYXzgvAXjFLt3qlMSjgnm'},
      'total_tracks': 1},
     'artists': [{'external_urls': {'spotify': 'https://open.spotify.com/artist/2p4FqHnazRucYQHyDCdBrJ'},
       'href': 'https://api.spotify.com/v1/artists/2p4FqHnazRucYQHyDCdBrJ',
       'id': '2p4FqHnazRucYQHyDCdBrJ',
       'name': 'Simple Plan',
       'type': 'artist',
       'uri': 'spotify:artist:2p4FqHnazRucYQHyDCdBrJ'},
      {'external_urls': {'spotify': 'https://open.spotify.com/artist/2l35CQqtYRh3d8ZIiBep4v'},
       'href': 'https://api.spotify.com/v1/artists/2l35CQqtYRh3d8ZIiBep4v',
       'id': '2l35CQqtYRh3d8ZIiBep4v',
       'name': 'MKTO',
       'type': 'artist',
       'uri': 'spotify:artist:2l35CQqtYRh3d8ZIiBep4v'}],
     'disc_number': 1,
     'track_number': 1,
     'duration_ms': 233578,
     'external_ids': {'isrc': 'USAT21301442'},
     'external_urls': {'spotify': 'https://open.spotify.com/track/56fljzsnWxuCp70LBsMuPD'},
     'href': 'https://api.spotify.com/v1/tracks/56fljzsnWxuCp70LBsMuPD',
     'id': '56fljzsnWxuCp70LBsMuPD',
     'name': 'Summer Paradise (feat. MKTO) - Single Version',
     'popularity': 50,
     'uri': 'spotify:track:56fljzsnWxuCp70LBsMuPD',
     'is_local': False},
    'video_thumbnail': {'url': None}}],
  'limit': 100,
  'next': None,
  'offset': 0,
  'previous': None,
  'total': 1},
 'type': 'playlist',
 'uri': 'spotify:playlist:2RXNjt9HUFnQD8VlVrE1QM'}
client_spotify.unfollow_playlist(playlist_spotify["id"])
Private TIDAL API#
playlist_tidal_private = client_tidal_private.create_playlist(
    "Minim", 
    description="A playlist created using Minim.",
    public=False
)
client_tidal_private.set_playlist_privacy(playlist_tidal_private["data"]["uuid"], 
                                          True)
client_tidal_private.add_playlist_items(playlist_tidal_private["data"]["uuid"], 
                                        track_tidal_private["id"])
playlist_tidal_private = client_tidal_private.get_user_playlist(
    playlist_tidal_private["data"]["uuid"]
)
# remove personal identifying information
playlist_tidal_private["playlist"]["creator"] = playlist_tidal_private["profile"] = None
playlist_tidal_private
Hide code cell output
{'playlist': {'uuid': '31b09bc7-f7af-48ca-b581-dd148ac03942',
  'type': 'USER',
  'creator': None,
  'contentBehavior': 'UNRESTRICTED',
  'sharingLevel': 'PUBLIC',
  'status': 'READY',
  'source': 'DEFAULT',
  'title': 'Minim',
  'description': 'A playlist created using Minim.',
  'image': '7e25d95d-f41b-4ba4-af6c-c6bc5c9f62c3',
  'squareImage': 'd9085c83-800d-4e3d-a4ba-aafe1b943903',
  'url': 'http://www.tidal.com/playlist/31b09bc7-f7af-48ca-b581-dd148ac03942',
  'created': '2024-03-08T21:19:12.140+0000',
  'lastUpdated': '2024-03-08T21:19:12.543+0000',
  'lastItemAddedAt': '2024-03-08T21:19:12.543+0000',
  'duration': 177,
  'numberOfTracks': 1,
  'numberOfVideos': 0,
  'promotedArtists': [],
  'trn': 'trn:playlist:31b09bc7-f7af-48ca-b581-dd148ac03942'},
 'followInfo': {'nrOfFollowers': 0,
  'tidalResourceName': 'trn:playlist:31b09bc7-f7af-48ca-b581-dd148ac03942',
  'followed': True,
  'followType': 'PLAYLIST'},
 'profile': None}
client_tidal_private.delete_playlist(playlist_tidal_private["playlist"]["uuid"])

Audio file handlers#

from pathlib import Path
from minim.audio import Audio, FLACAudio, MP3Audio, MP4Audio, OggAudio, WAVEAudio

Minim uses Mutagen to load and edit audio files and FFmpeg to convert between different audio formats. Currently, the most common audio formats, such as AAC, ALAC, FLAC, MP3, Opus, Vorbis, and WAVE, are supported.

Examples#

Loading and editing audio files#

To load an audio file, pass the filename as a str or a pathlib.Path object either to the minim.audio.Audio constructor for Minim to automatically detect the audio format:

file = Path().resolve().parents[2] / "tests/data/samples/middle_c.wav"
middle_c = Audio(file)

or the specific class for the audio format if known (in this case, minim.audio.WAVEAudio):

middle_c = WAVEAudio(Path().resolve().parents[2] / "tests/data/samples/middle_c.wav")

For this example, both approaches return a minim.audio.WAVEAudio object:

type(middle_c)
minim.audio.WAVEAudio

The metadata stored in the audio file can be accessed using dot notation or getattr():

for attr in ["title", "album", "artist", "genre", "codec", "bit_depth"]:
    print(f"{attr.capitalize().replace('_', ' ')}: {getattr(middle_c, attr)}")
Title: Middle C
Album: Minim
Artist: Square Wave
Genre: Game
Codec: lpcm
Bit depth: 24

and edited similarly using dot notation or setattr():

middle_c.title = "Middle C (261.63 Hz)"
middle_c.write_metadata()

If changes are made, don’t forget to write them to file using minim.audio.Audio.write_metadata().

Converting between audio formats#

Conversion between the supported audio formats is powered by FFmpeg.

To re-encode the previous WAVE audio using the ALAC codec and store it in a MP4 container, use the minim.audio.Audio.convert() method:

middle_c.convert("alac", filename="middle_c_alac")
Hide code cell output
size=     116kB time=00:00:01.02 bitrate= 930.3kbits/s speed=87.5x    

The call above not only converts the WAVE audio into ALAC audio, but also updates the variable middle_c to now point to a minim.audio.MP4Audio file handler for the new file middle_c.m4a and maintains the metadata:

type(middle_c)
minim.audio.MP4Audio
for attr in ["title", "album", "artist", "genre", "codec", "bit_depth"]:
    print(f"{attr.capitalize().replace('_', ' ')}: {getattr(middle_c, attr)}")
Title: Middle C
Album: Minim
Artist: Square Wave
Genre: Game
Codec: alac
Bit depth: 24