clean format function improved, config updates

This commit is contained in:
nathannathant 2021-03-01 17:56:52 -08:00
parent 0d02292823
commit 3affd97916
3 changed files with 77 additions and 56 deletions

View File

@ -101,8 +101,20 @@ def main():
no_cover = config.getboolean("DEFAULT", "no_cover") no_cover = config.getboolean("DEFAULT", "no_cover")
no_database = config.getboolean("DEFAULT", "no_database") no_database = config.getboolean("DEFAULT", "no_database")
app_id = config["DEFAULT"]["app_id"] app_id = config["DEFAULT"]["app_id"]
if ("folder_format" not in config["DEFAULT"]
or "track_format" not in config["DEFAULT"]):
logging.info(f'{YELLOW}Config file does not include format string,'
' updating...')
config["DEFAULT"]["folder_format"] = "{artist} - {album} ({year}) "
"[{bit_depth}B-{sampling_rate}kHz]"
config["DEFAULT"]["track_format"] = "{tracknumber}. {tracktitle}"
with open(CONFIG_FILE, 'w') as cf:
config.write(cf)
folder_format = config["DEFAULT"]["folder_format"] folder_format = config["DEFAULT"]["folder_format"]
track_format = config["DEFAULT"]["track_format"] track_format = config["DEFAULT"]["track_format"]
secrets = [ secrets = [
secret for secret in config["DEFAULT"]["secrets"].split(",") if secret secret for secret in config["DEFAULT"]["secrets"].split(",") if secret
] ]
@ -137,9 +149,9 @@ def main():
no_cover=arguments.no_cover or no_cover, no_cover=arguments.no_cover or no_cover,
downloads_db=None if no_database or arguments.no_db else QOBUZ_DB, downloads_db=None if no_database or arguments.no_db else QOBUZ_DB,
folder_format=arguments.folder_format folder_format=arguments.folder_format
if hasattr(arguments, "folder_format") else folder_format, if arguments.folder_format is not None else folder_format,
track_format=arguments.track_format track_format=arguments.track_format
if hasattr(arguments, "track_format") else track_format, if arguments.track_format is not None else track_format,
) )
qobuz.initialize_client(email, password, app_id, secrets) qobuz.initialize_client(email, password, app_id, secrets)

View File

@ -108,7 +108,7 @@ def add_common_arg(custom_parser, default_folder, default_quality):
metavar='PATTERN', metavar='PATTERN',
help='pattern for formatting folder names, e.g ' help='pattern for formatting folder names, e.g '
'"{artist} - {album} ({year})". available keys: artist, ' '"{artist} - {album} ({year})". available keys: artist, '
'album, year, sampling_rate, bit_rate, tracktitle. ' 'albumartist, album, year, sampling_rate, bit_rate, tracktitle. '
'cannot contain characters used by the system, which includes /:<>', 'cannot contain characters used by the system, which includes /:<>',
) )
custom_parser.add_argument( custom_parser.add_argument(

View File

@ -11,10 +11,17 @@ from qobuz_dl.color import OFF, GREEN, RED, YELLOW, CYAN
from qobuz_dl.exceptions import NonStreamable from qobuz_dl.exceptions import NonStreamable
QL_DOWNGRADE = "FormatRestrictedByFormatAvailability" QL_DOWNGRADE = "FormatRestrictedByFormatAvailability"
DEFAULT_MP3_FOLDER_FORMAT = '{artist} - {album} [MP3]' # used in case of error
DEFAULT_MP3_TRACK_FORMAT = '{tracknumber}. {tracktitle}' DEFAULT_FORMATS = {
DEFAULT_UNKNOWN_FOLDER_FORMAT = '{artist} - {album}' 'MP3': [
DEFAULT_UNKNOWN_TRACK_FORMAT = '{tracknumber}. {tracktitle}' '{artist} - {album} ({year}) [MP3]',
'{tracknumber}. {tracktitle}',
],
'Unknown': [
'{artist} - {album}',
'{tracknumber}. {tracktitle}',
]
}
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -145,15 +152,16 @@ def download_and_tag(
filename = os.path.join(root_dir, f".{tmp_count:02}.tmp") filename = os.path.join(root_dir, f".{tmp_count:02}.tmp")
# Determine the filename # Determine the filename
track_title = track_metadata["title"] track_title = track_metadata.get("title")
print(track_metadata) artist = _safe_get(track_metadata, "performer", "name")
filename_attr = { filename_attr = {
'artist': track_metadata["performer"]["name"], 'artist': artist,
'albumartist': track_metadata["album"]["artist"]["name"], 'albumartist': _safe_get(track_metadata, "album", "artist", "name",
default=artist),
'bit_depth': track_metadata['maximum_bit_depth'], 'bit_depth': track_metadata['maximum_bit_depth'],
'sampling_rate': track_metadata['maximum_sampling_rate'], 'sampling_rate': track_metadata['maximum_sampling_rate'],
'tracktitle': track_title, 'tracktitle': track_title,
'version': track_metadata["version"], 'version': track_metadata.get("version"),
'tracknumber': f"{track_metadata['track_number']:02}" 'tracknumber': f"{track_metadata['track_number']:02}"
} }
# track_format is a format string # track_format is a format string
@ -250,9 +258,9 @@ def download_id_by_type(
'bit_depth': bit_depth, 'bit_depth': bit_depth,
'sampling_rate': sampling_rate 'sampling_rate': sampling_rate
} }
folder_format, track_format = clean_format_str(folder_format, folder_format, track_format = _clean_format_str(folder_format,
track_format, track_format,
file_format) file_format)
sanitized_title = sanitize_filename( sanitized_title = sanitize_filename(
folder_format.format(**album_attr) folder_format.format(**album_attr)
) )
@ -303,9 +311,9 @@ def download_id_by_type(
is_track_id=True, track_url_dict=parse) is_track_id=True, track_url_dict=parse)
file_format, quality_met, bit_depth, sampling_rate = format_info file_format, quality_met, bit_depth, sampling_rate = format_info
folder_format, track_format = clean_format_str(folder_format, folder_format, track_format = _clean_format_str(folder_format,
track_format, track_format,
bit_depth) bit_depth)
if not downgrade_quality and not quality_met: if not downgrade_quality and not quality_met:
logger.info( logger.info(
@ -342,45 +350,46 @@ def download_id_by_type(
# ----------- Utilities ----------- # ----------- Utilities -----------
def _clean_format_gen(s: str) -> str:
'''General clean for format strings. Avoids user errors.
'''
if s.endswith('.mp3'):
s = s[:-4]
elif s.endswith('.flac'):
s = s[:-5]
s = s.strip()
return s
def _clean_format_str(folder: str, track: str,
def _not_mp3_valid(s: str) -> bool: file_format: str) -> Tuple[str, str]:
return 'bit_depth' in s or 'sample_rate' in s '''Cleans up the format strings, avoids errors
def clean_format_str(folder: str, track: str,
file_format: str) -> Tuple[str, str]:
'''Cleans up the format strings to avoid errors
with MP3 files. with MP3 files.
''' '''
folder = _clean_format_gen(folder) final = []
track = _clean_format_gen(track) for i, fs in enumerate((folder, track)):
if file_format == 'MP3': if fs.endswith('.mp3'):
if _not_mp3_valid(folder): fs = fs[:-4]
logger.error(f'{RED}invalid format string for MP3: "{folder}"' elif fs.endswith('.flac'):
f'\ndefaulting to "{DEFAULT_MP3_FOLDER_FORMAT}"') fs = fs[:-5]
folder = DEFAULT_MP3_FOLDER_FORMAT fs = fs.strip()
if _not_mp3_valid(track):
logger.error(f'{RED}invalid format string for MP3: "{track}"'
f'\ndefaulting to "{DEFAULT_MP3_TRACK_FORMAT}"')
track = DEFAULT_MP3_TRACK_FORMAT
elif file_format == 'Unknown':
if _not_mp3_valid(folder):
logger.error(f'{RED}Error getting format. Defaulting format '
f'string to "{DEFAULT_UNKNOWN_FOLDER_FORMAT}"')
folder = DEFAULT_UNKNOWN_FOLDER_FORMAT
if _not_mp3_valid(track):
logger.error(f'{RED}Error getting format. Defaulting format '
f'string to "{DEFAULT_UNKNOWN_TRACK_FORMAT}"')
track = DEFAULT_UNKNOWN_TRACK_FORMAT
return (folder, track) # default to pre-chosen string if format is invalid
if (file_format in ('MP3', 'Unknown') and
'bit_depth' in file_format or 'sampling_rate' in file_format):
default = DEFAULT_FORMATS[file_format][i]
logger.error(f'{RED}invalid format string for format {file_format}'
f'. defaulting to {default}')
fs = default
final.append(fs)
return tuple(final)
def _safe_get(d: dict, *keys, default=None):
'''A replacement for chained `get()` statements on dicts:
>>> d = {'foo': {'bar': 'baz'}}
>>> _safe_get(d, 'baz')
None
>>> _safe_get(d, 'foo', 'bar')
'baz'
'''
curr = d
res = default
for key in keys:
res = curr.get(key, default)
if res == default or not hasattr(res, '__getitem__'):
return res
else:
curr = res
return res