Merge pull request #586 from exislow:playlist_sort
feat(path): ✨ add customizable delimiters for artist names in file paths
This commit is contained in:
+27
-6
@@ -653,7 +653,13 @@ class Download:
|
|||||||
)
|
)
|
||||||
|
|
||||||
file_name_relative: str = format_path_media(
|
file_name_relative: str = format_path_media(
|
||||||
file_template, media, self.settings.data.album_track_num_pad_min, list_position, list_total
|
file_template,
|
||||||
|
media,
|
||||||
|
self.settings.data.album_track_num_pad_min,
|
||||||
|
list_position,
|
||||||
|
list_total,
|
||||||
|
delimiter_artist=self.settings.data.filename_delimiter_artist,
|
||||||
|
delimiter_album_artist=self.settings.data.filename_delimiter_album_artist,
|
||||||
)
|
)
|
||||||
|
|
||||||
path_media_dst: pathlib.Path = (
|
path_media_dst: pathlib.Path = (
|
||||||
@@ -671,7 +677,12 @@ class Download:
|
|||||||
|
|
||||||
if self.settings.data.symlink_to_track and not isinstance(media, Video):
|
if self.settings.data.symlink_to_track and not isinstance(media, Video):
|
||||||
# Compute symlink tracks path, sanitize and check if file exists
|
# Compute symlink tracks path, sanitize and check if file exists
|
||||||
file_name_track_dir_relative: str = format_path_media(self.settings.data.format_track, media)
|
file_name_track_dir_relative: str = format_path_media(
|
||||||
|
self.settings.data.format_track,
|
||||||
|
media,
|
||||||
|
delimiter_artist=self.settings.data.filename_delimiter_artist,
|
||||||
|
delimiter_album_artist=self.settings.data.filename_delimiter_album_artist,
|
||||||
|
)
|
||||||
path_media_track_dir: pathlib.Path = (
|
path_media_track_dir: pathlib.Path = (
|
||||||
pathlib.Path(self.path_base).expanduser() / (file_name_track_dir_relative + file_extension_dummy)
|
pathlib.Path(self.path_base).expanduser() / (file_name_track_dir_relative + file_extension_dummy)
|
||||||
).absolute()
|
).absolute()
|
||||||
@@ -947,7 +958,12 @@ class Download:
|
|||||||
pathlib.Path: Destination path.
|
pathlib.Path: Destination path.
|
||||||
"""
|
"""
|
||||||
# Compute tracks path, sanitize and ensure path exists
|
# Compute tracks path, sanitize and ensure path exists
|
||||||
file_name_relative: str = format_path_media(self.settings.data.format_track, media)
|
file_name_relative: str = format_path_media(
|
||||||
|
self.settings.data.format_track,
|
||||||
|
media,
|
||||||
|
delimiter_artist=self.settings.data.filename_delimiter_artist,
|
||||||
|
delimiter_album_artist=self.settings.data.filename_delimiter_album_artist,
|
||||||
|
)
|
||||||
path_media_dst: pathlib.Path = (
|
path_media_dst: pathlib.Path = (
|
||||||
pathlib.Path(self.path_base).expanduser() / (file_name_relative + file_extension)
|
pathlib.Path(self.path_base).expanduser() / (file_name_relative + file_extension)
|
||||||
).absolute()
|
).absolute()
|
||||||
@@ -1315,7 +1331,12 @@ class Download:
|
|||||||
tuple[str, str, str, list, bool]: (file_name_relative, list_media_name, list_media_name_short, items, progress_stdout)
|
tuple[str, str, str, list, bool]: (file_name_relative, list_media_name, list_media_name_short, items, progress_stdout)
|
||||||
"""
|
"""
|
||||||
# Create file name and path
|
# Create file name and path
|
||||||
file_name_relative: str = format_path_media(file_template, media)
|
file_name_relative: str = format_path_media(
|
||||||
|
file_template,
|
||||||
|
media,
|
||||||
|
delimiter_artist=self.settings.data.filename_delimiter_artist,
|
||||||
|
delimiter_album_artist=self.settings.data.filename_delimiter_album_artist,
|
||||||
|
)
|
||||||
|
|
||||||
# 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)
|
||||||
@@ -1522,8 +1543,8 @@ class Download:
|
|||||||
if sort_alphabetically:
|
if sort_alphabetically:
|
||||||
path_tracks.sort()
|
path_tracks.sort()
|
||||||
elif not is_album:
|
elif not is_album:
|
||||||
# If it is not an album sort by modification time
|
# If it is not an album sort by creation time
|
||||||
path_tracks.sort(key=lambda x: os.path.getmtime(x))
|
path_tracks.sort(key=lambda x: os.path.getctime(x))
|
||||||
|
|
||||||
# Write data to m3u file
|
# Write data to m3u file
|
||||||
with path_playlist.open(mode="w", encoding="utf-8") as f:
|
with path_playlist.open(mode="w", encoding="utf-8") as f:
|
||||||
|
|||||||
+65
-15
@@ -87,7 +87,25 @@ def format_path_media(
|
|||||||
album_track_num_pad_min: int = 0,
|
album_track_num_pad_min: int = 0,
|
||||||
list_pos: int = 0,
|
list_pos: int = 0,
|
||||||
list_total: int = 0,
|
list_total: int = 0,
|
||||||
|
delimiter_artist: str = ", ",
|
||||||
|
delimiter_album_artist: str = ", ",
|
||||||
) -> str:
|
) -> str:
|
||||||
|
"""Formats a media path string using a template and media attributes.
|
||||||
|
|
||||||
|
Replaces placeholders in the format template with sanitized media attribute values to generate a valid file path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
fmt_template (str): The format template string containing placeholders.
|
||||||
|
media (Track | Album | Playlist | UserPlaylist | Video | Mix): The media object to extract values from.
|
||||||
|
album_track_num_pad_min (int, optional): Minimum padding for track numbers. Defaults to 0.
|
||||||
|
list_pos (int, optional): Position in a list. Defaults to 0.
|
||||||
|
list_total (int, optional): Total items in a list. Defaults to 0.
|
||||||
|
delimiter_artist (str, optional): Delimiter for artist names. Defaults to ", ".
|
||||||
|
delimiter_album_artist (str, optional): Delimiter for album artist names. Defaults to ", ".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The formatted and sanitized media path string.
|
||||||
|
"""
|
||||||
result = fmt_template
|
result = fmt_template
|
||||||
|
|
||||||
# Search track format template for placeholder.
|
# Search track format template for placeholder.
|
||||||
@@ -96,7 +114,15 @@ 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, list_pos, list_total)
|
result_fmt = format_str_media(
|
||||||
|
match.group(1),
|
||||||
|
media,
|
||||||
|
album_track_num_pad_min,
|
||||||
|
list_pos,
|
||||||
|
list_total,
|
||||||
|
delimiter_artist=delimiter_artist,
|
||||||
|
delimiter_album_artist=delimiter_album_artist,
|
||||||
|
)
|
||||||
|
|
||||||
if result_fmt != match.group(1):
|
if result_fmt != match.group(1):
|
||||||
# Sanitize here, in case of the filename has slashes or something, which will be recognized later as a directory separator.
|
# Sanitize here, in case of the filename has slashes or something, which will be recognized later as a directory separator.
|
||||||
@@ -115,18 +141,24 @@ def format_str_media(
|
|||||||
album_track_num_pad_min: int = 0,
|
album_track_num_pad_min: int = 0,
|
||||||
list_pos: int = 0,
|
list_pos: int = 0,
|
||||||
list_total: int = 0,
|
list_total: int = 0,
|
||||||
|
delimiter_artist: str = ", ",
|
||||||
|
delimiter_album_artist: str = ", ",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""Format a string based on media attributes.
|
"""Formats a string for media attributes based on the provided name.
|
||||||
|
|
||||||
|
Attempts to format the given name using a sequence of formatter functions, returning the first successful result.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The format template name.
|
name (str): The format string name to process.
|
||||||
media (Track | Album | Playlist | UserPlaylist | Video | Mix): The media object.
|
media (Track | Album | Playlist | UserPlaylist | Video | Mix): The media object to extract values from.
|
||||||
album_track_num_pad_min (int): Minimum padding for track numbers. Defaults to 0.
|
album_track_num_pad_min (int, optional): Minimum padding for track numbers. Defaults to 0.
|
||||||
list_pos (int): Position in a list. Defaults to 0.
|
list_pos (int, optional): Position in a list. Defaults to 0.
|
||||||
list_total (int): Total items in a list. Defaults to 0.
|
list_total (int, optional): Total items in a list. Defaults to 0.
|
||||||
|
delimiter_artist (str, optional): Delimiter for artist names. Defaults to ", ".
|
||||||
|
delimiter_album_artist (str, optional): Delimiter for album artist names. Defaults to ", ".
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str: The formatted string.
|
str: The formatted string for the media attribute, or the original name if no formatter matches.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Try each formatter function in sequence
|
# Try each formatter function in sequence
|
||||||
@@ -139,7 +171,15 @@ def format_str_media(
|
|||||||
_format_metadata,
|
_format_metadata,
|
||||||
_format_volumes,
|
_format_volumes,
|
||||||
):
|
):
|
||||||
result = formatter(name, media, album_track_num_pad_min, list_pos, list_total)
|
result = formatter(
|
||||||
|
name,
|
||||||
|
media,
|
||||||
|
album_track_num_pad_min,
|
||||||
|
list_pos,
|
||||||
|
list_total,
|
||||||
|
delimiter_artist=delimiter_artist,
|
||||||
|
delimiter_album_artist=delimiter_album_artist,
|
||||||
|
)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -152,6 +192,8 @@ def format_str_media(
|
|||||||
def _format_artist_names(
|
def _format_artist_names(
|
||||||
name: str,
|
name: str,
|
||||||
media: Track | Album | Playlist | UserPlaylist | Video | Mix,
|
media: Track | Album | Playlist | UserPlaylist | Video | Mix,
|
||||||
|
delimiter_artist: str = ", ",
|
||||||
|
delimiter_album_artist: str = ", ",
|
||||||
*_args,
|
*_args,
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
"""Handle artist name-related format strings.
|
"""Handle artist name-related format strings.
|
||||||
@@ -166,13 +208,13 @@ def _format_artist_names(
|
|||||||
"""
|
"""
|
||||||
if name == "artist_name" and isinstance(media, Track | Video):
|
if name == "artist_name" and isinstance(media, Track | Video):
|
||||||
if hasattr(media, "artists"):
|
if hasattr(media, "artists"):
|
||||||
return name_builder_artist(media)
|
return name_builder_artist(media, delimiter=delimiter_artist)
|
||||||
elif hasattr(media, "artist"):
|
elif hasattr(media, "artist"):
|
||||||
return media.artist.name
|
return media.artist.name
|
||||||
elif name == "album_artist":
|
elif name == "album_artist":
|
||||||
return name_builder_album_artist(media, first_only=True)
|
return name_builder_album_artist(media, first_only=True)
|
||||||
elif name == "album_artists":
|
elif name == "album_artists":
|
||||||
return name_builder_album_artist(media)
|
return name_builder_album_artist(media, delimiter=delimiter_album_artist)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@@ -208,20 +250,28 @@ def _format_titles(
|
|||||||
def _format_names(
|
def _format_names(
|
||||||
name: str,
|
name: str,
|
||||||
media: Track | Album | Playlist | UserPlaylist | Video | Mix,
|
media: Track | Album | Playlist | UserPlaylist | Video | Mix,
|
||||||
*_args,
|
*args,
|
||||||
|
delimiter_artist: str = ", ",
|
||||||
|
delimiter_album_artist: str = ", ",
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
"""Handle name-related format strings.
|
"""Handles name-related format strings for media.
|
||||||
|
|
||||||
|
Tries to format the provided name as an artist or title, returning the first matching result.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
name (str): The format string name to check.
|
name (str): The format string name to check.
|
||||||
media (Track | Album | Playlist | UserPlaylist | Video | Mix): The media object to extract name information from.
|
media (Track | Album | Playlist | UserPlaylist | Video | Mix): The media object to extract name information from.
|
||||||
*_args (Any): Additional arguments (not used).
|
*args: Additional arguments (not used).
|
||||||
|
delimiter_artist (str, optional): Delimiter for artist names. Defaults to ", ".
|
||||||
|
delimiter_album_artist (str, optional): Delimiter for album artist names. Defaults to ", ".
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
str | None: The formatted name or None if the format string is not name-related.
|
str | None: The formatted name or None if the format string is not name-related.
|
||||||
"""
|
"""
|
||||||
# First try artist name formats
|
# First try artist name formats
|
||||||
result = _format_artist_names(name, media)
|
result = _format_artist_names(
|
||||||
|
name, media, delimiter_artist=delimiter_artist, delimiter_album_artist=delimiter_album_artist
|
||||||
|
)
|
||||||
if result is not None:
|
if result is not None:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -10,11 +10,34 @@ from tidal_dl_ng.constants import FAVORITES, MediaType
|
|||||||
from tidal_dl_ng.helper.exceptions import MediaUnknown
|
from tidal_dl_ng.helper.exceptions import MediaUnknown
|
||||||
|
|
||||||
|
|
||||||
def name_builder_artist(media: Track | Video | Album, delimiter: str = "; ") -> str:
|
def name_builder_artist(media: Track | Video | Album, delimiter: str = ", ") -> str:
|
||||||
|
"""Builds a string of artist names for a track, video, or album.
|
||||||
|
|
||||||
|
Returns a delimited string of all artist names associated with the given media.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
media (Track | Video | Album): The media object to extract artist names from.
|
||||||
|
delimiter (str, optional): The delimiter to use between artist names. Defaults to ", ".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A delimited string of artist names.
|
||||||
|
"""
|
||||||
return delimiter.join(artist.name for artist in media.artists)
|
return delimiter.join(artist.name for artist in media.artists)
|
||||||
|
|
||||||
|
|
||||||
def name_builder_album_artist(media: Track | Album, first_only: bool = False, delimiter: str = "; ") -> str:
|
def name_builder_album_artist(media: Track | Album, first_only: bool = False, delimiter: str = ", ") -> str:
|
||||||
|
"""Builds a string of main album artist names for a track or album.
|
||||||
|
|
||||||
|
Returns a delimited string of main artist names from the album, optionally including only the first main artist.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
media (Track | Album): The media object to extract artist names from.
|
||||||
|
first_only (bool, optional): If True, only the first main artist is included. Defaults to False.
|
||||||
|
delimiter (str, optional): The delimiter to use between artist names. Defaults to ", ".
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: A delimited string of main album artist names.
|
||||||
|
"""
|
||||||
artists_tmp: [str] = []
|
artists_tmp: [str] = []
|
||||||
artists: [Artist] = media.album.artists if isinstance(media, Track) else media.artists
|
artists: [Artist] = media.album.artists if isinstance(media, Track) else media.artists
|
||||||
|
|
||||||
|
|||||||
@@ -50,8 +50,10 @@ class Settings:
|
|||||||
window_y: int = 50
|
window_y: int = 50
|
||||||
window_w: int = 1200
|
window_w: int = 1200
|
||||||
window_h: int = 800
|
window_h: int = 800
|
||||||
metadata_delimiter_artist: str = "; "
|
metadata_delimiter_artist: str = ", "
|
||||||
metadata_delimiter_album_artist: str = "; "
|
metadata_delimiter_album_artist: str = ", "
|
||||||
|
filename_delimiter_artist: str = ", "
|
||||||
|
filename_delimiter_album_artist: str = ", "
|
||||||
|
|
||||||
|
|
||||||
@dataclass_json
|
@dataclass_json
|
||||||
@@ -111,8 +113,10 @@ class HelpSettings:
|
|||||||
window_y: str = "Y-Coordinate of saved window location."
|
window_y: str = "Y-Coordinate of saved window location."
|
||||||
window_w: str = "Width of saved window size."
|
window_w: str = "Width of saved window size."
|
||||||
window_h: str = "Height of saved window size."
|
window_h: str = "Height of saved window size."
|
||||||
metadata_delimiter_artist: str = "Metadata tag delimiter for multiple artists. Default: '; '"
|
metadata_delimiter_artist: str = "Metadata tag delimiter for multiple artists. Default: ', '"
|
||||||
metadata_delimiter_album_artist: str = "Metadata tag delimiter for multiple album artists. Default: '; '"
|
metadata_delimiter_album_artist: str = "Metadata tag delimiter for multiple album artists. Default: ', '"
|
||||||
|
filename_delimiter_artist: str = "Filename delimiter for multiple artists. Default: ', '"
|
||||||
|
filename_delimiter_album_artist: str = "Filename delimiter for multiple album artists. Default: ', '"
|
||||||
|
|
||||||
|
|
||||||
@dataclass_json
|
@dataclass_json
|
||||||
|
|||||||
Reference in New Issue
Block a user