mirror of
https://github.com/KevinMidboe/spotify-downloader.git
synced 2025-10-29 18:00:15 +00:00
Implement --manual
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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 "
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user