From 7ddc5c6348fe075c62a09c6df2f2716b654a6c69 Mon Sep 17 00:00:00 2001 From: Ritiek Malhotra Date: Wed, 22 Apr 2020 16:02:27 +0530 Subject: [PATCH] Support reading & writing to STDIN & STDOUT respectively --- spotdl/command_line/__init__.py | 2 +- spotdl/command_line/__main__.py | 26 +++++++-------- spotdl/command_line/arguments.py | 14 ++++++++ spotdl/command_line/helpers.py | 56 ++++++++++++++++++++++++++------ spotdl/config.py | 1 + 5 files changed, 75 insertions(+), 24 deletions(-) diff --git a/spotdl/command_line/__init__.py b/spotdl/command_line/__init__.py index 5c56cc4..5e76bd2 100644 --- a/spotdl/command_line/__init__.py +++ b/spotdl/command_line/__init__.py @@ -1,3 +1,3 @@ -from spotdl.command_line.arguments import get_arguments from spotdl.command_line import helpers +from spotdl.command_line.arguments import get_arguments diff --git a/spotdl/command_line/__main__.py b/spotdl/command_line/__main__.py index b6626c1..39521e5 100644 --- a/spotdl/command_line/__main__.py +++ b/spotdl/command_line/__main__.py @@ -1,31 +1,31 @@ from spotdl.authorize.services import AuthorizeSpotify from spotdl import command_line +import sys + def match_arguments(arguments): if arguments.tracks: - # TODO: Also support reading from stdin for -t parameter - # Also supported writing to stdout for all parameters - if len(arguments.tracks) > 1: - # log.warning("download multiple tracks with optimized list instead") - pass for track in arguments.tracks: - command_line.helpers.download_track(track, arguments) + if track == "-": + for line in sys.stdin: + command_line.helpers.download_track(line, arguments) + else: + command_line.helpers.download_track(track, arguments) elif arguments.list: if arguments.write_m3u: youtube_tools.generate_m3u( track_file=arguments.list ) else: - command_line.helpers.download_tracks_from_file( + list_download = { + "sequential": command_line.helpers.download_tracks_from_file, + "threaded" : command_line.helpers.download_tracks_from_file_threaded, + }[arguments.processor] + + list_download( arguments.list, arguments, ) - # list_dl = downloader.ListDownloader( - # tracks_file=arguments.list, - # skip_file=arguments.skip, - # write_successful_file=arguments.write_successful, - # ) - # list_dl.download_list() elif arguments.playlist: spotify_tools.write_playlist( playlist_url=arguments.playlist, text_file=arguments.write_to diff --git a/spotdl/command_line/arguments.py b/spotdl/command_line/arguments.py index a8952c3..9c2382b 100644 --- a/spotdl/command_line/arguments.py +++ b/spotdl/command_line/arguments.py @@ -219,6 +219,13 @@ def get_arguments(argv=None, to_merge=True): "when YouTube API key is set", action="store_true", ) + parser.add_argument( + "--processor", + default=config["processor"], + help='list downloading strategy: - "synchronous" downloads ' + 'tracks one-by-one. - "threaded" (highly experimental!) pre-fetches ' + 'the next track\'s metadata for more efficient downloading' + ) parser.add_argument( "-ns", "--no-spaces", @@ -327,6 +334,13 @@ def run_errands(parser, parsed): setattr(parsed, "tracks", parsed.song) del parsed.song + if parsed.file_format == "-" and parsed.no_metadata is False: + # log.warn( + # "Cannot write metadata when target file is STDOUT. Pass " + # "--no-metadata explicitly to hide this warning." + # ) + parsed.no_metadata = True + parsed.log_level = log_leveller(parsed.log_level) return parsed diff --git a/spotdl/command_line/helpers.py b/spotdl/command_line/helpers.py index 221b7af..8417c5a 100644 --- a/spotdl/command_line/helpers.py +++ b/spotdl/command_line/helpers.py @@ -20,9 +20,6 @@ import spotdl.util import os import urllib.request -# XXX: The code here may be a bit ugly due to overly gross techniques -# applied to squeeze out possible bits of performance. - def search_lyrics(query): provider = Genius() @@ -181,6 +178,46 @@ def download_track_from_metadata(metadata, arguments): def download_tracks_from_file(path, arguments): + # log.info( + # "Checking and removing any duplicate tracks " + # "in reading {}".format(path) + # ) + with open(path, "r") as fin: + # Read tracks into a list and remove any duplicates + tracks = fin.read().splitlines() + + # Remove duplicates and empty elements + # Also strip whitespaces from elements (if any) + spotdl.util.remove_duplicates( + tracks, + condition=lambda x: x, + operation=str.strip + ) + + # Overwrite file + with open(path, "w") as fout: + fout.writelines(tracks) + + for number, track in enumerate(tracks, 1): + try: + 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) + except (urllib.request.URLError, TypeError, IOError) as e: + # log.exception(e.args[0]) + # 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: + fout.write(track) + finally: + with open(path, "w") as fout: + fout.writelines(tracks[number-1:]) + + +def download_tracks_from_file_threaded(path, arguments): # FIXME: Can we make this function cleaner? # log.info( @@ -221,7 +258,7 @@ def download_tracks_from_file(path, arguments): try: print(tracks_count) print(tracks) - if tracks_count > 0: + if tracks_count > 1: current_track = next_track next_track = tracks.pop(0) metadata["next_track"] = spotdl.util.ThreadWithReturnValue( @@ -234,13 +271,12 @@ def download_tracks_from_file(path, arguments): # log.info(log_fmt) if metadata["current_track"] is None: # log.warning("Something went wrong. Will retry after downloading remaining tracks") - print("FUCK") - raise TypeError("fuck.") + pass print(metadata["current_track"]["name"]) - download_track_from_metadata( - metadata["current_track"], - arguments - ) + # download_track_from_metadata( + # metadata["current_track"], + # arguments + # ) except (urllib.request.URLError, TypeError, IOError) as e: # log.exception(e.args[0]) # log.warning("Failed. Will retry after other songs\n") diff --git a/spotdl/config.py b/spotdl/config.py index 7ae609b..9dbd5d5 100644 --- a/spotdl/config.py +++ b/spotdl/config.py @@ -22,6 +22,7 @@ DEFAULT_CONFIGURATION = { "dry-run": False, "music-videos-only": False, "no-spaces": False, + "processor": "synchronous", "file-format": "{artist} - {track-name}.{output-ext}", "search-format": "{artist} - {track-name} lyrics", "youtube-api-key": None,