From c103b6b22e1f333c626f976c34f96c0cdefff9b5 Mon Sep 17 00:00:00 2001 From: Michal T Date: Wed, 9 Apr 2025 18:21:37 +0100 Subject: [PATCH] Modified spotipy for auth --- spotify_dl/__init__.py | 6 ++-- spotify_dl/constants.py | 2 +- spotify_dl/spotify.py | 68 ++++++++++++++++++++++++++++++---------- spotify_dl/spotify_dl.py | 2 +- spotify_dl/youtube.py | 22 ++++++------- 5 files changed, 69 insertions(+), 31 deletions(-) diff --git a/spotify_dl/__init__.py b/spotify_dl/__init__.py index 907630e..3de80ef 100644 --- a/spotify_dl/__init__.py +++ b/spotify_dl/__init__.py @@ -8,5 +8,7 @@ def signal_handler(sig, frame): print("\nCaught interrupt(did you press Ctrl+C?), stopping spotify_dl") sys.exit(0) - -signal.signal(signal.SIGINT, signal_handler) +try: + signal.signal(signal.SIGINT, signal_handler) +except ValueError: + print("Exception in signal handler") diff --git a/spotify_dl/constants.py b/spotify_dl/constants.py index 1210085..d9ce9e0 100644 --- a/spotify_dl/constants.py +++ b/spotify_dl/constants.py @@ -3,7 +3,7 @@ from pathlib import Path __all__ = ["VERSION"] -VERSION = "8.8.1" +VERSION = "8.9.0" if os.getenv("XDG_CACHE_HOME") is not None: SAVE_PATH = os.getenv("XDG_CACHE_HOME") + "/spotifydl" diff --git a/spotify_dl/spotify.py b/spotify_dl/spotify.py index 7969a58..4ce8d58 100644 --- a/spotify_dl/spotify.py +++ b/spotify_dl/spotify.py @@ -1,15 +1,17 @@ + import sys +import logging from spotify_dl.scaffold import log from spotify_dl.utils import sanitize from rich.progress import Progress -def fetch_tracks(sp, item_type, url): +def fetch_tracks(sp, item_type, item_id): """ - Fetches tracks from the provided URL. + Fetches tracks from the provided item_id. :param sp: Spotify client :param item_type: Type of item being requested for: album/playlist/track - :param url: URL of the item + :param item_id: id of the item :return Dictionary of song and artist """ songs_list = [] @@ -17,11 +19,14 @@ def fetch_tracks(sp, item_type, url): songs_fetched = 0 if item_type == "playlist": + logger = logging.getLogger("discord") + + logger.info("Playlist") with Progress() as progress: songs_task = progress.add_task(description="Fetching songs from playlist..") while True: items = sp.playlist_items( - playlist_id=url, + playlist_id=item_id, fields="items.track.name,items.track.artists(name, uri)," "items.track.album(name, release_date, total_tracks, images)," "items.track.track_number,total, next,offset," @@ -30,6 +35,7 @@ def fetch_tracks(sp, item_type, url): offset=offset, ) total_songs = items.get("total") + logger.info(total_songs) track_info_task = progress.add_task( description="Fetching track info", total=len(items["items"]) ) @@ -37,16 +43,32 @@ def fetch_tracks(sp, item_type, url): track_info = item.get("track") # If the user has a podcast in their playlist, there will be no track # Without this conditional, the program will fail later on when the metadata is fetched + logger.info(item) if track_info is None: offset += 1 continue + if not track_info.get("artists")[0]["name"]: + offset +=1 + continue track_album_info = track_info.get("album") track_num = track_info.get("track_number") - spotify_id = track_info.get("id") track_name = track_info.get("name") - track_artist = ", ".join( - [artist["name"] for artist in track_info.get("artists")] - ) + spotify_id = track_info.get("id") + track_audio_data = "No audio data" + try: + track_audio_data = sp.audio_analysis(spotify_id) + tempo = track_audio_data.get("track").get("tempo") + except: + log.error("Couldn't fetch audio analysis for %s", track_name) + tempo = None + print(track_info.get("artists")) + print(track_audio_data) + track_artist = "" + for artist in track_info.get("artists"): + if artist["name"]: + track_artist = ", ".join( + [artist["name"]] + ) if track_album_info: track_album = track_album_info.get("name") track_year = ( @@ -86,6 +108,7 @@ def fetch_tracks(sp, item_type, url): "genre": genre, "spotify_id": spotify_id, "track_url": None, + "tempo": tempo, } ) offset += 1 @@ -111,8 +134,8 @@ def fetch_tracks(sp, item_type, url): description="Fetching songs from the album.." ) while True: - album_info = sp.album(album_id=url) - items = sp.album_tracks(album_id=url, offset=offset) + album_info = sp.album(album_id=item_id) + items = sp.album_tracks(album_id=item_id, offset=offset) total_songs = items.get("total") track_album = album_info.get("name") track_year = ( @@ -141,6 +164,12 @@ def fetch_tracks(sp, item_type, url): ) track_num = item["track_number"] spotify_id = item.get("id") + try: + track_audio_data = sp.audio_analysis(spotify_id) + tempo = track_audio_data.get("track").get("tempo") + except: + log.error("Couldn't fetch audio analysis for %s", track_name) + tempo = None songs_list.append( { "name": track_name, @@ -154,6 +183,7 @@ def fetch_tracks(sp, item_type, url): "cover": cover, "genre": genre, "spotify_id": spotify_id, + "tempo": tempo, } ) offset += 1 @@ -168,7 +198,7 @@ def fetch_tracks(sp, item_type, url): break elif item_type == "track": - items = sp.track(track_id=url) + items = sp.track(track_id=item_id) track_name = items.get("name") album_info = items.get("album") track_artist = ", ".join([artist["name"] for artist in items["artists"]]) @@ -182,6 +212,12 @@ def fetch_tracks(sp, item_type, url): album_total = album_info.get("total_tracks") track_num = items["track_number"] spotify_id = items["id"] + try: + track_audio_data = sp.audio_analysis(spotify_id) + tempo = track_audio_data.get("track").get("tempo") + except: + log.error("Couldn't fetch audio analysis for %s", track_name) + tempo = None if len(items["album"]["images"]) > 0: cover = items["album"]["images"][0]["url"] else: @@ -203,6 +239,7 @@ def fetch_tracks(sp, item_type, url): "genre": genre, "track_url": None, "spotify_id": spotify_id, + "tempo": tempo, } ) @@ -219,9 +256,10 @@ def parse_spotify_url(url): if url.startswith("spotify:"): log.error("Spotify URI was provided instead of a playlist/album/track URL.") sys.exit(1) - parsed_url = url.replace("https://open.spotify.com/", "").split("?")[0] - item_type = parsed_url.split("/")[0] - item_id = parsed_url.split("/")[1] + parsed_url = url.replace("https://open.spotify.com/", "").split("?")[0].split("/") + index_adjustment = 1 if parsed_url[0].startswith("intl") else 0 + item_type = parsed_url[0+index_adjustment] + item_id = parsed_url[1+index_adjustment] return item_type, item_id @@ -239,8 +277,6 @@ def get_item_name(sp, item_type, item_id): name = sp.album(album_id=item_id).get("name") elif item_type == "track": name = sp.track(track_id=item_id).get("name") - elif item_type == "artist_top_tracks": - name = sp.artist_top_tracks(artist_id=item_id).get("name") return sanitize(name) diff --git a/spotify_dl/spotify_dl.py b/spotify_dl/spotify_dl.py index d4e3d13..0add158 100644 --- a/spotify_dl/spotify_dl.py +++ b/spotify_dl/spotify_dl.py @@ -198,7 +198,7 @@ def spotify_dl(): ) url_dict["save_path"].mkdir(parents=True, exist_ok=True) log.info("Saving songs to %s directory", directory_name) - url_dict["songs"] = fetch_tracks(sp, item_type, url) + url_dict["songs"] = fetch_tracks(sp, item_type, item_id) url_data["urls"].append(url_dict.copy()) if args.dump_json is True: dump_json(url_dict["songs"]) diff --git a/spotify_dl/youtube.py b/spotify_dl/youtube.py index 3f132af..f1f8ef1 100644 --- a/spotify_dl/youtube.py +++ b/spotify_dl/youtube.py @@ -1,9 +1,9 @@ +import shutil import urllib.request from os import path import os import multiprocessing -import shutil import json import mutagen import csv @@ -65,13 +65,13 @@ def write_tracks(tracks_file, song_dict): i = 0 writer = csv.writer(file_out, delimiter=";") for url_dict in song_dict["urls"]: - # for track in url_dict['songs']: for track in url_dict["songs"]: track_url = track["track_url"] # here track_name = track["name"] track_artist = track["artist"] track_num = track["num"] track_album = track["album"] + track_tempo = track["tempo"] track["save_path"] = url_dict["save_path"] track_db.append(track) track_index = i @@ -82,6 +82,7 @@ def write_tracks(tracks_file, song_dict): track_url, str(track_num), track_album, + str(track_tempo), str(track_index), ] try: @@ -97,8 +98,8 @@ def write_tracks(tracks_file, song_dict): def set_tags(temp, filename, kwargs): """ sets song tags after they are downloaded - :param temp: contains index used to obtain more info about song being edited - :param filename: location of song whose tags are to be edited + :param temp: contains index used to obtain more info about song being editted + :param filename: location of song whose tags are to be editted :param kwargs: a dictionary of extra arguments to be used in tag editing """ song = kwargs["track_db"][int(temp[-1])] @@ -120,6 +121,8 @@ def set_tags(temp, filename, kwargs): ) song_file["genre"] = song.get("genre") + if song.get("tempo") is not None: + song_file["bpm"] = str(song.get("tempo")) song_file.save() song_file = MP3(filename, ID3=ID3) cover = song.get("cover") @@ -162,7 +165,7 @@ def find_and_download_songs(kwargs): print(f"Initiating download for {query}.") file_name = kwargs["file_name_f"]( - name=name, artist=artist, track_num=kwargs["track_db"][i].get("num") + name=name, artist=artist, track_num=kwargs["track_db"][i].get("playlist_num") ) if kwargs["use_sponsorblock"][0].lower() == "y": @@ -197,9 +200,10 @@ def find_and_download_songs(kwargs): ): print(f"File {mp3file_path} already exists, we do not overwrite it ") continue - outtmpl = f"{file_path}.%(ext)s" ydl_opts = { + "username":kwargs["YT_AUTH"][0], + "password":kwargs["YT_AUTH"][1], "proxy": kwargs.get("proxy"), "default_search": "ytsearch", "format": "bestaudio/best", @@ -312,11 +316,7 @@ def download_songs(**kwargs): log.debug("Downloading to %s", url["save_path"]) reference_file = DOWNLOAD_LIST track_db = write_tracks(reference_file, kwargs["songs"]) - try: - shutil.copy(reference_file, kwargs["output_dir"] + "/" + reference_file) - os.remove(reference_file) - except: - os.rename(reference_file, kwargs["output_dir"] + "/" + reference_file) + shutil.copy(reference_file, kwargs["output_dir"] + "/" + reference_file) reference_file = str(kwargs["output_dir"]) + "/" + reference_file kwargs["reference_file"] = reference_file kwargs["track_db"] = track_db