def write_m3u(self, track_file, target_file=None): with open(track_file, "r") as fin: tracks = fin.read().splitlines() logger.info( "Checking and removing any duplicate tracks in {}.".format(track_file) ) # Remove duplicates and empty elements # Also strip whitespaces from elements (if any) tracks = spotdl.util.remove_duplicates( tracks, condition=lambda x: x, operation=str.strip ) if target_file is None: target_file = "{}.m3u".format(track_file.split(".")[0]) total_tracks = len(tracks) logger.info("Generating {0} from {1} YouTube URLs.".format(target_file, total_tracks)) write_to_stdout = target_file == "-" m3u_headers = "#EXTM3U\n\n" if write_to_stdout: sys.stdout.write(m3u_headers) else: with open(target_file, "w") as output_file: output_file.write(m3u_headers) videos = [] for n, track in enumerate(tracks, 1): search_metadata = MetadataSearch( track, lyrics=not self.arguments["no_metadata"], yt_search_format=self.arguments["search_format"], yt_manual=self.arguments["manual"] ) try: video = search_metadata.best_on_youtube_search() except (NoYouTubeVideoFoundError, NoYouTubeVideoMatchError) as e: logger.error(e.args[0]) else: logger.info( "Matched track {0}/{1} ({2})".format( str(n).zfill(len(str(total_tracks))), total_tracks, video["url"], ) ) m3u_key = "#EXTINF:{duration},{title}\n{youtube_url}\n".format( duration=spotdl.util.get_sec(video["duration"]), title=video["title"], youtube_url=video["url"], ) logger.debug(m3u_key.strip()) if write_to_stdout: sys.stdout.write(m3u_key) else: with open(target_file, "a") as output_file: output_file.write(m3u_key)
def download_tracks_from_file(self, path): logger.info( 'Checking and removing any duplicate tracks in "{}".'.format(path) ) tracks = spotdl.util.readlines_from_nonbinary_file(path) tracks = self.strip_and_filter_duplicates(tracks) if self.arguments["skip_file"]: len_tracks_before = len(tracks) tracks = self.filter_against_skip_file(tracks, self.arguments["skip_file"]) logger.info("Skipping {} tracks due to matches in skip file.".format( len_tracks_before - len(tracks)) ) # Overwrite file spotdl.util.writelines_to_nonbinary_file(path, tracks) logger.info( "Downloading {n} tracks.\n".format(n=len(tracks)) ) for position, track in enumerate(tracks, 1): search_metadata = MetadataSearch( track, lyrics=True, yt_search_format=self.arguments["search_format"], yt_manual=self.arguments["manual"] ) log_track_query = '{position}. Downloading "{track}"'.format( position=position, track=track ) logger.info(log_track_query) try: metadata = search_metadata.on_youtube_and_spotify() self.download_track_from_metadata(metadata) except (urllib.request.URLError, TypeError, IOError) as e: logger.exception(e.args[0]) logger.warning( "Failed to download current track due to possible network issue. " "Will retry after other songs." ) tracks.append(track) except (NoYouTubeVideoFoundError, NoYouTubeVideoMatchError) as e: logger.error("{err}".format(err=e.args[0])) except KeyboardInterrupt: # The current track hasn't been downloaded completely. # Make sure we continue from here the next the program runs. tracks.insert(0, track) raise else: if self.arguments["write_successful_file"]: with open(self.arguments["write_successful_file"], "a") as fout: fout.write("{}\n".format(track)) finally: spotdl.util.writelines_to_nonbinary_file(path, tracks[position:]) print("", file=sys.stderr)
def download_track(self, track): subtracks = track.split("::") download_track = subtracks[0] custom_metadata_track = len(subtracks) > 1 if custom_metadata_track: metadata_track = subtracks[1] else: metadata_track = download_track search_metadata = MetadataSearch( metadata_track, lyrics=not self.arguments["no_metadata"], yt_search_format=self.arguments["search_format"], yt_manual=self.arguments["manual"] ) def threaded_metadata(): try: if self.arguments["no_metadata"]: metadata = search_metadata.on_youtube() else: metadata = search_metadata.on_youtube_and_spotify() except (NoYouTubeVideoFoundError, NoYouTubeVideoMatchError) as e: logger.error(e.args[0]) else: return metadata metadata = spotdl.util.ThreadWithReturnValue(target=threaded_metadata) metadata.start() if not custom_metadata_track: metadata = metadata.join() if not metadata: return return self.download_track_from_metadata(metadata) search_metadata = MetadataSearch( download_track, lyrics=False, yt_search_format=self.arguments["search_format"], yt_manual=self.arguments["manual"] ) try: download_track_metadata = search_metadata.on_youtube() except (NoYouTubeVideoFoundError, NoYouTubeVideoMatchError) as e: logger.error(e.args[0]) return metadata = metadata.join() if not metadata: return logger.info('Overriding metadata as per passed metadata-track'.format(metadata_track)) metadata["streams"] = download_track_metadata["streams"] return self.download_track_from_metadata(metadata)
def download_track(self, track): logger.info('Downloading "{}"'.format(track)) search_metadata = MetadataSearch( track, lyrics=not self.arguments["no_metadata"], yt_search_format=self.arguments["search_format"], yt_manual=self.arguments["manual"]) try: if self.arguments["no_metadata"]: metadata = search_metadata.on_youtube() else: metadata = search_metadata.on_youtube_and_spotify() except (NoYouTubeVideoFoundError, NoYouTubeVideoMatchError) as e: logger.error(e.args[0]) else: self.download_track_from_metadata(metadata)