Created
June 27, 2020 20:06
-
-
Save j0e1in/ccfa48d3e65959e1c760db7552f4f758 to your computer and use it in GitHub Desktop.
Download all albums/tracks of all of your favorite artists on TIDAL.
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
""" Download all albums/tracks of all of your favorite artists on TIDAL. | |
# Usage | |
- Install dependency: `pip install -U tidal-dl` | |
- Create tidal-dl.ini with following content and then fill your username and password | |
``` | |
username = <username> | |
password = <password> | |
countrycode = US | |
outputdir = ./ | |
quality = HI_RES | |
resolution = 1080 | |
threadnum = 3 | |
onlym4a = False | |
showprogress = True | |
addhyphen = True | |
addyear = False | |
``` | |
Note: This configuration requires TIDAL HIFI subscription. If you have premium subscription, | |
change quality to either LOSSLESS or HIGH. See https://yaronzz.top/post/tidal_dl_installation/ | |
- Execute `tidal-dl` command once to fill access token in tidal-dl.ini | |
- Execute this file at the same directory where tidal-dl.ini is located | |
``` | |
python download_tidal_favorite_artists.py | |
``` | |
""" | |
from tidal_dl.download import Download | |
from tidal_dl import tidal | |
from threading import Thread, Lock | |
import json | |
import os | |
import random | |
import time | |
FAV_ARTISTS_FILE = "favorite_artists.json" | |
FORCE_RESTART = False | |
def fetchFavoriteArtists(): | |
config = tidal.TidalConfig() | |
tool = tidal.TidalTool() | |
artists = [] | |
offset = 0 | |
limit = 100 | |
total = 1 | |
while offset < total: | |
fav_artists_url = ( | |
f"users/{config.userid}/favorites/artists?limit={limit}&offset={offset}" | |
) | |
print(f"Fetching << {fav_artists_url} >>") | |
data = tool._get(fav_artists_url) | |
offset = data["offset"] + len(data["items"]) | |
total = data["totalNumberOfItems"] | |
for artist in data["items"]: | |
artists.append( | |
dict( | |
name=artist["item"]["name"], | |
url=artist["item"]["url"], | |
downloaded=False, | |
) | |
) | |
return artists | |
def saveFavoriteArtists(artists): | |
with open(FAV_ARTISTS_FILE, "w") as f: | |
json.dump(artists, f) | |
def loadFavoriteArtists(): | |
if not os.path.exists(FAV_ARTISTS_FILE): | |
return [] | |
with open(FAV_ARTISTS_FILE, "r") as f: | |
return json.load(f) | |
def setArtistDownloadStatus(artist, status): | |
artists = loadFavoriteArtists() | |
for art in artists: | |
if art["url"] == artist["url"]: | |
art["downloaded"] = status | |
saveFavoriteArtists(artists) | |
def restoreStatus(src_artists, dest_artists): | |
artist_index_by_url = {art["url"]: idx for idx, art in enumerate(dest_artists)} | |
for art in src_artists: | |
if art["url"] in artist_index_by_url: | |
idx = artist_index_by_url[art["url"]] | |
dest_artists[idx]["downloaded"] = art.get("downloaded", False) | |
def downlaodArtist(artist): | |
print(f"Start downloading {artist['name']}...") | |
downloader = Download() | |
downloader.downloadUrl(artist["url"]) | |
setArtistDownloadStatus(artist, True) | |
print(f"Finished downloading {artist['name']}...sleep for 100 seconds") | |
time.sleep(100) | |
if __name__ == "__main__": | |
fetched_artists = fetchFavoriteArtists() | |
if not FORCE_RESTART: # restore download status if not to force restart | |
loaded_artists = loadFavoriteArtists() | |
restoreStatus(loaded_artists, fetched_artists) | |
saveFavoriteArtists(fetched_artists) | |
not_downloaded_artists = [ | |
art for art in fetched_artists if art["downloaded"] is False | |
] | |
total = len(fetched_artists) | |
n_downloaded = total - len(not_downloaded_artists) | |
for art in not_downloaded_artists: | |
print( | |
f"Total artists: {total} | Downloaded: {n_downloaded} | Remaining: {total - n_downloaded}" | |
) | |
try: | |
downlaodArtist(art) | |
except Exception as err: | |
# Some tracks may have session invalid issue, and causing | |
# "local variable 'url' referenced before assignment" exception, | |
# need to download them manually | |
print(f"<{art['name']}> Exception: {err}") | |
time.sleep(10) | |
n_downloaded += 1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment