def backup_to_disk(self): """ RETURNS `~` backs up details of songObj's yet to be downloaded to a .spotdlTrackingFile """ # remove tracking file if no songs left in queue # ! we use 'return None' as a convenient exit point if len(self.song_list) == 0: if self.save_file and self.save_file.is_file(): self.save_file.unlink() return None # prepare datadumps of all songObj's yet to be downloaded song_data_dumps = [song.data_dump for song in self.song_list] # ! the default naming of a tracking file is $nameOfFirstSOng.spotdlTrackingFile, # ! it needs a little fixing because of disallowed characters in file naming if not self.save_file: song_name = self.song_list[0].song_name song_name = format_name(song_name) self.save_file = Path(song_name + ".spotdlTrackingFile") # save encoded string to a file with open(self.save_file, "wb") as file_handle: file_handle.write(str(song_data_dumps).encode())
def create_file_name(song_name: str, song_artists: List[str]) -> str: # build file name of converted file # the main artist is always included artist_string = song_artists[0] # ! we eliminate contributing artist names that are also in the song name, else we # ! would end up with things like 'Jetta, Mastubs - I'd love to change the world # ! (Mastubs REMIX).mp3' which is kinda an odd file name. for artist in song_artists[1:]: if artist.lower() not in song_name.lower(): artist_string += ", " + artist converted_file_name = artist_string + " - " + song_name return format_name(converted_file_name)
def from_playlist( playlist_url: str, output_format: str = None, use_youtube: bool = False, lyrics_provider: str = None, generate_m3u: bool = False, threads: int = 1, path_template: str = None, ) -> List[SongObject]: """ Create and return list containing SongObject for every song in the playlist `str` `album_url` : Spotify Url of the album whose tracks are to be retrieved `str` `output_format` : output format of the song returns a `list<SongObject>` containing Url's of each track in the given album """ spotify_client = SpotifyClient() tracks = [] playlist_response = spotify_client.playlist_tracks(playlist_url) playlist = spotify_client.playlist(playlist_url) if playlist_response is None: raise ValueError("Wrong playlist id") playlist_tracks = [ track for track in playlist_response["items"] # check if track has id if track is not None and track.get("track") is not None and track["track"].get("id") is not None ] # Get all tracks from playlist while playlist_response["next"]: playlist_response = spotify_client.next(playlist_response) # Failed to get response, break the loop if playlist_response is None: break playlist_tracks.extend(playlist_response["items"]) # Remove songs without id playlist_tracks = [ track for track in playlist_tracks if track is not None and track.get("track") is not None and track["track"].get("id") is not None ] def get_song(track): try: song = from_spotify_url( "https://open.spotify.com/track/" + track["track"]["id"], output_format, use_youtube, lyrics_provider, playlist, ) if generate_m3u: if path_template: file_path = _parse_path_template(path_template, song, output_format) else: file_path = _get_converted_file_path(song, output_format) return song, f"{file_path}\n" return song, None except (LookupError, ValueError): return None, None except OSError: if generate_m3u: song_obj = SongObject( track["track"], {}, {}, None, "", playlist_response ) if path_template: file_path = _parse_path_template( path_template, song_obj, output_format ) else: file_path = _get_converted_file_path(song_obj, output_format) return None, f"{file_path}\n" return None, None with concurrent.futures.ThreadPoolExecutor(max_workers=threads) as executor: results = executor.map(get_song, playlist_tracks) playlist_text = "" for result in results: if result[1] is not None: playlist_text += result[1] if result[0] is not None and result[0].youtube_link is not None: tracks.append(result[0]) if playlist_response and generate_m3u is True: playlist_data = spotify_client.playlist(playlist_url) if playlist_data is not None: playlist_name = playlist_data["name"] else: playlist_name = playlist_tracks[0]["track"]["name"] playlist_name = format_name(playlist_name) playlist_file = Path(f"{playlist_name}.m3u") with open(playlist_file, "w", encoding="utf-8") as file: file.write(playlist_text) return tracks
def _sanitize_filename(input_str: str) -> str: return format_name(input_str)