From 474fc62847b72e62537a6929961027f1ec26e693 Mon Sep 17 00:00:00 2001 From: McLP2 Date: Thu, 30 Mar 2023 16:38:46 +0200 Subject: [PATCH] Add max-duration-difference option to limit the search to matching lengths. --- spotify_dl/spotify.py | 4 +++- spotify_dl/spotify_dl.py | 9 +++++++++ spotify_dl/youtube.py | 27 +++++++++++++++++++++------ 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/spotify_dl/spotify.py b/spotify_dl/spotify.py index 90d5878f..21dbf320 100644 --- a/spotify_dl/spotify.py +++ b/spotify_dl/spotify.py @@ -25,7 +25,7 @@ def fetch_tracks(sp, item_type, url): 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," - "items.track.id", + "items.track.id,items.track.duration_ms", additional_types=["track"], offset=offset, ) @@ -47,6 +47,7 @@ def fetch_tracks(sp, item_type, url): track_artist = ",".join( [artist["name"] for artist in track_info.get("artists")] ) + track_duration = track_info.get("duration_ms") / 1000 if track_album_info: track_album = track_album_info.get("name") track_year = ( @@ -78,6 +79,7 @@ def fetch_tracks(sp, item_type, url): "name": track_name, "artist": track_artist, "album": track_album, + "duration": track_duration, "year": track_year, "num_tracks": album_total, "num": track_num, diff --git a/spotify_dl/spotify_dl.py b/spotify_dl/spotify_dl.py index 7fc50dda..53832ac6 100755 --- a/spotify_dl/spotify_dl.py +++ b/spotify_dl/spotify_dl.py @@ -112,6 +112,14 @@ def spotify_dl(): default="", help="Download through a proxy. Support HTTP & SOCKS5. Use 'http://username:password@hostname:port' or 'http://hostname:port'", ) + parser.add_argument( + "-mdd", + "--max-duration-difference", + action="store", + type=float, + default=-1, + help="Only download songs that match the track duration up to a maximum difference in seconds", + ) args = parser.parse_args() num_cores = os.cpu_count() args.multi_core = int(args.multi_core) @@ -188,6 +196,7 @@ def spotify_dl(): output_dir=args.output, format_str=args.format_str, skip_mp3=args.skip_mp3, + max_duration_difference=args.max_duration_difference, keep_playlist_order=args.keep_playlist_order, no_overwrites=args.no_overwrites, use_sponsorblock=args.use_sponsorblock, diff --git a/spotify_dl/youtube.py b/spotify_dl/youtube.py index 253b0b53..f92aa8e7 100644 --- a/spotify_dl/youtube.py +++ b/spotify_dl/youtube.py @@ -25,6 +25,13 @@ def playlist_num_filename(**kwargs): return f"{kwargs['track_num']} - {default_filename(**kwargs)}" +def duration_delta(info, expected_duration, delta): + """Download only videos that match maximum duration difference""" + duration = info.get('duration') + if abs(duration - expected_duration) > delta: + return 'The video length does not match' + + def write_tracks(tracks_file, song_dict): """ Writes the information of all tracks in the playlist[s] to a text file in csv kind of format @@ -45,6 +52,7 @@ def write_tracks(tracks_file, song_dict): track_artist = track["artist"] track_num = track["num"] track_album = track["album"] + track_duration = track["duration"] track["save_path"] = url_dict["save_path"] track_db.append(track) track_index = i @@ -56,6 +64,7 @@ def write_tracks(tracks_file, song_dict): str(track_num), track_album, str(track_index), + track_duration, ] try: writer.writerow(csv_row) @@ -74,7 +83,7 @@ def set_tags(temp, filename, kwargs): :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])] + song = kwargs["track_db"][int(temp[5])] try: song_file = MP3(filename, ID3=EasyID3) except mutagen.MutagenError as e: @@ -122,12 +131,13 @@ def find_and_download_songs(kwargs): reference_file = kwargs["reference_file"] with open(reference_file, "r", encoding="utf-8") as file: for line in file: - temp = line.split(";") - name, artist, album, i = ( + temp = line.replace("\n", "").split(";") + name, artist, album, i, duration = ( temp[0], temp[1], temp[4], - int(temp[-1].replace("\n", "")), + int(temp[5]), + float(temp[6]), ) query = f"{artist} - {name} Lyrics".replace(":", "").replace('"', "") @@ -163,7 +173,8 @@ def find_and_download_songs(kwargs): outtmpl = f"{file_path}.%(ext)s" ydl_opts = { "proxy": kwargs.get('proxy'), - "default_search": "ytsearch", + "default_search": "ytsearch10", + "max_downloads": 1, "format": "bestaudio/best", "outtmpl": outtmpl, "postprocessors": sponsorblock_postprocessor, @@ -178,6 +189,9 @@ def find_and_download_songs(kwargs): "album=" + album, ], } + if kwargs["max_duration_difference"] >= 0: + ydl_opts["match_filter"] = lambda info, *, incomplete: duration_delta( + info, duration, kwargs["max_duration_difference"]) if not kwargs["skip_mp3"]: mp3_postprocess_opts = { "key": "FFmpegExtractAudio", @@ -190,7 +204,8 @@ def find_and_download_songs(kwargs): ydl.download([query]) except Exception as e: # skipcq: PYL-W0703 log.debug(e) - print(f"Failed to download {name}, make sure yt_dlp is up to date") + if type(e) != yt_dlp.utils.MaxDownloadsReached: + print(f"Failed to download {name}, make sure yt_dlp is up to date") if not kwargs["skip_mp3"]: set_tags(temp, mp3filename, kwargs)