diff --git a/streamrip/bases.py b/streamrip/bases.py index a901047..11e44b6 100644 --- a/streamrip/bases.py +++ b/streamrip/bases.py @@ -23,7 +23,7 @@ from pathvalidate import sanitize_filepath from . import converter from .clients import Client -from .constants import FLAC_MAX_BLOCKSIZE, TRACK_FORMAT +from .constants import FLAC_MAX_BLOCKSIZE, TRACK_FORMAT, FOLDER_FORMAT from .exceptions import ( InvalidQuality, InvalidSourceError, @@ -146,7 +146,17 @@ class Track: self.folder = kwargs["parent_folder"] or self.folder + if kwargs["add_singles_to_folder"]: + self.folder = os.path.join( + self.folder, + clean_format( + kwargs.get("folder_format", FOLDER_FORMAT), + self.meta.get_album_formatter(self.quality), + ), + ) + self.file_format = kwargs.get("track_format", TRACK_FORMAT) + self.folder = sanitize_filepath(self.folder, platform="auto") self.format_final_path() diff --git a/streamrip/config.py b/streamrip/config.py index bbd48e9..d840324 100644 --- a/streamrip/config.py +++ b/streamrip/config.py @@ -56,7 +56,10 @@ class Config: if os.path.isfile(self._path): self.load() if self.file["misc"]["version"] != self.defaults["misc"]["version"]: - click.secho("Updating config file to new version. Some settings may be lost.", fg="yellow") + click.secho( + "Updating config file to new version. Some settings may be lost.", + fg="yellow", + ) self.update() self.load() else: diff --git a/streamrip/config.toml b/streamrip/config.toml index 3dab50a..3c38224 100644 --- a/streamrip/config.toml +++ b/streamrip/config.toml @@ -105,12 +105,15 @@ set_playlist_to_album = true new_playlist_tracknumbers = true # Changes the folder and file names generated by streamrip. -[path_format] +[filepaths] +# Create folders for single tracks within the downloads directory using the folder_format +# template +add_singles_to_folder = false # Available keys: "albumartist", "title", "year", "bit_depth", "sampling_rate", # and "container" -folder = "{albumartist} - {title} ({year}) [{container}] [{bit_depth}B-{sampling_rate}kHz]" +folder_format = "{albumartist} - {title} ({year}) [{container}] [{bit_depth}B-{sampling_rate}kHz]" # Available keys: "tracknumber", "artist", "albumartist", "composer", and "title" -track = "{tracknumber}. {artist} - {title}" +track_format = "{tracknumber}. {artist} - {title}" # Last.fm playlists are downloaded by searching for the titles of the tracks [lastfm] @@ -125,4 +128,4 @@ fallback_source = "deezer" check_for_updates = true # Metadata to identify this config file. Do not change. -version = "0.6" +version = "0.6.1" diff --git a/streamrip/core.py b/streamrip/core.py index c8672b4..5cd8b28 100644 --- a/streamrip/core.py +++ b/streamrip/core.py @@ -175,32 +175,32 @@ class MusicDL(list): :rtype: dict """ - logger.debug(self.config.session) + session = self.config.session + logger.debug(session) + # So that the dictionary isn't searched for the same keys multiple times + artwork, conversion, filepaths = tuple( + session[key] for key in ("artwork", "conversion", "filepaths") + ) return { "database": self.db, - "parent_folder": self.config.session["downloads"]["folder"], - "folder_format": self.config.session["path_format"]["folder"], - "track_format": self.config.session["path_format"]["track"], - "embed_cover": self.config.session["artwork"]["embed"], - "embed_cover_size": self.config.session["artwork"]["size"], - "keep_hires_cover": self.config.session["artwork"]["keep_hires_cover"], - "set_playlist_to_album": self.config.session["metadata"][ - "set_playlist_to_album" - ], - "stay_temp": self.config.session["conversion"]["enabled"], - "conversion": self.config.session["conversion"], - "concurrent_downloads": self.config.session["downloads"]["concurrent"], - "new_tracknumbers": self.config.session["metadata"][ - "new_playlist_tracknumbers" - ], - "download_videos": self.config.session["tidal"]["download_videos"], - "download_booklets": self.config.session["qobuz"]["download_booklets"], - "download_youtube_videos": self.config.session["youtube"][ - "download_videos" - ], - "youtube_video_downloads_folder": self.config.session["youtube"][ + "parent_folder": session["downloads"]["folder"], + "folder_format": filepaths["folder_format"], + "track_format": filepaths["track_format"], + "embed_cover": session["artwork"]["embed"], + "embed_cover_size": artwork["size"], + "keep_hires_cover": artwork["keep_hires_cover"], + "set_playlist_to_album": session["metadata"]["set_playlist_to_album"], + "stay_temp": conversion["enabled"], + "conversion": conversion, + "concurrent_downloads": session["downloads"]["concurrent"], + "new_tracknumbers": session["metadata"]["new_playlist_tracknumbers"], + "download_videos": session["tidal"]["download_videos"], + "download_booklets": session["qobuz"]["download_booklets"], + "download_youtube_videos": session["youtube"]["download_videos"], + "youtube_video_downloads_folder": session["youtube"][ "video_downloads_folder" ], + "add_singles_to_folder": filepaths["add_singles_to_folder"], } def download(self): diff --git a/streamrip/metadata.py b/streamrip/metadata.py index 990f9d6..f65fa4c 100644 --- a/streamrip/metadata.py +++ b/streamrip/metadata.py @@ -16,6 +16,7 @@ from .constants import ( PHON_COPYRIGHT, TIDAL_Q_MAP, TRACK_KEYS, + ALBUM_KEYS, ) from .exceptions import InvalidContainerError, InvalidSourceError from .utils import get_quality_id, safe_get, tidal_cover_url @@ -436,6 +437,18 @@ class TrackMetadata: # the keys in the tuple are the possible keys for format strings return {k: getattr(self, k) for k in TRACK_KEYS} + def get_album_formatter(self, max_quality: int) -> dict: + """Return a dict that is used to apply values to file format strings. + + :param max_quality: + :type max_quality: int + :rtype: dict + """ + formatter = {k: self.get(k) for k in ALBUM_KEYS} + formatter["container"] = "FLAC" if max_quality >= 2 else "MP3" + formatter["sampling_rate"] /= 1000 + return formatter + def tags(self, container: str = "flac") -> Generator: """Create a generator of key, value pairs for use with mutagen.