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_database = config.getboolean("DEFAULT", "no_database")
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"]
track_format = config["DEFAULT"]["track_format"]
secrets = [
secret for secret in config["DEFAULT"]["secrets"].split(",") if secret
]
@ -137,9 +149,9 @@ def main():
no_cover=arguments.no_cover or no_cover,
downloads_db=None if no_database or arguments.no_db else QOBUZ_DB,
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
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)

View File

@ -108,7 +108,7 @@ def add_common_arg(custom_parser, default_folder, default_quality):
metavar='PATTERN',
help='pattern for formatting folder names, e.g '
'"{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 /:<>',
)
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
QL_DOWNGRADE = "FormatRestrictedByFormatAvailability"
DEFAULT_MP3_FOLDER_FORMAT = '{artist} - {album} [MP3]'
DEFAULT_MP3_TRACK_FORMAT = '{tracknumber}. {tracktitle}'
DEFAULT_UNKNOWN_FOLDER_FORMAT = '{artist} - {album}'
DEFAULT_UNKNOWN_TRACK_FORMAT = '{tracknumber}. {tracktitle}'
# used in case of error
DEFAULT_FORMATS = {
'MP3': [
'{artist} - {album} ({year}) [MP3]',
'{tracknumber}. {tracktitle}',
],
'Unknown': [
'{artist} - {album}',
'{tracknumber}. {tracktitle}',
]
}
logger = logging.getLogger(__name__)
@ -145,15 +152,16 @@ def download_and_tag(
filename = os.path.join(root_dir, f".{tmp_count:02}.tmp")
# Determine the filename
track_title = track_metadata["title"]
print(track_metadata)
track_title = track_metadata.get("title")
artist = _safe_get(track_metadata, "performer", "name")
filename_attr = {
'artist': track_metadata["performer"]["name"],
'albumartist': track_metadata["album"]["artist"]["name"],
'artist': artist,
'albumartist': _safe_get(track_metadata, "album", "artist", "name",
default=artist),
'bit_depth': track_metadata['maximum_bit_depth'],
'sampling_rate': track_metadata['maximum_sampling_rate'],
'tracktitle': track_title,
'version': track_metadata["version"],
'version': track_metadata.get("version"),
'tracknumber': f"{track_metadata['track_number']:02}"
}
# track_format is a format string
@ -250,9 +258,9 @@ def download_id_by_type(
'bit_depth': bit_depth,
'sampling_rate': sampling_rate
}
folder_format, track_format = clean_format_str(folder_format,
track_format,
file_format)
folder_format, track_format = _clean_format_str(folder_format,
track_format,
file_format)
sanitized_title = sanitize_filename(
folder_format.format(**album_attr)
)
@ -303,9 +311,9 @@ def download_id_by_type(
is_track_id=True, track_url_dict=parse)
file_format, quality_met, bit_depth, sampling_rate = format_info
folder_format, track_format = clean_format_str(folder_format,
track_format,
bit_depth)
folder_format, track_format = _clean_format_str(folder_format,
track_format,
bit_depth)
if not downgrade_quality and not quality_met:
logger.info(
@ -342,45 +350,46 @@ def download_id_by_type(
# ----------- 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 _not_mp3_valid(s: str) -> bool:
return 'bit_depth' in s or 'sample_rate' in s
def clean_format_str(folder: str, track: str,
file_format: str) -> Tuple[str, str]:
'''Cleans up the format strings to avoid errors
def _clean_format_str(folder: str, track: str,
file_format: str) -> Tuple[str, str]:
'''Cleans up the format strings, avoids errors
with MP3 files.
'''
folder = _clean_format_gen(folder)
track = _clean_format_gen(track)
if file_format == 'MP3':
if _not_mp3_valid(folder):
logger.error(f'{RED}invalid format string for MP3: "{folder}"'
f'\ndefaulting to "{DEFAULT_MP3_FOLDER_FORMAT}"')
folder = DEFAULT_MP3_FOLDER_FORMAT
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
final = []
for i, fs in enumerate((folder, track)):
if fs.endswith('.mp3'):
fs = fs[:-4]
elif fs.endswith('.flac'):
fs = fs[:-5]
fs = fs.strip()
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