change to aigpy and tidalapi
This commit is contained in:
parent
1371b2f88f
commit
307da06b17
6 changed files with 162 additions and 291 deletions
123
tidal_scrape.py
123
tidal_scrape.py
|
@ -1,18 +1,111 @@
|
|||
#!/bin/python3
|
||||
#!/bin/env python
|
||||
import tidalapi
|
||||
import aigpy
|
||||
import aigpy.downloadHelper
|
||||
import json
|
||||
import sys
|
||||
import base64
|
||||
from Crypto.Cipher import AES
|
||||
from Crypto.Util import Counter
|
||||
from typing import Tuple
|
||||
from datetime import datetime
|
||||
|
||||
USER_ID = 188721652
|
||||
DL_PATH = "/home/luca/.cache/tidal_scrape"
|
||||
DEST_PATH = "/home/luca/Music"
|
||||
|
||||
config = tidalapi.Config(quality=tidalapi.Quality.lossless)
|
||||
session = tidalapi.Session(config)
|
||||
|
||||
|
||||
def decrypt_token(token) -> Tuple[bytes, bytes]:
|
||||
master_key = "UIlTTEMmmLfGowo/UC60x2H45W6MdGgTRfo/umg4754="
|
||||
master_key = base64.b64decode(master_key)
|
||||
security_token = base64.b64decode(token)
|
||||
iv = security_token[:16]
|
||||
encrypted_st = security_token[16:]
|
||||
|
||||
decryptor = AES.new(master_key, AES.MODE_CBC, iv)
|
||||
decrypted_st = decryptor.decrypt(encrypted_st)
|
||||
|
||||
key = decrypted_st[:16]
|
||||
nonce = decrypted_st[16:24]
|
||||
|
||||
return key, nonce
|
||||
|
||||
|
||||
def decrypt_file(input_file, output_file, key, nonce) -> None:
|
||||
counter = Counter.new(64, prefix=nonce, initial_value=0)
|
||||
decryptor = AES.new(key, AES.MODE_CTR, counter=counter)
|
||||
|
||||
with open(input_file, "rb") as i:
|
||||
data = decryptor.decrypt(i.read())
|
||||
|
||||
with open(output_file, "wb") as o:
|
||||
o.write(data)
|
||||
|
||||
|
||||
def set_metadata(track: tidalapi.Track, file: str):
|
||||
# This function could be more fleshed out (lyrics, covers) but I will leave that to external programs
|
||||
tagger = aigpy.tag.TagTool(file)
|
||||
|
||||
tagger.title = track.name
|
||||
tagger.artist = list(map(lambda artist: artist.name, track.artists)) # type: ignore[reportOptionalMemberAccess]
|
||||
tagger.copyright = track.copyright
|
||||
tagger.tracknumber = track.track_num
|
||||
tagger.discnumber = track.volume_num
|
||||
|
||||
tagger.album = track.album.name # type: ignore[reportOptionalMemberAccess]
|
||||
tagger.albumartist = list(map(lambda artist: artist.name, track.album.artists)) # type: ignore[reportOptionalMemberAccess]
|
||||
tagger.date = track.album.available_release_date # type: ignore[reportOptionalMemberAccess]
|
||||
tagger.totaldisc = track.album.num_volumes or 0 # type: ignore[reportOptionalMemberAccess]
|
||||
if tagger.totaldisc <= 1:
|
||||
tagger.totaltrack = track.album.num_tracks # type: ignore[reportOptionalMemberAccess]
|
||||
|
||||
tagger.save()
|
||||
|
||||
|
||||
def download_track(
|
||||
track: tidalapi.Track,
|
||||
partSize: int = 1048576,
|
||||
) -> Tuple[bool, str]:
|
||||
try:
|
||||
dl_path = f"{DL_PATH}/{track.album.name}/{track.name}.part" # type: ignore[reportOptionalMemberAccess]
|
||||
dest_path = f"{DEST_PATH}/{track.album.name}/{track.name}" # type: ignore[reportOptionalMemberAccess]
|
||||
|
||||
stream = track.stream()
|
||||
|
||||
stream.manifest = json.loads(base64.b64decode(stream.manifest))
|
||||
url = stream.manifest["urls"][0]
|
||||
try:
|
||||
key = stream.manifest["keyId"]
|
||||
except KeyError:
|
||||
key = None
|
||||
tool = aigpy.downloadHelper.DownloadTool(dl_path, [url])
|
||||
|
||||
tool.setPartSize(partSize)
|
||||
check, err = tool.start(True, 1)
|
||||
if not check:
|
||||
return False, str(err)
|
||||
|
||||
if key:
|
||||
key, nonce = decrypt_token(key)
|
||||
decrypt_file(dl_path, dest_path, key, nonce)
|
||||
|
||||
set_metadata(track, dest_path)
|
||||
|
||||
return True, ""
|
||||
except Exception as err:
|
||||
return False, str(err)
|
||||
|
||||
|
||||
try:
|
||||
with open("auth.json", "rb") as f:
|
||||
a = json.load(f)
|
||||
a.expiry_time = datetime.strptime(a.expiry_time, "%y-%m-%d %H:%M:%S")
|
||||
expiry_time = a["expiry_time"].split(".", 1)[0]
|
||||
expiry_time = datetime.strptime(expiry_time, "%Y-%m-%d %H:%M:%S")
|
||||
session.load_oauth_session(
|
||||
a.token_type, a.access_token, a.refresh_token, a.expiry_time
|
||||
a["token_type"], a["access_token"], a["refresh_token"], expiry_time
|
||||
)
|
||||
except (OSError, IndexError):
|
||||
session.login_oauth_simple()
|
||||
|
@ -24,22 +117,20 @@ if session.check_login():
|
|||
"token_type": session.token_type,
|
||||
"access_token": session.access_token,
|
||||
"refresh_token": session.refresh_token,
|
||||
"expiry_time": session.expiry_time,
|
||||
"expiry_time": str(session.expiry_time),
|
||||
},
|
||||
f,
|
||||
)
|
||||
else:
|
||||
sys.exit("Failed to log in")
|
||||
|
||||
user = session.get_user()
|
||||
# albums = user.Favorites.albums()
|
||||
# tracks = user.Favorites.tracks()
|
||||
# artists = user.Favorites.artists()
|
||||
#
|
||||
# for album in albums:
|
||||
# if album.artist not in artists:
|
||||
# user.Favorites.add_artist(album.artist.id)
|
||||
#
|
||||
# for track in tracks:
|
||||
# if track.album not in albums:
|
||||
# user.Favorites.add_album(track.album.id)
|
||||
|
||||
user = session.get_user(USER_ID)
|
||||
favorites = tidalapi.user.Favorites(session, user.id)
|
||||
tracks = favorites.tracks()
|
||||
|
||||
for track in tracks:
|
||||
print(f"Downloading {track.album.name} by {track.artist}")
|
||||
check, err = download_track(track)
|
||||
if not check:
|
||||
print(err)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue