✨ Implemented playlist track position naming ({list_pos}) for downloads. Fixes #165
This commit is contained in:
+22
-6
@@ -329,6 +329,8 @@ class Download:
|
|||||||
quality_audio: Quality | None = None,
|
quality_audio: Quality | None = None,
|
||||||
quality_video: QualityVideo | None = None,
|
quality_video: QualityVideo | None = None,
|
||||||
is_parent_album: bool = False,
|
is_parent_album: bool = False,
|
||||||
|
list_position: int = 0,
|
||||||
|
list_total: int = 0,
|
||||||
) -> (bool, pathlib.Path):
|
) -> (bool, pathlib.Path):
|
||||||
try:
|
try:
|
||||||
if media_id and media_type:
|
if media_id and media_type:
|
||||||
@@ -363,7 +365,9 @@ class Download:
|
|||||||
metadata_tags=[] if isinstance(media, Video) else media.media_metadata_tags,
|
metadata_tags=[] if isinstance(media, Video) else media.media_metadata_tags,
|
||||||
is_video=isinstance(media, Video),
|
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 = (
|
path_media_dst: pathlib.Path = (
|
||||||
pathlib.Path(self.path_base).expanduser() / (file_name_relative + file_extension_dummy)
|
pathlib.Path(self.path_base).expanduser() / (file_name_relative + file_extension_dummy)
|
||||||
).absolute()
|
).absolute()
|
||||||
@@ -732,7 +736,7 @@ class Download:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Create file name and path
|
# 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.
|
# Get the name of the list and check, if videos should be included.
|
||||||
list_media_name: str = name_builder_title(media)
|
list_media_name: str = name_builder_title(media)
|
||||||
@@ -756,7 +760,12 @@ class Download:
|
|||||||
)
|
)
|
||||||
|
|
||||||
is_album: bool = isinstance(media, Album)
|
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] = []
|
result_dirs: [pathlib.Path] = []
|
||||||
|
list_total: int = len(items)
|
||||||
|
|
||||||
# Iterate through list items
|
# Iterate through list items
|
||||||
while not progress.finished:
|
while not progress.finished:
|
||||||
@@ -771,8 +780,10 @@ class Download:
|
|||||||
quality_video=quality_video,
|
quality_video=quality_video,
|
||||||
download_delay=download_delay,
|
download_delay=download_delay,
|
||||||
is_parent_album=is_album,
|
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
|
# Report results as they become available
|
||||||
@@ -800,11 +811,13 @@ class Download:
|
|||||||
|
|
||||||
# Create playlist file
|
# Create playlist file
|
||||||
if self.settings.data.playlist_create:
|
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}'.")
|
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] = []
|
result: [pathlib.Path] = []
|
||||||
|
|
||||||
# For each dir, which contains tracks
|
# For each dir, which contains tracks
|
||||||
@@ -821,8 +834,11 @@ class Download:
|
|||||||
for extension_audio in AudioExtensions:
|
for extension_audio in AudioExtensions:
|
||||||
path_tracks = path_tracks + list(dir_scoped.glob(f"*{extension_audio!s}"))
|
path_tracks = path_tracks + list(dir_scoped.glob(f"*{extension_audio!s}"))
|
||||||
|
|
||||||
|
# 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
|
# If it is not an album sort by modification time
|
||||||
if not is_album:
|
|
||||||
path_tracks.sort(key=lambda x: os.path.getmtime(x))
|
path_tracks.sort(key=lambda x: os.path.getmtime(x))
|
||||||
|
|
||||||
# Write data to m3u file
|
# Write data to m3u file
|
||||||
|
|||||||
@@ -51,7 +51,11 @@ def path_file_settings() -> str:
|
|||||||
|
|
||||||
|
|
||||||
def format_path_media(
|
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:
|
) -> str:
|
||||||
result = fmt_template
|
result = fmt_template
|
||||||
|
|
||||||
@@ -61,7 +65,7 @@ def format_path_media(
|
|||||||
|
|
||||||
for _matchNum, match in enumerate(matches, start=1):
|
for _matchNum, match in enumerate(matches, start=1):
|
||||||
template_str = match.group()
|
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):
|
if result_fmt != match.group(1):
|
||||||
value = sanitize_filename(result_fmt)
|
value = sanitize_filename(result_fmt)
|
||||||
@@ -71,7 +75,11 @@ def format_path_media(
|
|||||||
|
|
||||||
|
|
||||||
def format_str_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:
|
) -> str:
|
||||||
result: str = name
|
result: str = name
|
||||||
|
|
||||||
@@ -101,12 +109,11 @@ def format_str_media(
|
|||||||
result = media.album.name
|
result = media.album.name
|
||||||
case "album_track_num":
|
case "album_track_num":
|
||||||
if isinstance(media, Track | Video):
|
if isinstance(media, Track | Video):
|
||||||
num_tracks: int = media.album.num_tracks if hasattr(media, "album") else 1
|
result = calculate_number_padding(
|
||||||
count_digits: int = int(math.log10(num_tracks)) + 1
|
album_track_num_pad_min,
|
||||||
count_digits_computed: int = (
|
media.track_num,
|
||||||
count_digits if count_digits > album_track_num_pad_min else album_track_num_pad_min
|
media.album.num_tracks if hasattr(media, "album") else 1,
|
||||||
)
|
)
|
||||||
result = str(media.track_num).zfill(count_digits_computed)
|
|
||||||
case "album_num_tracks":
|
case "album_num_tracks":
|
||||||
if isinstance(media, Track | Video):
|
if isinstance(media, Track | Video):
|
||||||
result = str(media.album.num_tracks if hasattr(media, "album") else 1)
|
result = str(media.album.num_tracks if hasattr(media, "album") else 1)
|
||||||
@@ -176,6 +183,10 @@ def format_str_media(
|
|||||||
case "isrc":
|
case "isrc":
|
||||||
if isinstance(media, Track):
|
if isinstance(media, Track):
|
||||||
result = media.isrc
|
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:
|
except Exception as e:
|
||||||
# TODO: Implement better exception logging.
|
# TODO: Implement better exception logging.
|
||||||
print(e)
|
print(e)
|
||||||
@@ -185,6 +196,19 @@ def format_str_media(
|
|||||||
return result
|
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(
|
def get_format_template(
|
||||||
media: Track | Album | Playlist | UserPlaylist | Video | Mix | MediaType, settings
|
media: Track | Album | Playlist | UserPlaylist | Video | Mix | MediaType, settings
|
||||||
) -> str | bool:
|
) -> str | bool:
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class Settings:
|
|||||||
"Albums/{album_artist} - {album_title}{album_explicit}/{track_volume_num_optional}"
|
"Albums/{album_artist} - {album_title}{album_explicit}/{track_volume_num_optional}"
|
||||||
"{album_track_num}. {artist_name} - {track_title}{album_explicit}"
|
"{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_mix: str = "Mix/{mix_name}/{artist_name} - {track_title}"
|
||||||
format_track: str = "Tracks/{artist_name} - {track_title}{track_explicit}"
|
format_track: str = "Tracks/{artist_name} - {track_title}{track_explicit}"
|
||||||
format_video: str = "Videos/{artist_name} - {track_title}{track_explicit}"
|
format_video: str = "Videos/{artist_name} - {track_title}{track_explicit}"
|
||||||
|
|||||||
Reference in New Issue
Block a user