From 2feb9c4b4945cd1c20b8799fd068cc81fc954929 Mon Sep 17 00:00:00 2001 From: Ritiek Malhotra Date: Thu, 23 Apr 2020 22:38:27 +0530 Subject: [PATCH] Implement --manual --- spotdl/command_line/__main__.py | 28 ++++----- spotdl/command_line/arguments.py | 37 ++---------- spotdl/command_line/helpers.py | 88 +++++++++++++++++----------- spotdl/metadata/providers/youtube.py | 3 + spotdl/util.py | 15 +++-- 5 files changed, 85 insertions(+), 86 deletions(-) diff --git a/spotdl/command_line/__main__.py b/spotdl/command_line/__main__.py index 234d59e..ba9e769 100644 --- a/spotdl/command_line/__main__.py +++ b/spotdl/command_line/__main__.py @@ -4,8 +4,8 @@ from spotdl import command_line import sys def match_arguments(arguments): - if arguments.tracks: - for track in arguments.tracks: + if arguments["song"]: + for track in arguments["song"]: if track == "-": for line in sys.stdin: command_line.helpers.download_track( @@ -14,36 +14,36 @@ def match_arguments(arguments): ) else: command_line.helpers.download_track(track, arguments) - elif arguments.list: - if arguments.write_m3u: + elif arguments["list"]: + if arguments["write_m3u"]: youtube_tools.generate_m3u( - track_file=arguments.list + track_file=arguments["list"] ) else: list_download = { "sequential": command_line.helpers.download_tracks_from_file, "threaded" : command_line.helpers.download_tracks_from_file_threaded, - }[arguments.processor] + }[arguments["processor"]] list_download( - arguments.list, + arguments["list"], arguments, ) - elif arguments.playlist: + elif arguments["playlist"]: spotify_tools.write_playlist( - playlist_url=arguments.playlist, text_file=arguments.write_to + playlist_url=arguments["playlist"], text_file=arguments["write_to"] ) - elif arguments.album: + elif arguments["album"]: spotify_tools.write_album( - album_url=arguments.album, text_file=arguments.write_to + album_url=arguments["album"], text_file=arguments["write_to"] ) elif arguments.all_albums: spotify_tools.write_all_albums_from_artist( - artist_url=arguments.all_albums, text_file=arguments.write_to + artist_url=arguments["all_albums"], text_file=arguments["write_to"] ) elif arguments.username: spotify_tools.write_user_playlist( - username=arguments.username, text_file=arguments.write_to + username=arguments["username"], text_file=arguments["write_to"] ) @@ -59,7 +59,7 @@ def main(): # logzero.setup_default_logger(formatter=const._formatter, level=const.args.log_level) try: - match_arguments(arguments) + match_arguments(arguments.__dict__) except KeyboardInterrupt as e: # log.exception(e) sys.exit(2) diff --git a/spotdl/command_line/arguments.py b/spotdl/command_line/arguments.py index feca6a8..42db085 100644 --- a/spotdl/command_line/arguments.py +++ b/spotdl/command_line/arguments.py @@ -51,18 +51,10 @@ def get_arguments(argv=None, to_merge=True): group = parser.add_mutually_exclusive_group(required=True) - # TODO: --song is deprecated. Remove in future versions. - # Use --tracks instead. group.add_argument( "-s", "--song", nargs="+", - help=argparse.SUPPRESS - ) - group.add_argument( - "-t", - "--tracks", - nargs="+", help="download track(s) by spotify link or name" ) group.add_argument( @@ -115,13 +107,6 @@ def get_arguments(argv=None, to_merge=True): help="do not embed metadata in tracks", action="store_true", ) - parser.add_argument( - "-nf", - "--no-fallback-metadata", - default=config["no-fallback-metadata"], - help="do not use YouTube as fallback for metadata if track not found on Spotify", - action="store_true", - ) parser.add_argument( "-a", "--avconv", @@ -190,13 +175,6 @@ def get_arguments(argv=None, to_merge=True): "are to be surrounded by curly braces. Possible tags: " # "{}".format([spotdl.util.formats[x] for x in spotdl.util.formats]), ) - parser.add_argument( - "-dm", - "--download-only-metadata", - default=config["download-only-metadata"], - help="download tracks only whose metadata is found", - action="store_true", - ) parser.add_argument( "-d", "--dry-run", @@ -210,15 +188,17 @@ def get_arguments(argv=None, to_merge=True): "--music-videos-only", default=config["music-videos-only"], help="search only for music videos on Youtube (works only " - "when YouTube API key is set", + "when YouTube API key is set)", action="store_true", ) parser.add_argument( "--processor", default=config["processor"], + choices={"synchronous", "threaded"}, help='list downloading strategy: - "synchronous" downloads ' - 'tracks one-by-one. - "threaded" (highly experimental!) pre-fetches ' - 'the next track\'s metadata for more efficient downloading' + 'tracks one-by-one. - "threaded" (highly experimental at the ' + 'moment! expect it to slash & burn) pre-fetches the next ' + 'track\'s metadata for more efficient downloading' ) parser.add_argument( "-ns", @@ -321,13 +301,6 @@ def run_errands(parser, parsed, config): # "output format".format(parsed.encoder)) parsed.encoder = "null" - song_parameter_passed = parsed.song is not None and parsed.tracks is None - if song_parameter_passed: - # log.warn("-s / --song is deprecated and will be removed in future versions. " - # "Use -t / --tracks instead.") - setattr(parsed, "tracks", parsed.song) - del parsed.song - if parsed.output_file == "-" and parsed.no_metadata is False: # log.warn( # "Cannot write metadata when target file is STDOUT. Pass " diff --git a/spotdl/command_line/helpers.py b/spotdl/command_line/helpers.py index 9dc5403..34599b5 100644 --- a/spotdl/command_line/helpers.py +++ b/spotdl/command_line/helpers.py @@ -40,7 +40,23 @@ def search_metadata_on_spotify(query): return metadata +def prompt_for_youtube_search_result(videos): + urls = [] + print("0. Skip downloading this track") + for index, video in enumerate(videos, 1): + video_repr = "{index}. {title} [{duration}] ({url})".format( + index=index, + title=video["title"], + duration=video["duration"], + url=video["url"] + ) + print(video_repr) + urls.append(video["url"]) + return spotdl.util.prompt_user_for_selection(urls) + + def search_metadata(track, search_format="{artist} - {track-name} lyrics", manual=False): + # TODO: Clean this function youtube = ProviderYouTube() youtube_searcher = YouTubeSearch() @@ -52,16 +68,16 @@ def search_metadata(track, search_format="{artist} - {track-name} lyrics", manua spotify_metadata, ) search_query = spotdl.metadata.format_string(search_format, spotify_metadata) - youtube_urls = youtube_searcher.search(search_query) - if not youtube_urls: + youtube_videos = youtube_searcher.search(search_query) + if not youtube_videos: raise NoYouTubeVideoError( 'No videos found for the search query: "{}"'.format(search_query) ) if manual: - pass + youtube_video = prompt_for_youtube_search_result(youtube_videos) else: - youtube_url = youtube_urls.bestmatch()["url"] - youtube_metadata = youtube.from_url(youtube_url) + youtube_video = youtube_videos.bestmatch()["url"] + youtube_metadata = youtube.from_url(youtube_video) metadata = spotdl.util.merge( youtube_metadata, spotify_metadata @@ -81,17 +97,17 @@ def search_metadata(track, search_format="{artist} - {track-name} lyrics", manua args=(track,) ) spotify_metadata.start() - youtube_urls = youtube_searcher.search(track) - if not youtube_urls: - # raise NoYouTubeVideoError( - # 'No videos found for the search query: "{}"'.format(track) - # ) + youtube_videos = youtube_searcher.search(track) + if not youtube_videos: + raise NoYouTubeVideoError( + 'No videos found for the search query: "{}"'.format(track) + ) return if manual: - pass + youtube_video = prompt_for_youtube_search_result(youtube_videos) else: - youtube_url = youtube_urls.bestmatch()["url"] - youtube_metadata = youtube.from_url(youtube_url) + youtube_video = youtube_videos.bestmatch()["url"] + youtube_metadata = youtube.from_url(youtube_video) metadata = spotdl.util.merge( youtube_metadata, spotify_metadata.join() @@ -110,11 +126,15 @@ def download_track(track, arguments): track_splits = track.split(":") if len(track_splits) == 2: youtube_track, spotify_track = track_splits - metadata = search_metadata(track, search_format=arguments.search_format) + metadata = search_metadata( + track, + search_format=arguments["search_format"], + manual=arguments["manual"], + ) log_fmt = spotdl.metadata.format_string( - arguments.output_file, + arguments["output_file"], metadata, - output_extension=arguments.output_ext, + output_extension=arguments["output_ext"], ) # log.info(log_fmt) download_track_from_metadata(metadata, arguments) @@ -122,41 +142,41 @@ def download_track(track, arguments): def download_track_from_metadata(metadata, arguments): # TODO: Add `-m` flag - track = Track(metadata, cache_albumart=(not arguments.no_metadata)) + track = Track(metadata, cache_albumart=(not arguments["no_metadata"])) print(metadata["name"]) stream = metadata["streams"].get( - quality=arguments.quality, - preftype=arguments.input_ext, + quality=arguments["quality"], + preftype=arguments["input_ext"], ) # log.info(stream) Encoder = { "ffmpeg": EncoderFFmpeg, "avconv": EncoderAvconv, - }.get(arguments.encoder) + }.get(arguments["encoder"]) if Encoder is None: output_extension = stream["encoding"] else: - output_extension = arguments.output_ext + output_extension = arguments["output_ext"] filename = spotdl.metadata.format_string( - arguments.output_file, + arguments["output_file"], metadata, output_extension=output_extension, sanitizer=lambda s: spotdl.util.sanitize( - s, spaces_to_underscores=arguments.no_spaces + s, spaces_to_underscores=arguments["no_spaces"] ) ) print(filename) # log.info(filename) - to_skip = arguments.dry_run + to_skip = arguments["dry_run"] if not to_skip and os.path.isfile(filename): - if arguments.overwrite == "force": + if arguments["overwrite"] == "force": to_skip = False - elif arguments.overwrite == "prompt": + elif arguments["overwrite"] == "prompt": to_skip = not input("overwrite? (y/N)").lower() == "y" else: to_skip = True @@ -174,7 +194,7 @@ def download_track_from_metadata(metadata, arguments): encoder=Encoder() ) - if not arguments.no_metadata: + if not arguments["no_metadata"]: track.metadata["lyrics"] = track.metadata["lyrics"].join() try: track.apply_metadata(filename, encoding=output_extension) @@ -206,7 +226,7 @@ def download_tracks_from_file(path, arguments): for number, track in enumerate(tracks, 1): try: - metadata = search_metadata(next_track, arguments.search_format) + metadata = search_metadata(next_track, arguments["search_format"]) log_fmt=(str(number) + ". {artist} - {track-name}") # log.info(log_fmt) download_track_from_metadata(metadata, arguments) @@ -215,8 +235,8 @@ def download_tracks_from_file(path, arguments): # log.warning("Failed. Will retry after other songs\n") tracks.append(track) else: - if arguments.write_sucessful: - with open(arguments.write_successful, "a") as fout: + if arguments["write_sucessful"]: + with open(arguments["write_successful"], "a") as fout: fout.write(track) finally: with open(path, "w") as fout: @@ -254,7 +274,7 @@ def download_tracks_from_file_threaded(path, arguments): "current_track": None, "next_track": spotdl.util.ThreadWithReturnValue( target=search_metadata, - args=(next_track, arguments.search_format) + args=(next_track, arguments["search_format"]) ) } metadata["next_track"].start() @@ -269,7 +289,7 @@ def download_tracks_from_file_threaded(path, arguments): next_track = tracks.pop(0) metadata["next_track"] = spotdl.util.ThreadWithReturnValue( target=search_metadata, - args=(next_track, arguments.search_format) + args=(next_track, arguments["search_format"]) ) metadata["next_track"].start() @@ -289,8 +309,8 @@ def download_tracks_from_file_threaded(path, arguments): tracks.append(current_track) else: tracks_count -= 1 - if arguments.write_successful: - with open(arguments.write_successful, "a") as fout: + if arguments["write_successful"]: + with open(arguments["write_successful"], "a") as fout: fout.write(current_track) finally: current_iteration += 1 diff --git a/spotdl/metadata/providers/youtube.py b/spotdl/metadata/providers/youtube.py index ebdf053..e9a91e9 100644 --- a/spotdl/metadata/providers/youtube.py +++ b/spotdl/metadata/providers/youtube.py @@ -20,6 +20,9 @@ class YouTubeVideos(Sequence): self.videos = videos super().__init__() + def __repr__(self): + return "YouTubeVideos({})".format(self.videos) + def __len__(self): return len(self.videos) diff --git a/spotdl/util.py b/spotdl/util.py index 6d32028..f326fa7 100644 --- a/spotdl/util.py +++ b/spotdl/util.py @@ -49,20 +49,23 @@ def merge(base, overrider): return merger -def input_link(links): +def prompt_user_for_selection(items): """ Let the user input a choice. """ while True: try: - log.info("Choose your number:") + # log.info("Choose your number:") + print("Choose your number:") the_chosen_one = int(input("> ")) - if 1 <= the_chosen_one <= len(links): - return links[the_chosen_one - 1] + if 1 <= the_chosen_one <= len(items): + return items[the_chosen_one - 1] elif the_chosen_one == 0: return None else: - log.warning("Choose a valid number!") + # log.warning("Choose a valid number!") + print("Chose a valid number!") except ValueError: - log.warning("Choose a valid number!") + # log.warning("Choose a valid number!") + print("Chose a valid number!") def is_spotify(raw_song):