diff --git a/tidal_dl_ng/download.py b/tidal_dl_ng/download.py index fe5f0c6..3866ca9 100644 --- a/tidal_dl_ng/download.py +++ b/tidal_dl_ng/download.py @@ -329,6 +329,8 @@ class Download: quality_audio: Quality | None = None, quality_video: QualityVideo | None = None, is_parent_album: bool = False, + list_position: int = 0, + list_total: int = 0, ) -> (bool, pathlib.Path): try: if media_id and media_type: @@ -363,7 +365,9 @@ class Download: metadata_tags=[] if isinstance(media, Video) else media.media_metadata_tags, is_video=isinstance(media, Video), ) - file_name_relative: str = format_path_media(file_template, media, self.settings.data.album_track_num_pad_min) + file_name_relative: str = format_path_media( + file_template, media, self.settings.data.album_track_num_pad_min, list_position, list_total + ) path_media_dst: pathlib.Path = ( pathlib.Path(self.path_base).expanduser() / (file_name_relative + file_extension_dummy) ).absolute() @@ -732,7 +736,7 @@ class Download: return # Create file name and path - file_name_relative: str = format_path_media(file_template, media, self.settings.data.album_track_num_pad_min) + file_name_relative: str = format_path_media(file_template, media) # Get the name of the list and check, if videos should be included. list_media_name: str = name_builder_title(media) @@ -756,7 +760,12 @@ class Download: ) is_album: bool = isinstance(media, Album) + # TODO: Refactor strings to constants (also in cfg.py) + sort_by_track_num: bool = ( + True if "album_track_num" in file_name_relative or "list_pos" in file_name_relative else False + ) result_dirs: [pathlib.Path] = [] + list_total: int = len(items) # Iterate through list items while not progress.finished: @@ -771,8 +780,10 @@ class Download: quality_video=quality_video, download_delay=download_delay, is_parent_album=is_album, + list_position=count + 1, + list_total=list_total, ) - for item_media in items + for count, item_media in enumerate(items) ] # Report results as they become available @@ -800,11 +811,13 @@ class Download: # Create playlist file if self.settings.data.playlist_create: - self.playlist_populate(set(result_dirs), list_media_name, is_album) + self.playlist_populate(set(result_dirs), list_media_name, is_album, sort_by_track_num) self.fn_logger.info(f"Finished list '{list_media_name}'.") - def playlist_populate(self, dirs_scoped: [pathlib.Path], name_list: str, is_album: bool) -> [pathlib.Path]: + def playlist_populate( + self, dirs_scoped: [pathlib.Path], name_list: str, is_album: bool, sort_alphabetically + ) -> [pathlib.Path]: result: [pathlib.Path] = [] # For each dir, which contains tracks @@ -821,8 +834,11 @@ class Download: for extension_audio in AudioExtensions: path_tracks = path_tracks + list(dir_scoped.glob(f"*{extension_audio!s}")) - # If it is not an album sort by modification time - if not is_album: + # Sort alphabetically, e.g. if items are prefixed with numbers + if sort_alphabetically: + path_tracks.sort() + elif not is_album: + # If it is not an album sort by modification time path_tracks.sort(key=lambda x: os.path.getmtime(x)) # Write data to m3u file diff --git a/tidal_dl_ng/helper/path.py b/tidal_dl_ng/helper/path.py index a02ebd2..7e90b61 100644 --- a/tidal_dl_ng/helper/path.py +++ b/tidal_dl_ng/helper/path.py @@ -51,7 +51,11 @@ def path_file_settings() -> str: def format_path_media( - fmt_template: str, media: Track | Album | Playlist | UserPlaylist | Video | Mix, album_track_num_pad_min: int = 0 + fmt_template: str, + media: Track | Album | Playlist | UserPlaylist | Video | Mix, + album_track_num_pad_min: int = 0, + list_pos: int = 0, + list_total: int = 0, ) -> str: result = fmt_template @@ -61,7 +65,7 @@ def format_path_media( for _matchNum, match in enumerate(matches, start=1): template_str = match.group() - result_fmt = format_str_media(match.group(1), media, album_track_num_pad_min) + result_fmt = format_str_media(match.group(1), media, album_track_num_pad_min, list_pos, list_total) if result_fmt != match.group(1): value = sanitize_filename(result_fmt) @@ -71,7 +75,11 @@ def format_path_media( def format_str_media( - name: str, media: Track | Album | Playlist | UserPlaylist | Video | Mix, album_track_num_pad_min: int = 0 + name: str, + media: Track | Album | Playlist | UserPlaylist | Video | Mix, + album_track_num_pad_min: int = 0, + list_pos: int = 0, + list_total: int = 0, ) -> str: result: str = name @@ -101,12 +109,11 @@ def format_str_media( result = media.album.name case "album_track_num": if isinstance(media, Track | Video): - num_tracks: int = media.album.num_tracks if hasattr(media, "album") else 1 - count_digits: int = int(math.log10(num_tracks)) + 1 - count_digits_computed: int = ( - count_digits if count_digits > album_track_num_pad_min else album_track_num_pad_min + result = calculate_number_padding( + album_track_num_pad_min, + media.track_num, + media.album.num_tracks if hasattr(media, "album") else 1, ) - result = str(media.track_num).zfill(count_digits_computed) case "album_num_tracks": if isinstance(media, Track | Video): result = str(media.album.num_tracks if hasattr(media, "album") else 1) @@ -176,6 +183,10 @@ def format_str_media( case "isrc": if isinstance(media, Track): result = media.isrc + case "list_pos": + if isinstance(media, Track | Video): + # TODO: Rename `album_track_num_pad_min` globally. + result = calculate_number_padding(album_track_num_pad_min, list_pos, list_total) except Exception as e: # TODO: Implement better exception logging. print(e) @@ -185,6 +196,19 @@ def format_str_media( return result +def calculate_number_padding(padding_minimum: int, item_position: int, items_max: int) -> str: + result: str + + if items_max > 0: + count_digits: int = int(math.log10(items_max)) + 1 + count_digits_computed: int = count_digits if count_digits > padding_minimum else padding_minimum + result = str(item_position).zfill(count_digits_computed) + else: + result = str(item_position) + + return result + + def get_format_template( media: Track | Album | Playlist | UserPlaylist | Video | Mix | MediaType, settings ) -> str | bool: diff --git a/tidal_dl_ng/model/cfg.py b/tidal_dl_ng/model/cfg.py index 69c394d..8166050 100644 --- a/tidal_dl_ng/model/cfg.py +++ b/tidal_dl_ng/model/cfg.py @@ -27,7 +27,7 @@ class Settings: "Albums/{album_artist} - {album_title}{album_explicit}/{track_volume_num_optional}" "{album_track_num}. {artist_name} - {track_title}{album_explicit}" ) - format_playlist: str = "Playlists/{playlist_name}/{artist_name} - {track_title}" + format_playlist: str = "Playlists/{playlist_name}/{list_pos}. {artist_name} - {track_title}" format_mix: str = "Mix/{mix_name}/{artist_name} - {track_title}" format_track: str = "Tracks/{artist_name} - {track_title}{track_explicit}" format_video: str = "Videos/{artist_name} - {track_title}{track_explicit}"