mirror of
https://github.com/beetbox/beets.git
synced 2025-12-06 08:39:17 +01:00
Do not use explicit indices for logging args when not needed
This commit is contained in:
parent
2fccf64efe
commit
d93ddf8dd4
56 changed files with 297 additions and 305 deletions
|
|
@ -261,7 +261,7 @@ There are a few coding conventions we use in beets:
|
||||||
|
|
||||||
- The loggers use `str.format
|
- The loggers use `str.format
|
||||||
<http://docs.python.org/library/stdtypes.html#str.format>`__-style logging
|
<http://docs.python.org/library/stdtypes.html#str.format>`__-style logging
|
||||||
instead of ``%``-style, so you can type ``log.debug("{0}", obj)`` to do your
|
instead of ``%``-style, so you can type ``log.debug("{}", obj)`` to do your
|
||||||
formatting.
|
formatting.
|
||||||
|
|
||||||
- Exception handlers must use ``except A as B:`` instead of ``except A, B:``.
|
- Exception handlers must use ``except A as B:`` instead of ``except A, B:``.
|
||||||
|
|
|
||||||
24
beets/art.py
24
beets/art.py
|
|
@ -39,7 +39,7 @@ def get_art(log, item):
|
||||||
mf = mediafile.MediaFile(syspath(item.path))
|
mf = mediafile.MediaFile(syspath(item.path))
|
||||||
except mediafile.UnreadableFileError as exc:
|
except mediafile.UnreadableFileError as exc:
|
||||||
log.warning(
|
log.warning(
|
||||||
"Could not extract art from {0}: {1}",
|
"Could not extract art from {}: {}",
|
||||||
displayable_path(item.path),
|
displayable_path(item.path),
|
||||||
exc,
|
exc,
|
||||||
)
|
)
|
||||||
|
|
@ -83,10 +83,10 @@ def embed_item(
|
||||||
|
|
||||||
# Get the `Image` object from the file.
|
# Get the `Image` object from the file.
|
||||||
try:
|
try:
|
||||||
log.debug("embedding {0}", displayable_path(imagepath))
|
log.debug("embedding {}", displayable_path(imagepath))
|
||||||
image = mediafile_image(imagepath, maxwidth)
|
image = mediafile_image(imagepath, maxwidth)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
log.warning("could not read image file: {0}", exc)
|
log.warning("could not read image file: {}", exc)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Make sure the image kind is safe (some formats only support PNG
|
# Make sure the image kind is safe (some formats only support PNG
|
||||||
|
|
@ -110,11 +110,11 @@ def embed_album(
|
||||||
"""Embed album art into all of the album's items."""
|
"""Embed album art into all of the album's items."""
|
||||||
imagepath = album.artpath
|
imagepath = album.artpath
|
||||||
if not imagepath:
|
if not imagepath:
|
||||||
log.info("No album art present for {0}", album)
|
log.info("No album art present for {}", album)
|
||||||
return
|
return
|
||||||
if not os.path.isfile(syspath(imagepath)):
|
if not os.path.isfile(syspath(imagepath)):
|
||||||
log.info(
|
log.info(
|
||||||
"Album art not found at {0} for {1}",
|
"Album art not found at {} for {}",
|
||||||
displayable_path(imagepath),
|
displayable_path(imagepath),
|
||||||
album,
|
album,
|
||||||
)
|
)
|
||||||
|
|
@ -122,7 +122,7 @@ def embed_album(
|
||||||
if maxwidth:
|
if maxwidth:
|
||||||
imagepath = resize_image(log, imagepath, maxwidth, quality)
|
imagepath = resize_image(log, imagepath, maxwidth, quality)
|
||||||
|
|
||||||
log.info("Embedding album art into {0}", album)
|
log.info("Embedding album art into {}", album)
|
||||||
|
|
||||||
for item in album.items():
|
for item in album.items():
|
||||||
embed_item(
|
embed_item(
|
||||||
|
|
@ -143,7 +143,7 @@ def resize_image(log, imagepath, maxwidth, quality):
|
||||||
specified quality level.
|
specified quality level.
|
||||||
"""
|
"""
|
||||||
log.debug(
|
log.debug(
|
||||||
"Resizing album art to {0} pixels wide and encoding at quality level {1}",
|
"Resizing album art to {} pixels wide and encoding at quality level {}",
|
||||||
maxwidth,
|
maxwidth,
|
||||||
quality,
|
quality,
|
||||||
)
|
)
|
||||||
|
|
@ -183,18 +183,18 @@ def extract(log, outpath, item):
|
||||||
art = get_art(log, item)
|
art = get_art(log, item)
|
||||||
outpath = bytestring_path(outpath)
|
outpath = bytestring_path(outpath)
|
||||||
if not art:
|
if not art:
|
||||||
log.info("No album art present in {0}, skipping.", item)
|
log.info("No album art present in {}, skipping.", item)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Add an extension to the filename.
|
# Add an extension to the filename.
|
||||||
ext = mediafile.image_extension(art)
|
ext = mediafile.image_extension(art)
|
||||||
if not ext:
|
if not ext:
|
||||||
log.warning("Unknown image type in {0}.", displayable_path(item.path))
|
log.warning("Unknown image type in {}.", displayable_path(item.path))
|
||||||
return
|
return
|
||||||
outpath += bytestring_path(f".{ext}")
|
outpath += bytestring_path(f".{ext}")
|
||||||
|
|
||||||
log.info(
|
log.info(
|
||||||
"Extracting album art from: {0} to: {1}",
|
"Extracting album art from: {} to: {}",
|
||||||
item,
|
item,
|
||||||
displayable_path(outpath),
|
displayable_path(outpath),
|
||||||
)
|
)
|
||||||
|
|
@ -212,7 +212,7 @@ def extract_first(log, outpath, items):
|
||||||
|
|
||||||
def clear(log, lib, query):
|
def clear(log, lib, query):
|
||||||
items = lib.items(query)
|
items = lib.items(query)
|
||||||
log.info("Clearing album art from {0} items", len(items))
|
log.info("Clearing album art from {} items", len(items))
|
||||||
for item in items:
|
for item in items:
|
||||||
log.debug("Clearing art for {0}", item)
|
log.debug("Clearing art for {}", item)
|
||||||
item.try_write(tags={"images": None})
|
item.try_write(tags={"images": None})
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,7 @@ def match_by_id(items: Iterable[Item]) -> AlbumInfo | None:
|
||||||
log.debug("No album ID consensus.")
|
log.debug("No album ID consensus.")
|
||||||
return None
|
return None
|
||||||
# If all album IDs are equal, look up the album.
|
# If all album IDs are equal, look up the album.
|
||||||
log.debug("Searching for discovered album ID: {0}", first)
|
log.debug("Searching for discovered album ID: {}", first)
|
||||||
return metadata_plugins.album_for_id(first)
|
return metadata_plugins.album_for_id(first)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -197,9 +197,7 @@ def _add_candidate(
|
||||||
checking the track count, ordering the items, checking for
|
checking the track count, ordering the items, checking for
|
||||||
duplicates, and calculating the distance.
|
duplicates, and calculating the distance.
|
||||||
"""
|
"""
|
||||||
log.debug(
|
log.debug("Candidate: {} - {} ({})", info.artist, info.album, info.album_id)
|
||||||
"Candidate: {0} - {1} ({2})", info.artist, info.album, info.album_id
|
|
||||||
)
|
|
||||||
|
|
||||||
# Discard albums with zero tracks.
|
# Discard albums with zero tracks.
|
||||||
if not info.tracks:
|
if not info.tracks:
|
||||||
|
|
@ -215,7 +213,7 @@ def _add_candidate(
|
||||||
required_tags: Sequence[str] = config["match"]["required"].as_str_seq()
|
required_tags: Sequence[str] = config["match"]["required"].as_str_seq()
|
||||||
for req_tag in required_tags:
|
for req_tag in required_tags:
|
||||||
if getattr(info, req_tag) is None:
|
if getattr(info, req_tag) is None:
|
||||||
log.debug("Ignored. Missing required tag: {0}", req_tag)
|
log.debug("Ignored. Missing required tag: {}", req_tag)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Find mapping between the items and the track info.
|
# Find mapping between the items and the track info.
|
||||||
|
|
@ -229,10 +227,10 @@ def _add_candidate(
|
||||||
ignored_tags: Sequence[str] = config["match"]["ignored"].as_str_seq()
|
ignored_tags: Sequence[str] = config["match"]["ignored"].as_str_seq()
|
||||||
for penalty in ignored_tags:
|
for penalty in ignored_tags:
|
||||||
if penalty in penalties:
|
if penalty in penalties:
|
||||||
log.debug("Ignored. Penalty: {0}", penalty)
|
log.debug("Ignored. Penalty: {}", penalty)
|
||||||
return
|
return
|
||||||
|
|
||||||
log.debug("Success. Distance: {0}", dist)
|
log.debug("Success. Distance: {}", dist)
|
||||||
results[info.album_id] = hooks.AlbumMatch(
|
results[info.album_id] = hooks.AlbumMatch(
|
||||||
dist, info, mapping, extra_items, extra_tracks
|
dist, info, mapping, extra_items, extra_tracks
|
||||||
)
|
)
|
||||||
|
|
@ -265,7 +263,7 @@ def tag_album(
|
||||||
likelies, consensus = get_most_common_tags(items)
|
likelies, consensus = get_most_common_tags(items)
|
||||||
cur_artist: str = likelies["artist"]
|
cur_artist: str = likelies["artist"]
|
||||||
cur_album: str = likelies["album"]
|
cur_album: str = likelies["album"]
|
||||||
log.debug("Tagging {0} - {1}", cur_artist, cur_album)
|
log.debug("Tagging {} - {}", cur_artist, cur_album)
|
||||||
|
|
||||||
# The output result, keys are the MB album ID.
|
# The output result, keys are the MB album ID.
|
||||||
candidates: dict[Any, AlbumMatch] = {}
|
candidates: dict[Any, AlbumMatch] = {}
|
||||||
|
|
@ -273,7 +271,7 @@ def tag_album(
|
||||||
# Search by explicit ID.
|
# Search by explicit ID.
|
||||||
if search_ids:
|
if search_ids:
|
||||||
for search_id in search_ids:
|
for search_id in search_ids:
|
||||||
log.debug("Searching for album ID: {0}", search_id)
|
log.debug("Searching for album ID: {}", search_id)
|
||||||
if info := metadata_plugins.album_for_id(search_id):
|
if info := metadata_plugins.album_for_id(search_id):
|
||||||
_add_candidate(items, candidates, info)
|
_add_candidate(items, candidates, info)
|
||||||
|
|
||||||
|
|
@ -283,7 +281,7 @@ def tag_album(
|
||||||
if info := match_by_id(items):
|
if info := match_by_id(items):
|
||||||
_add_candidate(items, candidates, info)
|
_add_candidate(items, candidates, info)
|
||||||
rec = _recommendation(list(candidates.values()))
|
rec = _recommendation(list(candidates.values()))
|
||||||
log.debug("Album ID match recommendation is {0}", rec)
|
log.debug("Album ID match recommendation is {}", rec)
|
||||||
if candidates and not config["import"]["timid"]:
|
if candidates and not config["import"]["timid"]:
|
||||||
# If we have a very good MBID match, return immediately.
|
# If we have a very good MBID match, return immediately.
|
||||||
# Otherwise, this match will compete against metadata-based
|
# Otherwise, this match will compete against metadata-based
|
||||||
|
|
@ -300,7 +298,7 @@ def tag_album(
|
||||||
if not (search_artist and search_album):
|
if not (search_artist and search_album):
|
||||||
# No explicit search terms -- use current metadata.
|
# No explicit search terms -- use current metadata.
|
||||||
search_artist, search_album = cur_artist, cur_album
|
search_artist, search_album = cur_artist, cur_album
|
||||||
log.debug("Search terms: {0} - {1}", search_artist, search_album)
|
log.debug("Search terms: {} - {}", search_artist, search_album)
|
||||||
|
|
||||||
# Is this album likely to be a "various artist" release?
|
# Is this album likely to be a "various artist" release?
|
||||||
va_likely = (
|
va_likely = (
|
||||||
|
|
@ -308,7 +306,7 @@ def tag_album(
|
||||||
or (search_artist.lower() in VA_ARTISTS)
|
or (search_artist.lower() in VA_ARTISTS)
|
||||||
or any(item.comp for item in items)
|
or any(item.comp for item in items)
|
||||||
)
|
)
|
||||||
log.debug("Album might be VA: {0}", va_likely)
|
log.debug("Album might be VA: {}", va_likely)
|
||||||
|
|
||||||
# Get the results from the data sources.
|
# Get the results from the data sources.
|
||||||
for matched_candidate in metadata_plugins.candidates(
|
for matched_candidate in metadata_plugins.candidates(
|
||||||
|
|
@ -316,7 +314,7 @@ def tag_album(
|
||||||
):
|
):
|
||||||
_add_candidate(items, candidates, matched_candidate)
|
_add_candidate(items, candidates, matched_candidate)
|
||||||
|
|
||||||
log.debug("Evaluating {0} candidates.", len(candidates))
|
log.debug("Evaluating {} candidates.", len(candidates))
|
||||||
# Sort and get the recommendation.
|
# Sort and get the recommendation.
|
||||||
candidates_sorted = _sort_candidates(candidates.values())
|
candidates_sorted = _sort_candidates(candidates.values())
|
||||||
rec = _recommendation(candidates_sorted)
|
rec = _recommendation(candidates_sorted)
|
||||||
|
|
@ -345,7 +343,7 @@ def tag_item(
|
||||||
trackids = search_ids or [t for t in [item.mb_trackid] if t]
|
trackids = search_ids or [t for t in [item.mb_trackid] if t]
|
||||||
if trackids:
|
if trackids:
|
||||||
for trackid in trackids:
|
for trackid in trackids:
|
||||||
log.debug("Searching for track ID: {0}", trackid)
|
log.debug("Searching for track ID: {}", trackid)
|
||||||
if info := metadata_plugins.track_for_id(trackid):
|
if info := metadata_plugins.track_for_id(trackid):
|
||||||
dist = track_distance(item, info, incl_artist=True)
|
dist = track_distance(item, info, incl_artist=True)
|
||||||
candidates[info.track_id] = hooks.TrackMatch(dist, info)
|
candidates[info.track_id] = hooks.TrackMatch(dist, info)
|
||||||
|
|
@ -369,7 +367,7 @@ def tag_item(
|
||||||
# Search terms.
|
# Search terms.
|
||||||
search_artist = search_artist or item.artist
|
search_artist = search_artist or item.artist
|
||||||
search_title = search_title or item.title
|
search_title = search_title or item.title
|
||||||
log.debug("Item search terms: {0} - {1}", search_artist, search_title)
|
log.debug("Item search terms: {} - {}", search_artist, search_title)
|
||||||
|
|
||||||
# Get and evaluate candidate metadata.
|
# Get and evaluate candidate metadata.
|
||||||
for track_info in metadata_plugins.item_candidates(
|
for track_info in metadata_plugins.item_candidates(
|
||||||
|
|
@ -379,7 +377,7 @@ def tag_item(
|
||||||
candidates[track_info.track_id] = hooks.TrackMatch(dist, track_info)
|
candidates[track_info.track_id] = hooks.TrackMatch(dist, track_info)
|
||||||
|
|
||||||
# Sort by distance and return with recommendation.
|
# Sort by distance and return with recommendation.
|
||||||
log.debug("Found {0} candidates.", len(candidates))
|
log.debug("Found {} candidates.", len(candidates))
|
||||||
candidates_sorted = _sort_candidates(candidates.values())
|
candidates_sorted = _sort_candidates(candidates.values())
|
||||||
rec = _recommendation(candidates_sorted)
|
rec = _recommendation(candidates_sorted)
|
||||||
return Proposal(candidates_sorted, rec)
|
return Proposal(candidates_sorted, rec)
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ class ImportSession:
|
||||||
"""Log a message about a given album to the importer log. The status
|
"""Log a message about a given album to the importer log. The status
|
||||||
should reflect the reason the album couldn't be tagged.
|
should reflect the reason the album couldn't be tagged.
|
||||||
"""
|
"""
|
||||||
self.logger.info("{0} {1}", status, displayable_path(paths))
|
self.logger.info("{} {}", status, displayable_path(paths))
|
||||||
|
|
||||||
def log_choice(self, task: ImportTask, duplicate=False):
|
def log_choice(self, task: ImportTask, duplicate=False):
|
||||||
"""Logs the task's current choice if it should be logged. If
|
"""Logs the task's current choice if it should be logged. If
|
||||||
|
|
@ -187,7 +187,7 @@ class ImportSession:
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
"""Run the import task."""
|
"""Run the import task."""
|
||||||
self.logger.info("import started {0}", time.asctime())
|
self.logger.info("import started {}", time.asctime())
|
||||||
self.set_config(config["import"])
|
self.set_config(config["import"])
|
||||||
|
|
||||||
# Set up the pipeline.
|
# Set up the pipeline.
|
||||||
|
|
@ -297,7 +297,7 @@ class ImportSession:
|
||||||
# Either accept immediately or prompt for input to decide.
|
# Either accept immediately or prompt for input to decide.
|
||||||
if self.want_resume is True or self.should_resume(toppath):
|
if self.want_resume is True or self.should_resume(toppath):
|
||||||
log.warning(
|
log.warning(
|
||||||
"Resuming interrupted import of {0}",
|
"Resuming interrupted import of {}",
|
||||||
util.displayable_path(toppath),
|
util.displayable_path(toppath),
|
||||||
)
|
)
|
||||||
self._is_resuming[toppath] = True
|
self._is_resuming[toppath] = True
|
||||||
|
|
|
||||||
|
|
@ -58,11 +58,11 @@ def read_tasks(session: ImportSession):
|
||||||
skipped += task_factory.skipped
|
skipped += task_factory.skipped
|
||||||
|
|
||||||
if not task_factory.imported:
|
if not task_factory.imported:
|
||||||
log.warning("No files imported from {0}", displayable_path(toppath))
|
log.warning("No files imported from {}", displayable_path(toppath))
|
||||||
|
|
||||||
# Show skipped directories (due to incremental/resume).
|
# Show skipped directories (due to incremental/resume).
|
||||||
if skipped:
|
if skipped:
|
||||||
log.info("Skipped {0} paths.", skipped)
|
log.info("Skipped {} paths.", skipped)
|
||||||
|
|
||||||
|
|
||||||
def query_tasks(session: ImportSession):
|
def query_tasks(session: ImportSession):
|
||||||
|
|
@ -82,7 +82,7 @@ def query_tasks(session: ImportSession):
|
||||||
# Search for albums.
|
# Search for albums.
|
||||||
for album in session.lib.albums(session.query):
|
for album in session.lib.albums(session.query):
|
||||||
log.debug(
|
log.debug(
|
||||||
"yielding album {0}: {1} - {2}",
|
"yielding album {}: {} - {}",
|
||||||
album.id,
|
album.id,
|
||||||
album.albumartist,
|
album.albumartist,
|
||||||
album.album,
|
album.album,
|
||||||
|
|
@ -140,7 +140,7 @@ def lookup_candidates(session: ImportSession, task: ImportTask):
|
||||||
return
|
return
|
||||||
|
|
||||||
plugins.send("import_task_start", session=session, task=task)
|
plugins.send("import_task_start", session=session, task=task)
|
||||||
log.debug("Looking up: {0}", displayable_path(task.paths))
|
log.debug("Looking up: {}", displayable_path(task.paths))
|
||||||
|
|
||||||
# Restrict the initial lookup to IDs specified by the user via the -m
|
# Restrict the initial lookup to IDs specified by the user via the -m
|
||||||
# option. Currently all the IDs are passed onto the tasks directly.
|
# option. Currently all the IDs are passed onto the tasks directly.
|
||||||
|
|
@ -259,11 +259,11 @@ def plugin_stage(
|
||||||
def log_files(session: ImportSession, task: ImportTask):
|
def log_files(session: ImportSession, task: ImportTask):
|
||||||
"""A coroutine (pipeline stage) to log each file to be imported."""
|
"""A coroutine (pipeline stage) to log each file to be imported."""
|
||||||
if isinstance(task, SingletonImportTask):
|
if isinstance(task, SingletonImportTask):
|
||||||
log.info("Singleton: {0}", displayable_path(task.item["path"]))
|
log.info("Singleton: {}", displayable_path(task.item["path"]))
|
||||||
elif task.items:
|
elif task.items:
|
||||||
log.info("Album: {0}", displayable_path(task.paths[0]))
|
log.info("Album: {}", displayable_path(task.paths[0]))
|
||||||
for item in task.items:
|
for item in task.items:
|
||||||
log.info(" {0}", displayable_path(item["path"]))
|
log.info(" {}", displayable_path(item["path"]))
|
||||||
|
|
||||||
|
|
||||||
# --------------------------------- Consumer --------------------------------- #
|
# --------------------------------- Consumer --------------------------------- #
|
||||||
|
|
@ -353,7 +353,7 @@ def _resolve_duplicates(session: ImportSession, task: ImportTask):
|
||||||
"ask": "a",
|
"ask": "a",
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
log.debug("default action for duplicates: {0}", duplicate_action)
|
log.debug("default action for duplicates: {}", duplicate_action)
|
||||||
|
|
||||||
if duplicate_action == "s":
|
if duplicate_action == "s":
|
||||||
# Skip new.
|
# Skip new.
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ class ImportState:
|
||||||
# unpickling, including ImportError. We use a catch-all
|
# unpickling, including ImportError. We use a catch-all
|
||||||
# exception to avoid enumerating them all (the docs don't even have a
|
# exception to avoid enumerating them all (the docs don't even have a
|
||||||
# full list!).
|
# full list!).
|
||||||
log.debug("state file could not be read: {0}", exc)
|
log.debug("state file could not be read: {}", exc)
|
||||||
|
|
||||||
def _save(self):
|
def _save(self):
|
||||||
try:
|
try:
|
||||||
|
|
@ -100,7 +100,7 @@ class ImportState:
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
log.error("state file could not be written: {0}", exc)
|
log.error("state file could not be written: {}", exc)
|
||||||
|
|
||||||
# -------------------------------- Tagprogress ------------------------------- #
|
# -------------------------------- Tagprogress ------------------------------- #
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -267,12 +267,12 @@ class ImportTask(BaseImportTask):
|
||||||
|
|
||||||
def remove_duplicates(self, lib: library.Library):
|
def remove_duplicates(self, lib: library.Library):
|
||||||
duplicate_items = self.duplicate_items(lib)
|
duplicate_items = self.duplicate_items(lib)
|
||||||
log.debug("removing {0} old duplicated items", len(duplicate_items))
|
log.debug("removing {} old duplicated items", len(duplicate_items))
|
||||||
for item in duplicate_items:
|
for item in duplicate_items:
|
||||||
item.remove()
|
item.remove()
|
||||||
if lib.directory in util.ancestry(item.path):
|
if lib.directory in util.ancestry(item.path):
|
||||||
log.debug(
|
log.debug(
|
||||||
"deleting duplicate {0}", util.displayable_path(item.path)
|
"deleting duplicate {}", util.displayable_path(item.path)
|
||||||
)
|
)
|
||||||
util.remove(item.path)
|
util.remove(item.path)
|
||||||
util.prune_dirs(os.path.dirname(item.path), lib.directory)
|
util.prune_dirs(os.path.dirname(item.path), lib.directory)
|
||||||
|
|
@ -285,10 +285,10 @@ class ImportTask(BaseImportTask):
|
||||||
for field, view in config["import"]["set_fields"].items():
|
for field, view in config["import"]["set_fields"].items():
|
||||||
value = str(view.get())
|
value = str(view.get())
|
||||||
log.debug(
|
log.debug(
|
||||||
"Set field {1}={2} for {0}",
|
"Set field {}={} for {}",
|
||||||
util.displayable_path(self.paths),
|
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
|
util.displayable_path(self.paths),
|
||||||
)
|
)
|
||||||
self.album.set_parse(field, format(self.album, value))
|
self.album.set_parse(field, format(self.album, value))
|
||||||
for item in items:
|
for item in items:
|
||||||
|
|
@ -622,13 +622,13 @@ class ImportTask(BaseImportTask):
|
||||||
for item in self.imported_items():
|
for item in self.imported_items():
|
||||||
for dup_item in self.replaced_items[item]:
|
for dup_item in self.replaced_items[item]:
|
||||||
log.debug(
|
log.debug(
|
||||||
"Replacing item {0}: {1}",
|
"Replacing item {}: {}",
|
||||||
dup_item.id,
|
dup_item.id,
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
)
|
)
|
||||||
dup_item.remove()
|
dup_item.remove()
|
||||||
log.debug(
|
log.debug(
|
||||||
"{0} of {1} items replaced",
|
"{} of {} items replaced",
|
||||||
sum(bool(v) for v in self.replaced_items.values()),
|
sum(bool(v) for v in self.replaced_items.values()),
|
||||||
len(self.imported_items()),
|
len(self.imported_items()),
|
||||||
)
|
)
|
||||||
|
|
@ -747,10 +747,10 @@ class SingletonImportTask(ImportTask):
|
||||||
for field, view in config["import"]["set_fields"].items():
|
for field, view in config["import"]["set_fields"].items():
|
||||||
value = str(view.get())
|
value = str(view.get())
|
||||||
log.debug(
|
log.debug(
|
||||||
"Set field {1}={2} for {0}",
|
"Set field {}={} for {}",
|
||||||
util.displayable_path(self.paths),
|
|
||||||
field,
|
field,
|
||||||
value,
|
value,
|
||||||
|
util.displayable_path(self.paths),
|
||||||
)
|
)
|
||||||
self.item.set_parse(field, format(self.item, value))
|
self.item.set_parse(field, format(self.item, value))
|
||||||
self.item.store()
|
self.item.store()
|
||||||
|
|
@ -870,7 +870,7 @@ class ArchiveImportTask(SentinelImportTask):
|
||||||
"""Removes the temporary directory the archive was extracted to."""
|
"""Removes the temporary directory the archive was extracted to."""
|
||||||
if self.extracted and self.toppath:
|
if self.extracted and self.toppath:
|
||||||
log.debug(
|
log.debug(
|
||||||
"Removing extracted directory: {0}",
|
"Removing extracted directory: {}",
|
||||||
util.displayable_path(self.toppath),
|
util.displayable_path(self.toppath),
|
||||||
)
|
)
|
||||||
shutil.rmtree(util.syspath(self.toppath))
|
shutil.rmtree(util.syspath(self.toppath))
|
||||||
|
|
@ -1002,7 +1002,7 @@ class ImportTaskFactory:
|
||||||
"""Return a `SingletonImportTask` for the music file."""
|
"""Return a `SingletonImportTask` for the music file."""
|
||||||
if self.session.already_imported(self.toppath, [path]):
|
if self.session.already_imported(self.toppath, [path]):
|
||||||
log.debug(
|
log.debug(
|
||||||
"Skipping previously-imported path: {0}",
|
"Skipping previously-imported path: {}",
|
||||||
util.displayable_path(path),
|
util.displayable_path(path),
|
||||||
)
|
)
|
||||||
self.skipped += 1
|
self.skipped += 1
|
||||||
|
|
@ -1026,7 +1026,7 @@ class ImportTaskFactory:
|
||||||
|
|
||||||
if self.session.already_imported(self.toppath, dirs):
|
if self.session.already_imported(self.toppath, dirs):
|
||||||
log.debug(
|
log.debug(
|
||||||
"Skipping previously-imported path: {0}",
|
"Skipping previously-imported path: {}",
|
||||||
util.displayable_path(dirs),
|
util.displayable_path(dirs),
|
||||||
)
|
)
|
||||||
self.skipped += 1
|
self.skipped += 1
|
||||||
|
|
@ -1063,19 +1063,17 @@ class ImportTaskFactory:
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
log.debug(
|
log.debug("Extracting archive: {}", util.displayable_path(self.toppath))
|
||||||
"Extracting archive: {0}", util.displayable_path(self.toppath)
|
|
||||||
)
|
|
||||||
archive_task = ArchiveImportTask(self.toppath)
|
archive_task = ArchiveImportTask(self.toppath)
|
||||||
try:
|
try:
|
||||||
archive_task.extract()
|
archive_task.extract()
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
log.error("extraction failed: {0}", exc)
|
log.error("extraction failed: {}", exc)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Now read albums from the extracted directory.
|
# Now read albums from the extracted directory.
|
||||||
self.toppath = archive_task.toppath
|
self.toppath = archive_task.toppath
|
||||||
log.debug("Archive extracted to: {0}", self.toppath)
|
log.debug("Archive extracted to: {}", self.toppath)
|
||||||
return archive_task
|
return archive_task
|
||||||
|
|
||||||
def read_item(self, path: util.PathBytes):
|
def read_item(self, path: util.PathBytes):
|
||||||
|
|
@ -1091,10 +1089,10 @@ class ImportTaskFactory:
|
||||||
# Silently ignore non-music files.
|
# Silently ignore non-music files.
|
||||||
pass
|
pass
|
||||||
elif isinstance(exc.reason, mediafile.UnreadableFileError):
|
elif isinstance(exc.reason, mediafile.UnreadableFileError):
|
||||||
log.warning("unreadable file: {0}", util.displayable_path(path))
|
log.warning("unreadable file: {}", util.displayable_path(path))
|
||||||
else:
|
else:
|
||||||
log.error(
|
log.error(
|
||||||
"error reading {0}: {1}", util.displayable_path(path), exc
|
"error reading {}: {}", util.displayable_path(path), exc
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -425,7 +425,7 @@ class Album(LibModel):
|
||||||
|
|
||||||
new_art = util.unique_path(new_art)
|
new_art = util.unique_path(new_art)
|
||||||
log.debug(
|
log.debug(
|
||||||
"moving album art {0} to {1}",
|
"moving album art {} to {}",
|
||||||
util.displayable_path(old_art),
|
util.displayable_path(old_art),
|
||||||
util.displayable_path(new_art),
|
util.displayable_path(new_art),
|
||||||
)
|
)
|
||||||
|
|
@ -992,7 +992,7 @@ class Item(LibModel):
|
||||||
self.write(*args, **kwargs)
|
self.write(*args, **kwargs)
|
||||||
return True
|
return True
|
||||||
except FileOperationError as exc:
|
except FileOperationError as exc:
|
||||||
log.error("{0}", exc)
|
log.error("{}", exc)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def try_sync(self, write, move, with_album=True):
|
def try_sync(self, write, move, with_album=True):
|
||||||
|
|
@ -1013,7 +1013,7 @@ class Item(LibModel):
|
||||||
# Check whether this file is inside the library directory.
|
# Check whether this file is inside the library directory.
|
||||||
if self._db and self._db.directory in util.ancestry(self.path):
|
if self._db and self._db.directory in util.ancestry(self.path):
|
||||||
log.debug(
|
log.debug(
|
||||||
"moving {0} to synchronize path",
|
"moving {} to synchronize path",
|
||||||
util.displayable_path(self.path),
|
util.displayable_path(self.path),
|
||||||
)
|
)
|
||||||
self.move(with_album=with_album)
|
self.move(with_album=with_album)
|
||||||
|
|
@ -1087,7 +1087,7 @@ class Item(LibModel):
|
||||||
try:
|
try:
|
||||||
return os.path.getsize(syspath(self.path))
|
return os.path.getsize(syspath(self.path))
|
||||||
except (OSError, Exception) as exc:
|
except (OSError, Exception) as exc:
|
||||||
log.warning("could not get filesize: {0}", exc)
|
log.warning("could not get filesize: {}", exc)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
# Model methods.
|
# Model methods.
|
||||||
|
|
|
||||||
|
|
@ -543,7 +543,7 @@ def send(event: EventType, **arguments: Any) -> list[Any]:
|
||||||
|
|
||||||
Return a list of non-None values returned from the handlers.
|
Return a list of non-None values returned from the handlers.
|
||||||
"""
|
"""
|
||||||
log.debug("Sending event: {0}", event)
|
log.debug("Sending event: {}", event)
|
||||||
return [
|
return [
|
||||||
r
|
r
|
||||||
for handler in BeetsPlugin.listeners[event]
|
for handler in BeetsPlugin.listeners[event]
|
||||||
|
|
|
||||||
|
|
@ -267,7 +267,7 @@ class TestHelper(ConfigMixin):
|
||||||
The item is attached to the database from `self.lib`.
|
The item is attached to the database from `self.lib`.
|
||||||
"""
|
"""
|
||||||
values_ = {
|
values_ = {
|
||||||
"title": "t\u00eftle {0}",
|
"title": "t\u00eftle {}",
|
||||||
"artist": "the \u00e4rtist",
|
"artist": "the \u00e4rtist",
|
||||||
"album": "the \u00e4lbum",
|
"album": "the \u00e4lbum",
|
||||||
"track": 1,
|
"track": 1,
|
||||||
|
|
|
||||||
|
|
@ -572,7 +572,7 @@ def colorize(color_name, text):
|
||||||
# instead of the abstract color name ('text_error')
|
# instead of the abstract color name ('text_error')
|
||||||
color = COLORS.get(color_name)
|
color = COLORS.get(color_name)
|
||||||
if not color:
|
if not color:
|
||||||
log.debug("Invalid color_name: {0}", color_name)
|
log.debug("Invalid color_name: {}", color_name)
|
||||||
color = color_name
|
color = color_name
|
||||||
return _colorize(color, text)
|
return _colorize(color, text)
|
||||||
else:
|
else:
|
||||||
|
|
@ -1587,19 +1587,19 @@ def _configure(options):
|
||||||
|
|
||||||
if overlay_path:
|
if overlay_path:
|
||||||
log.debug(
|
log.debug(
|
||||||
"overlaying configuration: {0}", util.displayable_path(overlay_path)
|
"overlaying configuration: {}", util.displayable_path(overlay_path)
|
||||||
)
|
)
|
||||||
|
|
||||||
config_path = config.user_config_path()
|
config_path = config.user_config_path()
|
||||||
if os.path.isfile(config_path):
|
if os.path.isfile(config_path):
|
||||||
log.debug("user configuration: {0}", util.displayable_path(config_path))
|
log.debug("user configuration: {}", util.displayable_path(config_path))
|
||||||
else:
|
else:
|
||||||
log.debug(
|
log.debug(
|
||||||
"no user configuration found at {0}",
|
"no user configuration found at {}",
|
||||||
util.displayable_path(config_path),
|
util.displayable_path(config_path),
|
||||||
)
|
)
|
||||||
|
|
||||||
log.debug("data directory: {0}", util.displayable_path(config.config_dir()))
|
log.debug("data directory: {}", util.displayable_path(config.config_dir()))
|
||||||
return config
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1634,7 +1634,7 @@ def _open_library(config: confuse.LazyConfig) -> library.Library:
|
||||||
f" opened: {db_error}"
|
f" opened: {db_error}"
|
||||||
)
|
)
|
||||||
log.debug(
|
log.debug(
|
||||||
"library database: {0}\nlibrary directory: {1}",
|
"library database: {}\nlibrary directory: {}",
|
||||||
util.displayable_path(lib.path),
|
util.displayable_path(lib.path),
|
||||||
util.displayable_path(lib.directory),
|
util.displayable_path(lib.directory),
|
||||||
)
|
)
|
||||||
|
|
@ -1751,7 +1751,7 @@ def main(args=None):
|
||||||
_raw_main(args)
|
_raw_main(args)
|
||||||
except UserError as exc:
|
except UserError as exc:
|
||||||
message = exc.args[0] if exc.args else None
|
message = exc.args[0] if exc.args else None
|
||||||
log.error("error: {0}", message)
|
log.error("error: {}", message)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except util.HumanReadableError as exc:
|
except util.HumanReadableError as exc:
|
||||||
exc.log(log)
|
exc.log(log)
|
||||||
|
|
@ -1763,10 +1763,10 @@ def main(args=None):
|
||||||
log.error("{}", exc)
|
log.error("{}", exc)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except confuse.ConfigError as exc:
|
except confuse.ConfigError as exc:
|
||||||
log.error("configuration error: {0}", exc)
|
log.error("configuration error: {}", exc)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except db_query.InvalidQueryError as exc:
|
except db_query.InvalidQueryError as exc:
|
||||||
log.error("invalid query: {0}", exc)
|
log.error("invalid query: {}", exc)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
if exc.errno == errno.EPIPE:
|
if exc.errno == errno.EPIPE:
|
||||||
|
|
@ -1779,7 +1779,7 @@ def main(args=None):
|
||||||
log.debug("{}", traceback.format_exc())
|
log.debug("{}", traceback.format_exc())
|
||||||
except db.DBAccessError as exc:
|
except db.DBAccessError as exc:
|
||||||
log.error(
|
log.error(
|
||||||
"database access error: {0}\n"
|
"database access error: {}\n"
|
||||||
"the library file might have a permissions problem",
|
"the library file might have a permissions problem",
|
||||||
exc,
|
exc,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1148,7 +1148,7 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
that's already in the library.
|
that's already in the library.
|
||||||
"""
|
"""
|
||||||
log.warning(
|
log.warning(
|
||||||
"This {0} is already in the library!",
|
"This {} is already in the library!",
|
||||||
("album" if task.is_album else "item"),
|
("album" if task.is_album else "item"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1280,8 +1280,8 @@ class TerminalImportSession(importer.ImportSession):
|
||||||
dup_choices = [c for c in all_choices if c.short == short]
|
dup_choices = [c for c in all_choices if c.short == short]
|
||||||
for c in dup_choices[1:]:
|
for c in dup_choices[1:]:
|
||||||
log.warning(
|
log.warning(
|
||||||
"Prompt choice '{0}' removed due to conflict "
|
"Prompt choice '{}' removed due to conflict "
|
||||||
"with '{1}' (short letter: '{2}')",
|
"with '{}' (short letter: '{}')",
|
||||||
c.long,
|
c.long,
|
||||||
dup_choices[0].long,
|
dup_choices[0].long,
|
||||||
c.short,
|
c.short,
|
||||||
|
|
@ -1639,7 +1639,7 @@ def update_items(lib, query, album, move, pretend, fields, exclude_fields=None):
|
||||||
# Did the item change since last checked?
|
# Did the item change since last checked?
|
||||||
if item.current_mtime() <= item.mtime:
|
if item.current_mtime() <= item.mtime:
|
||||||
log.debug(
|
log.debug(
|
||||||
"skipping {0} because mtime is up to date ({1})",
|
"skipping {} because mtime is up to date ({})",
|
||||||
displayable_path(item.path),
|
displayable_path(item.path),
|
||||||
item.mtime,
|
item.mtime,
|
||||||
)
|
)
|
||||||
|
|
@ -1650,7 +1650,7 @@ def update_items(lib, query, album, move, pretend, fields, exclude_fields=None):
|
||||||
item.read()
|
item.read()
|
||||||
except library.ReadError as exc:
|
except library.ReadError as exc:
|
||||||
log.error(
|
log.error(
|
||||||
"error reading {0}: {1}", displayable_path(item.path), exc
|
"error reading {}: {}", displayable_path(item.path), exc
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
@ -1692,7 +1692,7 @@ def update_items(lib, query, album, move, pretend, fields, exclude_fields=None):
|
||||||
continue
|
continue
|
||||||
album = lib.get_album(album_id)
|
album = lib.get_album(album_id)
|
||||||
if not album: # Empty albums have already been removed.
|
if not album: # Empty albums have already been removed.
|
||||||
log.debug("emptied album {0}", album_id)
|
log.debug("emptied album {}", album_id)
|
||||||
continue
|
continue
|
||||||
first_item = album.items().get()
|
first_item = album.items().get()
|
||||||
|
|
||||||
|
|
@ -1703,7 +1703,7 @@ def update_items(lib, query, album, move, pretend, fields, exclude_fields=None):
|
||||||
|
|
||||||
# Move album art (and any inconsistent items).
|
# Move album art (and any inconsistent items).
|
||||||
if move and lib.directory in ancestry(first_item.path):
|
if move and lib.directory in ancestry(first_item.path):
|
||||||
log.debug("moving album {0}", album_id)
|
log.debug("moving album {}", album_id)
|
||||||
|
|
||||||
# Manually moving and storing the album.
|
# Manually moving and storing the album.
|
||||||
items = list(album.items())
|
items = list(album.items())
|
||||||
|
|
@ -2141,7 +2141,7 @@ def move_items(
|
||||||
act = "copy" if copy else "move"
|
act = "copy" if copy else "move"
|
||||||
entity = "album" if album else "item"
|
entity = "album" if album else "item"
|
||||||
log.info(
|
log.info(
|
||||||
"{0} {1} {2}{3}{4}.",
|
"{} {} {}{}{}.",
|
||||||
action,
|
action,
|
||||||
len(objs),
|
len(objs),
|
||||||
entity,
|
entity,
|
||||||
|
|
@ -2175,7 +2175,7 @@ def move_items(
|
||||||
)
|
)
|
||||||
|
|
||||||
for obj in objs:
|
for obj in objs:
|
||||||
log.debug("moving: {0}", util.displayable_path(obj.path))
|
log.debug("moving: {}", util.displayable_path(obj.path))
|
||||||
|
|
||||||
if export:
|
if export:
|
||||||
# Copy without affecting the database.
|
# Copy without affecting the database.
|
||||||
|
|
@ -2258,16 +2258,14 @@ def write_items(lib, query, pretend, force):
|
||||||
for item in items:
|
for item in items:
|
||||||
# Item deleted?
|
# Item deleted?
|
||||||
if not os.path.exists(syspath(item.path)):
|
if not os.path.exists(syspath(item.path)):
|
||||||
log.info("missing file: {0}", util.displayable_path(item.path))
|
log.info("missing file: {}", util.displayable_path(item.path))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Get an Item object reflecting the "clean" (on-disk) state.
|
# Get an Item object reflecting the "clean" (on-disk) state.
|
||||||
try:
|
try:
|
||||||
clean_item = library.Item.from_path(item.path)
|
clean_item = library.Item.from_path(item.path)
|
||||||
except library.ReadError as exc:
|
except library.ReadError as exc:
|
||||||
log.error(
|
log.error("error reading {}: {}", displayable_path(item.path), exc)
|
||||||
"error reading {0}: {1}", displayable_path(item.path), exc
|
|
||||||
)
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Check for and display changes.
|
# Check for and display changes.
|
||||||
|
|
|
||||||
|
|
@ -126,7 +126,7 @@ class HumanReadableError(Exception):
|
||||||
"""
|
"""
|
||||||
if self.tb:
|
if self.tb:
|
||||||
logger.debug(self.tb)
|
logger.debug(self.tb)
|
||||||
logger.error("{0}: {1}", self.error_kind, self.args[0])
|
logger.error("{}: {}", self.error_kind, self.args[0])
|
||||||
|
|
||||||
|
|
||||||
class FilesystemError(HumanReadableError):
|
class FilesystemError(HumanReadableError):
|
||||||
|
|
|
||||||
|
|
@ -255,7 +255,7 @@ class IMBackend(LocalBackend):
|
||||||
path_out = get_temp_filename(__name__, "resize_IM_", path_in)
|
path_out = get_temp_filename(__name__, "resize_IM_", path_in)
|
||||||
|
|
||||||
log.debug(
|
log.debug(
|
||||||
"artresizer: ImageMagick resizing {0} to {1}",
|
"artresizer: ImageMagick resizing {} to {}",
|
||||||
displayable_path(path_in),
|
displayable_path(path_in),
|
||||||
displayable_path(path_out),
|
displayable_path(path_out),
|
||||||
)
|
)
|
||||||
|
|
@ -287,7 +287,7 @@ class IMBackend(LocalBackend):
|
||||||
util.command_output(cmd)
|
util.command_output(cmd)
|
||||||
except subprocess.CalledProcessError:
|
except subprocess.CalledProcessError:
|
||||||
log.warning(
|
log.warning(
|
||||||
"artresizer: IM convert failed for {0}",
|
"artresizer: IM convert failed for {}",
|
||||||
displayable_path(path_in),
|
displayable_path(path_in),
|
||||||
)
|
)
|
||||||
return path_in
|
return path_in
|
||||||
|
|
@ -452,7 +452,7 @@ class IMBackend(LocalBackend):
|
||||||
if compare_proc.returncode:
|
if compare_proc.returncode:
|
||||||
if compare_proc.returncode != 1:
|
if compare_proc.returncode != 1:
|
||||||
log.debug(
|
log.debug(
|
||||||
"ImageMagick compare failed: {0}, {1}",
|
"ImageMagick compare failed: {}, {}",
|
||||||
displayable_path(im2),
|
displayable_path(im2),
|
||||||
displayable_path(im1),
|
displayable_path(im1),
|
||||||
)
|
)
|
||||||
|
|
@ -472,7 +472,7 @@ class IMBackend(LocalBackend):
|
||||||
log.debug("IM output is not a number: {0!r}", out_str)
|
log.debug("IM output is not a number: {0!r}", out_str)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
log.debug("ImageMagick compare score: {0}", phash_diff)
|
log.debug("ImageMagick compare score: {}", phash_diff)
|
||||||
return phash_diff <= compare_threshold
|
return phash_diff <= compare_threshold
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|
@ -523,7 +523,7 @@ class PILBackend(LocalBackend):
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
log.debug(
|
log.debug(
|
||||||
"artresizer: PIL resizing {0} to {1}",
|
"artresizer: PIL resizing {} to {}",
|
||||||
displayable_path(path_in),
|
displayable_path(path_in),
|
||||||
displayable_path(path_out),
|
displayable_path(path_out),
|
||||||
)
|
)
|
||||||
|
|
@ -552,7 +552,7 @@ class PILBackend(LocalBackend):
|
||||||
for i in range(5):
|
for i in range(5):
|
||||||
# 5 attempts is an arbitrary choice
|
# 5 attempts is an arbitrary choice
|
||||||
filesize = os.stat(syspath(path_out)).st_size
|
filesize = os.stat(syspath(path_out)).st_size
|
||||||
log.debug("PIL Pass {0} : Output size: {1}B", i, filesize)
|
log.debug("PIL Pass {} : Output size: {}B", i, filesize)
|
||||||
if filesize <= max_filesize:
|
if filesize <= max_filesize:
|
||||||
return path_out
|
return path_out
|
||||||
# The relationship between filesize & quality will be
|
# The relationship between filesize & quality will be
|
||||||
|
|
@ -569,7 +569,7 @@ class PILBackend(LocalBackend):
|
||||||
progressive=False,
|
progressive=False,
|
||||||
)
|
)
|
||||||
log.warning(
|
log.warning(
|
||||||
"PIL Failed to resize file to below {0}B", max_filesize
|
"PIL Failed to resize file to below {}B", max_filesize
|
||||||
)
|
)
|
||||||
return path_out
|
return path_out
|
||||||
|
|
||||||
|
|
@ -577,7 +577,7 @@ class PILBackend(LocalBackend):
|
||||||
return path_out
|
return path_out
|
||||||
except OSError:
|
except OSError:
|
||||||
log.error(
|
log.error(
|
||||||
"PIL cannot create thumbnail for '{0}'",
|
"PIL cannot create thumbnail for '{}'",
|
||||||
displayable_path(path_in),
|
displayable_path(path_in),
|
||||||
)
|
)
|
||||||
return path_in
|
return path_in
|
||||||
|
|
|
||||||
|
|
@ -366,7 +366,7 @@ class BeatportPlugin(MetadataSourcePlugin):
|
||||||
try:
|
try:
|
||||||
url = auth_client.get_authorize_url()
|
url = auth_client.get_authorize_url()
|
||||||
except AUTH_ERRORS as e:
|
except AUTH_ERRORS as e:
|
||||||
self._log.debug("authentication error: {0}", e)
|
self._log.debug("authentication error: {}", e)
|
||||||
raise beets.ui.UserError("communication with Beatport failed")
|
raise beets.ui.UserError("communication with Beatport failed")
|
||||||
|
|
||||||
beets.ui.print_("To authenticate with Beatport, visit:")
|
beets.ui.print_("To authenticate with Beatport, visit:")
|
||||||
|
|
@ -377,11 +377,11 @@ class BeatportPlugin(MetadataSourcePlugin):
|
||||||
try:
|
try:
|
||||||
token, secret = auth_client.get_access_token(data)
|
token, secret = auth_client.get_access_token(data)
|
||||||
except AUTH_ERRORS as e:
|
except AUTH_ERRORS as e:
|
||||||
self._log.debug("authentication error: {0}", e)
|
self._log.debug("authentication error: {}", e)
|
||||||
raise beets.ui.UserError("Beatport token request failed")
|
raise beets.ui.UserError("Beatport token request failed")
|
||||||
|
|
||||||
# Save the token for later use.
|
# Save the token for later use.
|
||||||
self._log.debug("Beatport token {0}, secret {1}", token, secret)
|
self._log.debug("Beatport token {}, secret {}", token, secret)
|
||||||
with open(self._tokenfile(), "w") as f:
|
with open(self._tokenfile(), "w") as f:
|
||||||
json.dump({"token": token, "secret": secret}, f)
|
json.dump({"token": token, "secret": secret}, f)
|
||||||
|
|
||||||
|
|
@ -405,7 +405,7 @@ class BeatportPlugin(MetadataSourcePlugin):
|
||||||
try:
|
try:
|
||||||
yield from self._get_releases(query)
|
yield from self._get_releases(query)
|
||||||
except BeatportAPIError as e:
|
except BeatportAPIError as e:
|
||||||
self._log.debug("API Error: {0} (query: {1})", e, query)
|
self._log.debug("API Error: {} (query: {})", e, query)
|
||||||
return
|
return
|
||||||
|
|
||||||
def item_candidates(
|
def item_candidates(
|
||||||
|
|
@ -415,14 +415,14 @@ class BeatportPlugin(MetadataSourcePlugin):
|
||||||
try:
|
try:
|
||||||
return self._get_tracks(query)
|
return self._get_tracks(query)
|
||||||
except BeatportAPIError as e:
|
except BeatportAPIError as e:
|
||||||
self._log.debug("API Error: {0} (query: {1})", e, query)
|
self._log.debug("API Error: {} (query: {})", e, query)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def album_for_id(self, album_id: str):
|
def album_for_id(self, album_id: str):
|
||||||
"""Fetches a release by its Beatport ID and returns an AlbumInfo object
|
"""Fetches a release by its Beatport ID and returns an AlbumInfo object
|
||||||
or None if the query is not a valid ID or release is not found.
|
or None if the query is not a valid ID or release is not found.
|
||||||
"""
|
"""
|
||||||
self._log.debug("Searching for release {0}", album_id)
|
self._log.debug("Searching for release {}", album_id)
|
||||||
|
|
||||||
if not (release_id := self._extract_id(album_id)):
|
if not (release_id := self._extract_id(album_id)):
|
||||||
self._log.debug("Not a valid Beatport release ID.")
|
self._log.debug("Not a valid Beatport release ID.")
|
||||||
|
|
@ -437,7 +437,7 @@ class BeatportPlugin(MetadataSourcePlugin):
|
||||||
"""Fetches a track by its Beatport ID and returns a TrackInfo object
|
"""Fetches a track by its Beatport ID and returns a TrackInfo object
|
||||||
or None if the track is not a valid Beatport ID or track is not found.
|
or None if the track is not a valid Beatport ID or track is not found.
|
||||||
"""
|
"""
|
||||||
self._log.debug("Searching for track {0}", track_id)
|
self._log.debug("Searching for track {}", track_id)
|
||||||
# TODO: move to extractor
|
# TODO: move to extractor
|
||||||
match = re.search(r"(^|beatport\.com/track/.+/)(\d+)$", track_id)
|
match = re.search(r"(^|beatport\.com/track/.+/)(\d+)$", track_id)
|
||||||
if not match:
|
if not match:
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,12 @@ class BPMPlugin(BeetsPlugin):
|
||||||
|
|
||||||
item = items[0]
|
item = items[0]
|
||||||
if item["bpm"]:
|
if item["bpm"]:
|
||||||
self._log.info("Found bpm {0}", item["bpm"])
|
self._log.info("Found bpm {}", item["bpm"])
|
||||||
if not overwrite:
|
if not overwrite:
|
||||||
return
|
return
|
||||||
|
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Press Enter {0} times to the rhythm or Ctrl-D to exit",
|
"Press Enter {} times to the rhythm or Ctrl-D to exit",
|
||||||
self.config["max_strokes"].get(int),
|
self.config["max_strokes"].get(int),
|
||||||
)
|
)
|
||||||
new_bpm = bpm(self.config["max_strokes"].get(int))
|
new_bpm = bpm(self.config["max_strokes"].get(int))
|
||||||
|
|
@ -86,4 +86,4 @@ class BPMPlugin(BeetsPlugin):
|
||||||
if write:
|
if write:
|
||||||
item.try_write()
|
item.try_write()
|
||||||
item.store()
|
item.store()
|
||||||
self._log.info("Added new bpm {0}", item["bpm"])
|
self._log.info("Added new bpm {}", item["bpm"])
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ def acoustid_match(log, path):
|
||||||
duration, fp = acoustid.fingerprint_file(util.syspath(path))
|
duration, fp = acoustid.fingerprint_file(util.syspath(path))
|
||||||
except acoustid.FingerprintGenerationError as exc:
|
except acoustid.FingerprintGenerationError as exc:
|
||||||
log.error(
|
log.error(
|
||||||
"fingerprinting of {0} failed: {1}",
|
"fingerprinting of {} failed: {}",
|
||||||
util.displayable_path(repr(path)),
|
util.displayable_path(repr(path)),
|
||||||
exc,
|
exc,
|
||||||
)
|
)
|
||||||
|
|
@ -103,12 +103,12 @@ def acoustid_match(log, path):
|
||||||
)
|
)
|
||||||
except acoustid.AcoustidError as exc:
|
except acoustid.AcoustidError as exc:
|
||||||
log.debug(
|
log.debug(
|
||||||
"fingerprint matching {0} failed: {1}",
|
"fingerprint matching {} failed: {}",
|
||||||
util.displayable_path(repr(path)),
|
util.displayable_path(repr(path)),
|
||||||
exc,
|
exc,
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
log.debug("chroma: fingerprinted {0}", util.displayable_path(repr(path)))
|
log.debug("chroma: fingerprinted {}", util.displayable_path(repr(path)))
|
||||||
|
|
||||||
# Ensure the response is usable and parse it.
|
# Ensure the response is usable and parse it.
|
||||||
if res["status"] != "ok" or not res.get("results"):
|
if res["status"] != "ok" or not res.get("results"):
|
||||||
|
|
@ -146,7 +146,7 @@ def acoustid_match(log, path):
|
||||||
release_ids = [rel["id"] for rel in releases]
|
release_ids = [rel["id"] for rel in releases]
|
||||||
|
|
||||||
log.debug(
|
log.debug(
|
||||||
"matched recordings {0} on releases {1}", recording_ids, release_ids
|
"matched recordings {} on releases {}", recording_ids, release_ids
|
||||||
)
|
)
|
||||||
_matches[path] = recording_ids, release_ids
|
_matches[path] = recording_ids, release_ids
|
||||||
|
|
||||||
|
|
@ -211,7 +211,7 @@ class AcoustidPlugin(MetadataSourcePlugin):
|
||||||
if album:
|
if album:
|
||||||
albums.append(album)
|
albums.append(album)
|
||||||
|
|
||||||
self._log.debug("acoustid album candidates: {0}", len(albums))
|
self._log.debug("acoustid album candidates: {}", len(albums))
|
||||||
return albums
|
return albums
|
||||||
|
|
||||||
def item_candidates(self, item, artist, title) -> Iterable[TrackInfo]:
|
def item_candidates(self, item, artist, title) -> Iterable[TrackInfo]:
|
||||||
|
|
@ -224,7 +224,7 @@ class AcoustidPlugin(MetadataSourcePlugin):
|
||||||
track = self.mb.track_for_id(recording_id)
|
track = self.mb.track_for_id(recording_id)
|
||||||
if track:
|
if track:
|
||||||
tracks.append(track)
|
tracks.append(track)
|
||||||
self._log.debug("acoustid item candidates: {0}", len(tracks))
|
self._log.debug("acoustid item candidates: {}", len(tracks))
|
||||||
return tracks
|
return tracks
|
||||||
|
|
||||||
def album_for_id(self, *args, **kwargs):
|
def album_for_id(self, *args, **kwargs):
|
||||||
|
|
@ -292,11 +292,11 @@ def submit_items(log, userkey, items, chunksize=64):
|
||||||
|
|
||||||
def submit_chunk():
|
def submit_chunk():
|
||||||
"""Submit the current accumulated fingerprint data."""
|
"""Submit the current accumulated fingerprint data."""
|
||||||
log.info("submitting {0} fingerprints", len(data))
|
log.info("submitting {} fingerprints", len(data))
|
||||||
try:
|
try:
|
||||||
acoustid.submit(API_KEY, userkey, data, timeout=10)
|
acoustid.submit(API_KEY, userkey, data, timeout=10)
|
||||||
except acoustid.AcoustidError as exc:
|
except acoustid.AcoustidError as exc:
|
||||||
log.warning("acoustid submission error: {0}", exc)
|
log.warning("acoustid submission error: {}", exc)
|
||||||
del data[:]
|
del data[:]
|
||||||
|
|
||||||
for item in items:
|
for item in items:
|
||||||
|
|
@ -343,31 +343,31 @@ def fingerprint_item(log, item, write=False):
|
||||||
"""
|
"""
|
||||||
# Get a fingerprint and length for this track.
|
# Get a fingerprint and length for this track.
|
||||||
if not item.length:
|
if not item.length:
|
||||||
log.info("{0}: no duration available", util.displayable_path(item.path))
|
log.info("{}: no duration available", util.displayable_path(item.path))
|
||||||
elif item.acoustid_fingerprint:
|
elif item.acoustid_fingerprint:
|
||||||
if write:
|
if write:
|
||||||
log.info(
|
log.info(
|
||||||
"{0}: fingerprint exists, skipping",
|
"{}: fingerprint exists, skipping",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
log.info(
|
log.info(
|
||||||
"{0}: using existing fingerprint",
|
"{}: using existing fingerprint",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
)
|
)
|
||||||
return item.acoustid_fingerprint
|
return item.acoustid_fingerprint
|
||||||
else:
|
else:
|
||||||
log.info("{0}: fingerprinting", util.displayable_path(item.path))
|
log.info("{}: fingerprinting", util.displayable_path(item.path))
|
||||||
try:
|
try:
|
||||||
_, fp = acoustid.fingerprint_file(util.syspath(item.path))
|
_, fp = acoustid.fingerprint_file(util.syspath(item.path))
|
||||||
item.acoustid_fingerprint = fp.decode()
|
item.acoustid_fingerprint = fp.decode()
|
||||||
if write:
|
if write:
|
||||||
log.info(
|
log.info(
|
||||||
"{0}: writing fingerprint", util.displayable_path(item.path)
|
"{}: writing fingerprint", util.displayable_path(item.path)
|
||||||
)
|
)
|
||||||
item.try_write()
|
item.try_write()
|
||||||
if item._db:
|
if item._db:
|
||||||
item.store()
|
item.store()
|
||||||
return item.acoustid_fingerprint
|
return item.acoustid_fingerprint
|
||||||
except acoustid.FingerprintGenerationError as exc:
|
except acoustid.FingerprintGenerationError as exc:
|
||||||
log.info("fingerprint generation failed: {0}", exc)
|
log.info("fingerprint generation failed: {}", exc)
|
||||||
|
|
|
||||||
|
|
@ -288,7 +288,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
quiet = self.config["quiet"].get(bool)
|
quiet = self.config["quiet"].get(bool)
|
||||||
|
|
||||||
if not quiet and not pretend:
|
if not quiet and not pretend:
|
||||||
self._log.info("Encoding {0}", util.displayable_path(source))
|
self._log.info("Encoding {}", util.displayable_path(source))
|
||||||
|
|
||||||
command = os.fsdecode(command)
|
command = os.fsdecode(command)
|
||||||
source = os.fsdecode(source)
|
source = os.fsdecode(source)
|
||||||
|
|
@ -307,7 +307,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
encode_cmd.append(os.fsdecode(args[i]))
|
encode_cmd.append(os.fsdecode(args[i]))
|
||||||
|
|
||||||
if pretend:
|
if pretend:
|
||||||
self._log.info("{0}", " ".join(args))
|
self._log.info("{}", " ".join(args))
|
||||||
return
|
return
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -315,11 +315,11 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
# Something went wrong (probably Ctrl+C), remove temporary files
|
# Something went wrong (probably Ctrl+C), remove temporary files
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Encoding {0} failed. Cleaning up...",
|
"Encoding {} failed. Cleaning up...",
|
||||||
util.displayable_path(source),
|
util.displayable_path(source),
|
||||||
)
|
)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Command {0} exited with status {1}: {2}",
|
"Command {} exited with status {}: {}",
|
||||||
args,
|
args,
|
||||||
exc.returncode,
|
exc.returncode,
|
||||||
exc.output,
|
exc.output,
|
||||||
|
|
@ -334,7 +334,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
|
|
||||||
if not quiet and not pretend:
|
if not quiet and not pretend:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Finished encoding {0}", util.displayable_path(source)
|
"Finished encoding {}", util.displayable_path(source)
|
||||||
)
|
)
|
||||||
|
|
||||||
def convert_item(
|
def convert_item(
|
||||||
|
|
@ -362,7 +362,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
mediafile.MediaFile(util.syspath(item.path))
|
mediafile.MediaFile(util.syspath(item.path))
|
||||||
except mediafile.UnreadableFileError as exc:
|
except mediafile.UnreadableFileError as exc:
|
||||||
self._log.error("Could not open file to convert: {0}", exc)
|
self._log.error("Could not open file to convert: {}", exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# When keeping the new file in the library, we first move the
|
# When keeping the new file in the library, we first move the
|
||||||
|
|
@ -388,7 +388,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
|
|
||||||
if os.path.exists(util.syspath(dest)):
|
if os.path.exists(util.syspath(dest)):
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Skipping {0} (target file exists)",
|
"Skipping {} (target file exists)",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
@ -396,13 +396,13 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
if keep_new:
|
if keep_new:
|
||||||
if pretend:
|
if pretend:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"mv {0} {1}",
|
"mv {} {}",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
util.displayable_path(original),
|
util.displayable_path(original),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Moving to {0}", util.displayable_path(original)
|
"Moving to {}", util.displayable_path(original)
|
||||||
)
|
)
|
||||||
util.move(item.path, original)
|
util.move(item.path, original)
|
||||||
|
|
||||||
|
|
@ -418,10 +418,10 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
msg = "ln" if hardlink else ("ln -s" if link else "cp")
|
msg = "ln" if hardlink else ("ln -s" if link else "cp")
|
||||||
|
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"{2} {0} {1}",
|
"{} {} {}",
|
||||||
|
msg,
|
||||||
util.displayable_path(original),
|
util.displayable_path(original),
|
||||||
util.displayable_path(converted),
|
util.displayable_path(converted),
|
||||||
msg,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# No transcoding necessary.
|
# No transcoding necessary.
|
||||||
|
|
@ -432,7 +432,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"{1} {0}", util.displayable_path(item.path), msg
|
"{} {}", msg, util.displayable_path(item.path)
|
||||||
)
|
)
|
||||||
|
|
||||||
if hardlink:
|
if hardlink:
|
||||||
|
|
@ -523,7 +523,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
|
|
||||||
if os.path.exists(util.syspath(dest)):
|
if os.path.exists(util.syspath(dest)):
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Skipping {0} (target file exists)",
|
"Skipping {} (target file exists)",
|
||||||
util.displayable_path(album.artpath),
|
util.displayable_path(album.artpath),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
@ -534,7 +534,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
# Either copy or resize (while copying) the image.
|
# Either copy or resize (while copying) the image.
|
||||||
if maxwidth is not None:
|
if maxwidth is not None:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Resizing cover art from {0} to {1}",
|
"Resizing cover art from {} to {}",
|
||||||
util.displayable_path(album.artpath),
|
util.displayable_path(album.artpath),
|
||||||
util.displayable_path(dest),
|
util.displayable_path(dest),
|
||||||
)
|
)
|
||||||
|
|
@ -545,10 +545,10 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
msg = "ln" if hardlink else ("ln -s" if link else "cp")
|
msg = "ln" if hardlink else ("ln -s" if link else "cp")
|
||||||
|
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"{2} {0} {1}",
|
"{} {} {}",
|
||||||
|
msg,
|
||||||
util.displayable_path(album.artpath),
|
util.displayable_path(album.artpath),
|
||||||
util.displayable_path(dest),
|
util.displayable_path(dest),
|
||||||
msg,
|
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
msg = (
|
msg = (
|
||||||
|
|
@ -558,10 +558,10 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
)
|
)
|
||||||
|
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"{2} cover art from {0} to {1}",
|
"{} cover art from {} to {}",
|
||||||
|
msg,
|
||||||
util.displayable_path(album.artpath),
|
util.displayable_path(album.artpath),
|
||||||
util.displayable_path(dest),
|
util.displayable_path(dest),
|
||||||
msg,
|
|
||||||
)
|
)
|
||||||
if hardlink:
|
if hardlink:
|
||||||
util.hardlink(album.artpath, dest)
|
util.hardlink(album.artpath, dest)
|
||||||
|
|
@ -622,7 +622,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
# Playlist paths are understood as relative to the dest directory.
|
# Playlist paths are understood as relative to the dest directory.
|
||||||
pl_normpath = util.normpath(playlist)
|
pl_normpath = util.normpath(playlist)
|
||||||
pl_dir = os.path.dirname(pl_normpath)
|
pl_dir = os.path.dirname(pl_normpath)
|
||||||
self._log.info("Creating playlist file {0}", pl_normpath)
|
self._log.info("Creating playlist file {}", pl_normpath)
|
||||||
# Generates a list of paths to media files, ensures the paths are
|
# Generates a list of paths to media files, ensures the paths are
|
||||||
# relative to the playlist's location and translates the unicode
|
# relative to the playlist's location and translates the unicode
|
||||||
# strings we get from item.destination to bytes.
|
# strings we get from item.destination to bytes.
|
||||||
|
|
@ -672,7 +672,7 @@ class ConvertPlugin(BeetsPlugin):
|
||||||
if self.config["delete_originals"]:
|
if self.config["delete_originals"]:
|
||||||
self._log.log(
|
self._log.log(
|
||||||
logging.DEBUG if self.config["quiet"] else logging.INFO,
|
logging.DEBUG if self.config["quiet"] else logging.INFO,
|
||||||
"Removing original file {0}",
|
"Removing original file {}",
|
||||||
source_path,
|
source_path,
|
||||||
)
|
)
|
||||||
util.remove(source_path, False)
|
util.remove(source_path, False)
|
||||||
|
|
|
||||||
|
|
@ -145,7 +145,7 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
||||||
try:
|
try:
|
||||||
_, _, url = auth_client.get_authorize_url()
|
_, _, url = auth_client.get_authorize_url()
|
||||||
except CONNECTION_ERRORS as e:
|
except CONNECTION_ERRORS as e:
|
||||||
self._log.debug("connection error: {0}", e)
|
self._log.debug("connection error: {}", e)
|
||||||
raise beets.ui.UserError("communication with Discogs failed")
|
raise beets.ui.UserError("communication with Discogs failed")
|
||||||
|
|
||||||
beets.ui.print_("To authenticate with Discogs, visit:")
|
beets.ui.print_("To authenticate with Discogs, visit:")
|
||||||
|
|
@ -158,11 +158,11 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
||||||
except DiscogsAPIError:
|
except DiscogsAPIError:
|
||||||
raise beets.ui.UserError("Discogs authorization failed")
|
raise beets.ui.UserError("Discogs authorization failed")
|
||||||
except CONNECTION_ERRORS as e:
|
except CONNECTION_ERRORS as e:
|
||||||
self._log.debug("connection error: {0}", e)
|
self._log.debug("connection error: {}", e)
|
||||||
raise beets.ui.UserError("Discogs token request failed")
|
raise beets.ui.UserError("Discogs token request failed")
|
||||||
|
|
||||||
# Save the token for later use.
|
# Save the token for later use.
|
||||||
self._log.debug("Discogs token {0}, secret {1}", token, secret)
|
self._log.debug("Discogs token {}, secret {}", token, secret)
|
||||||
with open(self._tokenfile(), "w") as f:
|
with open(self._tokenfile(), "w") as f:
|
||||||
json.dump({"token": token, "secret": secret}, f)
|
json.dump({"token": token, "secret": secret}, f)
|
||||||
|
|
||||||
|
|
@ -202,7 +202,7 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
||||||
"""Fetches an album by its Discogs ID and returns an AlbumInfo object
|
"""Fetches an album by its Discogs ID and returns an AlbumInfo object
|
||||||
or None if the album is not found.
|
or None if the album is not found.
|
||||||
"""
|
"""
|
||||||
self._log.debug("Searching for release {0}", album_id)
|
self._log.debug("Searching for release {}", album_id)
|
||||||
|
|
||||||
discogs_id = self._extract_id(album_id)
|
discogs_id = self._extract_id(album_id)
|
||||||
|
|
||||||
|
|
@ -216,7 +216,7 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
||||||
except DiscogsAPIError as e:
|
except DiscogsAPIError as e:
|
||||||
if e.status_code != 404:
|
if e.status_code != 404:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"API Error: {0} (query: {1})",
|
"API Error: {} (query: {})",
|
||||||
e,
|
e,
|
||||||
result.data["resource_url"],
|
result.data["resource_url"],
|
||||||
)
|
)
|
||||||
|
|
@ -266,7 +266,7 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
||||||
"""Fetches a master release given its Discogs ID and returns its year
|
"""Fetches a master release given its Discogs ID and returns its year
|
||||||
or None if the master release is not found.
|
or None if the master release is not found.
|
||||||
"""
|
"""
|
||||||
self._log.debug("Getting master release {0}", master_id)
|
self._log.debug("Getting master release {}", master_id)
|
||||||
result = Master(self.discogs_client, {"id": master_id})
|
result = Master(self.discogs_client, {"id": master_id})
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -274,7 +274,7 @@ class DiscogsPlugin(MetadataSourcePlugin):
|
||||||
except DiscogsAPIError as e:
|
except DiscogsAPIError as e:
|
||||||
if e.status_code != 404:
|
if e.status_code != 404:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"API Error: {0} (query: {1})",
|
"API Error: {} (query: {})",
|
||||||
e,
|
e,
|
||||||
result.data["resource_url"],
|
result.data["resource_url"],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ class DuplicatesPlugin(BeetsPlugin):
|
||||||
checksum = getattr(item, key, False)
|
checksum = getattr(item, key, False)
|
||||||
if not checksum:
|
if not checksum:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"key {0} on item {1} not cached:computing checksum",
|
"key {} on item {} not cached:computing checksum",
|
||||||
key,
|
key,
|
||||||
displayable_path(item.path),
|
displayable_path(item.path),
|
||||||
)
|
)
|
||||||
|
|
@ -263,17 +263,17 @@ class DuplicatesPlugin(BeetsPlugin):
|
||||||
setattr(item, key, checksum)
|
setattr(item, key, checksum)
|
||||||
item.store()
|
item.store()
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"computed checksum for {0} using {1}", item.title, key
|
"computed checksum for {} using {}", item.title, key
|
||||||
)
|
)
|
||||||
except subprocess.CalledProcessError as e:
|
except subprocess.CalledProcessError as e:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"failed to checksum {0}: {1}",
|
"failed to checksum {}: {}",
|
||||||
displayable_path(item.path),
|
displayable_path(item.path),
|
||||||
e,
|
e,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"key {0} on item {1} cached:not computing checksum",
|
"key {} on item {} cached:not computing checksum",
|
||||||
key,
|
key,
|
||||||
displayable_path(item.path),
|
displayable_path(item.path),
|
||||||
)
|
)
|
||||||
|
|
@ -293,13 +293,13 @@ class DuplicatesPlugin(BeetsPlugin):
|
||||||
values = [v for v in values if v not in (None, "")]
|
values = [v for v in values if v not in (None, "")]
|
||||||
if strict and len(values) < len(keys):
|
if strict and len(values) < len(keys):
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"some keys {0} on item {1} are null or empty: skipping",
|
"some keys {} on item {} are null or empty: skipping",
|
||||||
keys,
|
keys,
|
||||||
displayable_path(obj.path),
|
displayable_path(obj.path),
|
||||||
)
|
)
|
||||||
elif not strict and not len(values):
|
elif not strict and not len(values):
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"all keys {0} on item {1} are null or empty: skipping",
|
"all keys {} on item {} are null or empty: skipping",
|
||||||
keys,
|
keys,
|
||||||
displayable_path(obj.path),
|
displayable_path(obj.path),
|
||||||
)
|
)
|
||||||
|
|
@ -359,8 +359,8 @@ class DuplicatesPlugin(BeetsPlugin):
|
||||||
value = getattr(o, f, None)
|
value = getattr(o, f, None)
|
||||||
if value:
|
if value:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"key {0} on item {1} is null "
|
"key {} on item {} is null "
|
||||||
"or empty: setting from item {2}",
|
"or empty: setting from item {}",
|
||||||
f,
|
f,
|
||||||
displayable_path(objs[0].path),
|
displayable_path(objs[0].path),
|
||||||
displayable_path(o.path),
|
displayable_path(o.path),
|
||||||
|
|
@ -383,8 +383,8 @@ class DuplicatesPlugin(BeetsPlugin):
|
||||||
missing.album_id = objs[0].id
|
missing.album_id = objs[0].id
|
||||||
missing.add(i._db)
|
missing.add(i._db)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"item {0} missing from album {1}:"
|
"item {} missing from album {}:"
|
||||||
" merging from {2} into {3}",
|
" merging from {} into {}",
|
||||||
missing,
|
missing,
|
||||||
objs[0],
|
objs[0],
|
||||||
displayable_path(o.path),
|
displayable_path(o.path),
|
||||||
|
|
|
||||||
|
|
@ -273,7 +273,7 @@ class EmbedCoverArtPlugin(BeetsPlugin):
|
||||||
"""
|
"""
|
||||||
if self.config["remove_art_file"] and album.artpath:
|
if self.config["remove_art_file"] and album.artpath:
|
||||||
if os.path.isfile(syspath(album.artpath)):
|
if os.path.isfile(syspath(album.artpath)):
|
||||||
self._log.debug("Removing album art file for {0}", album)
|
self._log.debug("Removing album art file for {}", album)
|
||||||
os.remove(syspath(album.artpath))
|
os.remove(syspath(album.artpath))
|
||||||
album.artpath = None
|
album.artpath = None
|
||||||
album.store()
|
album.store()
|
||||||
|
|
|
||||||
|
|
@ -196,7 +196,7 @@ class EmbyUpdate(BeetsPlugin):
|
||||||
# Get authentication token.
|
# Get authentication token.
|
||||||
token = get_token(host, port, headers, auth_data)
|
token = get_token(host, port, headers, auth_data)
|
||||||
if not token:
|
if not token:
|
||||||
self._log.warning("Could not get token for user {0}", username)
|
self._log.warning("Could not get token for user {}", username)
|
||||||
return
|
return
|
||||||
|
|
||||||
# Recreate headers with a token.
|
# Recreate headers with a token.
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ class ExportPlugin(BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
data, item = data_emitter(included_keys or "*")
|
data, item = data_emitter(included_keys or "*")
|
||||||
except (mediafile.UnreadableFileError, OSError) as ex:
|
except (mediafile.UnreadableFileError, OSError) as ex:
|
||||||
self._log.error("cannot read file: {0}", ex)
|
self._log.error("cannot read file: {}", ex)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for key, value in data.items():
|
for key, value in data.items():
|
||||||
|
|
|
||||||
|
|
@ -1541,7 +1541,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
|
||||||
out = candidate
|
out = candidate
|
||||||
assert out.path is not None # help mypy
|
assert out.path is not None # help mypy
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"using {0.LOC} image {1}",
|
"using {.LOC} image {}",
|
||||||
source,
|
source,
|
||||||
util.displayable_path(out.path),
|
util.displayable_path(out.path),
|
||||||
)
|
)
|
||||||
|
|
@ -1576,7 +1576,7 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
|
||||||
message = ui.colorize(
|
message = ui.colorize(
|
||||||
"text_highlight_minor", "has album art"
|
"text_highlight_minor", "has album art"
|
||||||
)
|
)
|
||||||
self._log.info("{0}: {1}", album, message)
|
self._log.info("{}: {}", album, message)
|
||||||
else:
|
else:
|
||||||
# In ordinary invocations, look for images on the
|
# In ordinary invocations, look for images on the
|
||||||
# filesystem. When forcing, however, always go to the Web
|
# filesystem. When forcing, however, always go to the Web
|
||||||
|
|
@ -1589,4 +1589,4 @@ class FetchArtPlugin(plugins.BeetsPlugin, RequestMixin):
|
||||||
message = ui.colorize("text_success", "found album art")
|
message = ui.colorize("text_success", "found album art")
|
||||||
else:
|
else:
|
||||||
message = ui.colorize("text_error", "no art found")
|
message = ui.colorize("text_error", "no art found")
|
||||||
self._log.info("{0}: {1}", album, message)
|
self._log.info("{}: {}", album, message)
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
|
||||||
{
|
{
|
||||||
"auto": True,
|
"auto": True,
|
||||||
"drop": False,
|
"drop": False,
|
||||||
"format": "feat. {0}",
|
"format": "feat. {}",
|
||||||
"keep_in_artist": False,
|
"keep_in_artist": False,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
@ -151,10 +151,10 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
|
||||||
# In case the artist is kept, do not update the artist fields.
|
# In case the artist is kept, do not update the artist fields.
|
||||||
if keep_in_artist_field:
|
if keep_in_artist_field:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"artist: {0} (Not changing due to keep_in_artist)", item.artist
|
"artist: {} (Not changing due to keep_in_artist)", item.artist
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._log.info("artist: {0} -> {1}", item.artist, item.albumartist)
|
self._log.info("artist: {} -> {}", item.artist, item.albumartist)
|
||||||
item.artist = item.albumartist
|
item.artist = item.albumartist
|
||||||
|
|
||||||
if item.artist_sort:
|
if item.artist_sort:
|
||||||
|
|
@ -167,7 +167,7 @@ class FtInTitlePlugin(plugins.BeetsPlugin):
|
||||||
feat_format = self.config["format"].as_str()
|
feat_format = self.config["format"].as_str()
|
||||||
new_format = feat_format.format(feat_part)
|
new_format = feat_format.format(feat_part)
|
||||||
new_title = f"{item.title} {new_format}"
|
new_title = f"{item.title} {new_format}"
|
||||||
self._log.info("title: {0} -> {1}", item.title, new_title)
|
self._log.info("title: {} -> {}", item.title, new_title)
|
||||||
item.title = new_title
|
item.title = new_title
|
||||||
|
|
||||||
def ft_in_title(
|
def ft_in_title(
|
||||||
|
|
|
||||||
|
|
@ -62,7 +62,7 @@ class HookPlugin(BeetsPlugin):
|
||||||
def create_and_register_hook(self, event, command):
|
def create_and_register_hook(self, event, command):
|
||||||
def hook_function(**kwargs):
|
def hook_function(**kwargs):
|
||||||
if command is None or len(command) == 0:
|
if command is None or len(command) == 0:
|
||||||
self._log.error('invalid command "{0}"', command)
|
self._log.error('invalid command "{}"', command)
|
||||||
return
|
return
|
||||||
|
|
||||||
# For backwards compatibility, use a string formatter that decodes
|
# For backwards compatibility, use a string formatter that decodes
|
||||||
|
|
@ -74,7 +74,7 @@ class HookPlugin(BeetsPlugin):
|
||||||
]
|
]
|
||||||
|
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
'running command "{0}" for event {1}',
|
'running command "{}" for event {}',
|
||||||
" ".join(command_pieces),
|
" ".join(command_pieces),
|
||||||
event,
|
event,
|
||||||
)
|
)
|
||||||
|
|
@ -83,9 +83,9 @@ class HookPlugin(BeetsPlugin):
|
||||||
subprocess.check_call(command_pieces)
|
subprocess.check_call(command_pieces)
|
||||||
except subprocess.CalledProcessError as exc:
|
except subprocess.CalledProcessError as exc:
|
||||||
self._log.error(
|
self._log.error(
|
||||||
"hook for {0} exited with status {1}", event, exc.returncode
|
"hook for {} exited with status {}", event, exc.returncode
|
||||||
)
|
)
|
||||||
except OSError as exc:
|
except OSError as exc:
|
||||||
self._log.error("hook for {0} failed: {1}", event, exc)
|
self._log.error("hook for {} failed: {}", event, exc)
|
||||||
|
|
||||||
self.register_listener(event, hook_function)
|
self.register_listener(event, hook_function)
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,10 @@ class IHatePlugin(BeetsPlugin):
|
||||||
self._log.debug("processing your hate")
|
self._log.debug("processing your hate")
|
||||||
if self.do_i_hate_this(task, skip_queries):
|
if self.do_i_hate_this(task, skip_queries):
|
||||||
task.choice_flag = Action.SKIP
|
task.choice_flag = Action.SKIP
|
||||||
self._log.info("skipped: {0}", summary(task))
|
self._log.info("skipped: {}", summary(task))
|
||||||
return
|
return
|
||||||
if self.do_i_hate_this(task, warn_queries):
|
if self.do_i_hate_this(task, warn_queries):
|
||||||
self._log.info("you may hate this: {0}", summary(task))
|
self._log.info("you may hate this: {}", summary(task))
|
||||||
else:
|
else:
|
||||||
self._log.debug("nothing to do")
|
self._log.debug("nothing to do")
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
||||||
mtime = os.stat(util.syspath(source)).st_mtime
|
mtime = os.stat(util.syspath(source)).st_mtime
|
||||||
self.item_mtime[destination] = mtime
|
self.item_mtime[destination] = mtime
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Recorded mtime {0} for item '{1}' imported from '{2}'",
|
"Recorded mtime {} for item '{}' imported from '{}'",
|
||||||
mtime,
|
mtime,
|
||||||
util.displayable_path(destination),
|
util.displayable_path(destination),
|
||||||
util.displayable_path(source),
|
util.displayable_path(source),
|
||||||
|
|
@ -103,7 +103,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
||||||
def update_album_times(self, lib, album):
|
def update_album_times(self, lib, album):
|
||||||
if self.reimported_album(album):
|
if self.reimported_album(album):
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Album '{0}' is reimported, skipping import of "
|
"Album '{}' is reimported, skipping import of "
|
||||||
"added dates for the album and its items.",
|
"added dates for the album and its items.",
|
||||||
util.displayable_path(album.path),
|
util.displayable_path(album.path),
|
||||||
)
|
)
|
||||||
|
|
@ -119,7 +119,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
||||||
item.store()
|
item.store()
|
||||||
album.added = min(album_mtimes)
|
album.added = min(album_mtimes)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Import of album '{0}', selected album.added={1} "
|
"Import of album '{}', selected album.added={} "
|
||||||
"from item file mtimes.",
|
"from item file mtimes.",
|
||||||
album.album,
|
album.album,
|
||||||
album.added,
|
album.added,
|
||||||
|
|
@ -129,7 +129,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
||||||
def update_item_times(self, lib, item):
|
def update_item_times(self, lib, item):
|
||||||
if self.reimported_item(item):
|
if self.reimported_item(item):
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Item '{0}' is reimported, skipping import of added date.",
|
"Item '{}' is reimported, skipping import of added date.",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
@ -139,7 +139,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
||||||
if self.config["preserve_mtimes"].get(bool):
|
if self.config["preserve_mtimes"].get(bool):
|
||||||
self.write_item_mtime(item, mtime)
|
self.write_item_mtime(item, mtime)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Import of item '{0}', selected item.added={1}",
|
"Import of item '{}', selected item.added={}",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
item.added,
|
item.added,
|
||||||
)
|
)
|
||||||
|
|
@ -153,7 +153,7 @@ class ImportAddedPlugin(BeetsPlugin):
|
||||||
if self.config["preserve_write_mtimes"].get(bool):
|
if self.config["preserve_write_mtimes"].get(bool):
|
||||||
self.write_item_mtime(item, item.added)
|
self.write_item_mtime(item, item.added)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"Write of item '{0}', selected item.added={1}",
|
"Write of item '{}', selected item.added={}",
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
item.added,
|
item.added,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ class ImportFeedsPlugin(BeetsPlugin):
|
||||||
if "echo" in formats:
|
if "echo" in formats:
|
||||||
self._log.info("Location of imported music:")
|
self._log.info("Location of imported music:")
|
||||||
for path in paths:
|
for path in paths:
|
||||||
self._log.info(" {0}", path)
|
self._log.info(" {}", path)
|
||||||
|
|
||||||
def album_imported(self, lib, album):
|
def album_imported(self, lib, album):
|
||||||
self._record_items(lib, album.album, album.items())
|
self._record_items(lib, album.album, album.items())
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ class InfoPlugin(BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
data, item = data_emitter(included_keys or "*")
|
data, item = data_emitter(included_keys or "*")
|
||||||
except (mediafile.UnreadableFileError, OSError) as ex:
|
except (mediafile.UnreadableFileError, OSError) as ex:
|
||||||
self._log.error("cannot read file: {0}", ex)
|
self._log.error("cannot read file: {}", ex)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if opts.summarize:
|
if opts.summarize:
|
||||||
|
|
|
||||||
|
|
@ -60,14 +60,14 @@ class InlinePlugin(BeetsPlugin):
|
||||||
for key, view in itertools.chain(
|
for key, view in itertools.chain(
|
||||||
config["item_fields"].items(), config["pathfields"].items()
|
config["item_fields"].items(), config["pathfields"].items()
|
||||||
):
|
):
|
||||||
self._log.debug("adding item field {0}", key)
|
self._log.debug("adding item field {}", key)
|
||||||
func = self.compile_inline(view.as_str(), False)
|
func = self.compile_inline(view.as_str(), False)
|
||||||
if func is not None:
|
if func is not None:
|
||||||
self.template_fields[key] = func
|
self.template_fields[key] = func
|
||||||
|
|
||||||
# Album fields.
|
# Album fields.
|
||||||
for key, view in config["album_fields"].items():
|
for key, view in config["album_fields"].items():
|
||||||
self._log.debug("adding album field {0}", key)
|
self._log.debug("adding album field {}", key)
|
||||||
func = self.compile_inline(view.as_str(), True)
|
func = self.compile_inline(view.as_str(), True)
|
||||||
if func is not None:
|
if func is not None:
|
||||||
self.album_template_fields[key] = func
|
self.album_template_fields[key] = func
|
||||||
|
|
@ -87,7 +87,7 @@ class InlinePlugin(BeetsPlugin):
|
||||||
func = _compile_func(python_code)
|
func = _compile_func(python_code)
|
||||||
except SyntaxError:
|
except SyntaxError:
|
||||||
self._log.error(
|
self._log.error(
|
||||||
"syntax error in inline field definition:\n{0}",
|
"syntax error in inline field definition:\n{}",
|
||||||
traceback.format_exc(),
|
traceback.format_exc(),
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
for album in lib.albums(args):
|
for album in lib.albums(args):
|
||||||
if len(album.items()) == 0:
|
if len(album.items()) == 0:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"{0} does not contain items, aborting", album
|
"{} does not contain items, aborting", album
|
||||||
)
|
)
|
||||||
|
|
||||||
self.ipfs_add(album)
|
self.ipfs_add(album)
|
||||||
|
|
@ -122,13 +122,13 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
if album.ipfs:
|
if album.ipfs:
|
||||||
self._log.debug("{0} already added", album_dir)
|
self._log.debug("{} already added", album_dir)
|
||||||
# Already added to ipfs
|
# Already added to ipfs
|
||||||
return False
|
return False
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self._log.info("Adding {0} to ipfs", album_dir)
|
self._log.info("Adding {} to ipfs", album_dir)
|
||||||
|
|
||||||
if self.config["nocopy"]:
|
if self.config["nocopy"]:
|
||||||
cmd = "ipfs add --nocopy -q -r".split()
|
cmd = "ipfs add --nocopy -q -r".split()
|
||||||
|
|
@ -138,7 +138,7 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
output = util.command_output(cmd).stdout.split()
|
output = util.command_output(cmd).stdout.split()
|
||||||
except (OSError, subprocess.CalledProcessError) as exc:
|
except (OSError, subprocess.CalledProcessError) as exc:
|
||||||
self._log.error("Failed to add {0}, error: {1}", album_dir, exc)
|
self._log.error("Failed to add {}, error: {}", album_dir, exc)
|
||||||
return False
|
return False
|
||||||
length = len(output)
|
length = len(output)
|
||||||
|
|
||||||
|
|
@ -146,12 +146,12 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
if linenr == length - 1:
|
if linenr == length - 1:
|
||||||
# last printed line is the album hash
|
# last printed line is the album hash
|
||||||
self._log.info("album: {0}", line)
|
self._log.info("album: {}", line)
|
||||||
album.ipfs = line
|
album.ipfs = line
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
item = album.items()[linenr]
|
item = album.items()[linenr]
|
||||||
self._log.info("item: {0}", line)
|
self._log.info("item: {}", line)
|
||||||
item.ipfs = line
|
item.ipfs = line
|
||||||
item.store()
|
item.store()
|
||||||
except IndexError:
|
except IndexError:
|
||||||
|
|
@ -180,11 +180,11 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
util.command_output(cmd)
|
util.command_output(cmd)
|
||||||
except (OSError, subprocess.CalledProcessError) as err:
|
except (OSError, subprocess.CalledProcessError) as err:
|
||||||
self._log.error(
|
self._log.error(
|
||||||
"Failed to get {0} from ipfs.\n{1}", _hash, err.output
|
"Failed to get {} from ipfs.\n{}", _hash, err.output
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self._log.info("Getting {0} from ipfs", _hash)
|
self._log.info("Getting {} from ipfs", _hash)
|
||||||
imp = ui.commands.TerminalImportSession(
|
imp = ui.commands.TerminalImportSession(
|
||||||
lib, loghandler=None, query=None, paths=[_hash]
|
lib, loghandler=None, query=None, paths=[_hash]
|
||||||
)
|
)
|
||||||
|
|
@ -208,7 +208,7 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
msg = f"Failed to publish library. Error: {err}"
|
msg = f"Failed to publish library. Error: {err}"
|
||||||
self._log.error(msg)
|
self._log.error(msg)
|
||||||
return False
|
return False
|
||||||
self._log.info("hash of library: {0}", output)
|
self._log.info("hash of library: {}", output)
|
||||||
|
|
||||||
def ipfs_import(self, lib, args):
|
def ipfs_import(self, lib, args):
|
||||||
_hash = args[0]
|
_hash = args[0]
|
||||||
|
|
@ -306,7 +306,7 @@ class IPFSPlugin(BeetsPlugin):
|
||||||
items.append(item)
|
items.append(item)
|
||||||
if len(items) < 1:
|
if len(items) < 1:
|
||||||
return False
|
return False
|
||||||
self._log.info("Adding '{0}' to temporary library", album)
|
self._log.info("Adding '{}' to temporary library", album)
|
||||||
new_album = tmplib.add_album(items)
|
new_album = tmplib.add_album(items)
|
||||||
new_album.ipfs = album.ipfs
|
new_album.ipfs = album.ipfs
|
||||||
new_album.store(inherit=False)
|
new_album.store(inherit=False)
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ class KeyFinderPlugin(BeetsPlugin):
|
||||||
command + [util.syspath(item.path)]
|
command + [util.syspath(item.path)]
|
||||||
).stdout
|
).stdout
|
||||||
except (subprocess.CalledProcessError, OSError) as exc:
|
except (subprocess.CalledProcessError, OSError) as exc:
|
||||||
self._log.error("execution failed: {0}", exc)
|
self._log.error("execution failed: {}", exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -73,7 +73,7 @@ class KeyFinderPlugin(BeetsPlugin):
|
||||||
except IndexError:
|
except IndexError:
|
||||||
# Sometimes keyfinder-cli returns 0 but with no key, usually
|
# Sometimes keyfinder-cli returns 0 but with no key, usually
|
||||||
# when the file is silent or corrupt, so we log and skip.
|
# when the file is silent or corrupt, so we log and skip.
|
||||||
self._log.error("no key returned for path: {0}", item.path)
|
self._log.error("no key returned for path: {}", item.path)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -84,7 +84,7 @@ class KeyFinderPlugin(BeetsPlugin):
|
||||||
|
|
||||||
item["initial_key"] = key
|
item["initial_key"] = key
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"added computed initial key {0} for {1}",
|
"added computed initial key {} for {}",
|
||||||
key,
|
key,
|
||||||
util.displayable_path(item.path),
|
util.displayable_path(item.path),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -96,10 +96,10 @@ class KodiUpdate(BeetsPlugin):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Kodi update triggered for {0}:{1}",
|
"Kodi update triggered for {}:{}",
|
||||||
instance["host"],
|
instance["host"],
|
||||||
instance["port"],
|
instance["port"],
|
||||||
)
|
)
|
||||||
except requests.exceptions.RequestException as e:
|
except requests.exceptions.RequestException as e:
|
||||||
self._log.warning("Kodi update failed: {0}", str(e))
|
self._log.warning("Kodi update failed: {}", str(e))
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -139,7 +139,7 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
||||||
|
|
||||||
# Read the tree
|
# Read the tree
|
||||||
if c14n_filename:
|
if c14n_filename:
|
||||||
self._log.debug("Loading canonicalization tree {0}", c14n_filename)
|
self._log.debug("Loading canonicalization tree {}", c14n_filename)
|
||||||
c14n_filename = normpath(c14n_filename)
|
c14n_filename = normpath(c14n_filename)
|
||||||
with codecs.open(c14n_filename, "r", encoding="utf-8") as f:
|
with codecs.open(c14n_filename, "r", encoding="utf-8") as f:
|
||||||
genres_tree = yaml.safe_load(f)
|
genres_tree = yaml.safe_load(f)
|
||||||
|
|
@ -607,12 +607,12 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
res = obj.get_top_tags()
|
res = obj.get_top_tags()
|
||||||
except PYLAST_EXCEPTIONS as exc:
|
except PYLAST_EXCEPTIONS as exc:
|
||||||
self._log.debug("last.fm error: {0}", exc)
|
self._log.debug("last.fm error: {}", exc)
|
||||||
return []
|
return []
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
# Isolate bugs in pylast.
|
# Isolate bugs in pylast.
|
||||||
self._log.debug("{}", traceback.format_exc())
|
self._log.debug("{}", traceback.format_exc())
|
||||||
self._log.error("error in pylast library: {0}", exc)
|
self._log.error("error in pylast library: {}", exc)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
# Filter by weight (optionally).
|
# Filter by weight (optionally).
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ def import_lastfm(lib, log):
|
||||||
if not user:
|
if not user:
|
||||||
raise ui.UserError("You must specify a user name for lastimport")
|
raise ui.UserError("You must specify a user name for lastimport")
|
||||||
|
|
||||||
log.info("Fetching last.fm library for @{0}", user)
|
log.info("Fetching last.fm library for @{}", user)
|
||||||
|
|
||||||
page_total = 1
|
page_total = 1
|
||||||
page_current = 0
|
page_current = 0
|
||||||
|
|
@ -130,7 +130,7 @@ def import_lastfm(lib, log):
|
||||||
# Iterate through a yet to be known page total count
|
# Iterate through a yet to be known page total count
|
||||||
while page_current < page_total:
|
while page_current < page_total:
|
||||||
log.info(
|
log.info(
|
||||||
"Querying page #{0}{1}...",
|
"Querying page #{}{}...",
|
||||||
page_current + 1,
|
page_current + 1,
|
||||||
f"/{page_total}" if page_total > 1 else "",
|
f"/{page_total}" if page_total > 1 else "",
|
||||||
)
|
)
|
||||||
|
|
@ -147,27 +147,27 @@ def import_lastfm(lib, log):
|
||||||
unknown_total += unknown
|
unknown_total += unknown
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
log.error("ERROR: unable to read page #{0}", page_current + 1)
|
log.error("ERROR: unable to read page #{}", page_current + 1)
|
||||||
if retry < retry_limit:
|
if retry < retry_limit:
|
||||||
log.info(
|
log.info(
|
||||||
"Retrying page #{0}... ({1}/{2} retry)",
|
"Retrying page #{}... ({}/{} retry)",
|
||||||
page_current + 1,
|
page_current + 1,
|
||||||
retry + 1,
|
retry + 1,
|
||||||
retry_limit,
|
retry_limit,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
log.error(
|
log.error(
|
||||||
"FAIL: unable to fetch page #{0}, ",
|
"FAIL: unable to fetch page #{}, ",
|
||||||
"tried {1} times",
|
"tried {} times",
|
||||||
page_current,
|
page_current,
|
||||||
retry + 1,
|
retry + 1,
|
||||||
)
|
)
|
||||||
page_current += 1
|
page_current += 1
|
||||||
|
|
||||||
log.info("... done!")
|
log.info("... done!")
|
||||||
log.info("finished processing {0} song pages", page_total)
|
log.info("finished processing {} song pages", page_total)
|
||||||
log.info("{0} unknown play-counts", unknown_total)
|
log.info("{} unknown play-counts", unknown_total)
|
||||||
log.info("{0} play-counts imported", found_total)
|
log.info("{} play-counts imported", found_total)
|
||||||
|
|
||||||
|
|
||||||
def fetch_tracks(user, page, limit):
|
def fetch_tracks(user, page, limit):
|
||||||
|
|
@ -201,7 +201,7 @@ def process_tracks(lib, tracks, log):
|
||||||
total = len(tracks)
|
total = len(tracks)
|
||||||
total_found = 0
|
total_found = 0
|
||||||
total_fails = 0
|
total_fails = 0
|
||||||
log.info("Received {0} tracks in this page, processing...", total)
|
log.info("Received {} tracks in this page, processing...", total)
|
||||||
|
|
||||||
for num in range(0, total):
|
for num in range(0, total):
|
||||||
song = None
|
song = None
|
||||||
|
|
@ -220,7 +220,7 @@ def process_tracks(lib, tracks, log):
|
||||||
else None
|
else None
|
||||||
)
|
)
|
||||||
|
|
||||||
log.debug("query: {0} - {1} ({2})", artist, title, album)
|
log.debug("query: {} - {} ({})", artist, title, album)
|
||||||
|
|
||||||
# First try to query by musicbrainz's trackid
|
# First try to query by musicbrainz's trackid
|
||||||
if trackid:
|
if trackid:
|
||||||
|
|
@ -231,7 +231,7 @@ def process_tracks(lib, tracks, log):
|
||||||
# If not, try just album/title
|
# If not, try just album/title
|
||||||
if song is None:
|
if song is None:
|
||||||
log.debug(
|
log.debug(
|
||||||
"no album match, trying by album/title: {0} - {1}", album, title
|
"no album match, trying by album/title: {} - {}", album, title
|
||||||
)
|
)
|
||||||
query = dbcore.AndQuery(
|
query = dbcore.AndQuery(
|
||||||
[
|
[
|
||||||
|
|
@ -268,7 +268,7 @@ def process_tracks(lib, tracks, log):
|
||||||
count = int(song.get("play_count", 0))
|
count = int(song.get("play_count", 0))
|
||||||
new_count = int(tracks[num].get("playcount", 1))
|
new_count = int(tracks[num].get("playcount", 1))
|
||||||
log.debug(
|
log.debug(
|
||||||
"match: {0} - {1} ({2}) updating: play_count {3} => {4}",
|
"match: {} - {} ({}) updating: play_count {} => {}",
|
||||||
song.artist,
|
song.artist,
|
||||||
song.title,
|
song.title,
|
||||||
song.album,
|
song.album,
|
||||||
|
|
@ -280,11 +280,11 @@ def process_tracks(lib, tracks, log):
|
||||||
total_found += 1
|
total_found += 1
|
||||||
else:
|
else:
|
||||||
total_fails += 1
|
total_fails += 1
|
||||||
log.info(" - No match: {0} - {1} ({2})", artist, title, album)
|
log.info(" - No match: {} - {} ({})", artist, title, album)
|
||||||
|
|
||||||
if total_fails > 0:
|
if total_fails > 0:
|
||||||
log.info(
|
log.info(
|
||||||
"Acquired {0}/{1} play-counts ({2} unknown)",
|
"Acquired {}/{} play-counts ({} unknown)",
|
||||||
total_found,
|
total_found,
|
||||||
total,
|
total,
|
||||||
total_fails,
|
total_fails,
|
||||||
|
|
|
||||||
|
|
@ -48,8 +48,8 @@ class ListenBrainzPlugin(BeetsPlugin):
|
||||||
found_total += found
|
found_total += found
|
||||||
unknown_total += unknown
|
unknown_total += unknown
|
||||||
log.info("... done!")
|
log.info("... done!")
|
||||||
log.info("{0} unknown play-counts", unknown_total)
|
log.info("{} unknown play-counts", unknown_total)
|
||||||
log.info("{0} play-counts imported", found_total)
|
log.info("{} play-counts imported", found_total)
|
||||||
|
|
||||||
def _make_request(self, url, params=None):
|
def _make_request(self, url, params=None):
|
||||||
"""Makes a request to the ListenBrainz API."""
|
"""Makes a request to the ListenBrainz API."""
|
||||||
|
|
|
||||||
|
|
@ -1090,7 +1090,7 @@ class LyricsPlugin(RequestHandler, plugins.BeetsPlugin):
|
||||||
return
|
return
|
||||||
|
|
||||||
if lyrics := self.find_lyrics(item):
|
if lyrics := self.find_lyrics(item):
|
||||||
self.info("🟢 Found lyrics: {0}", item)
|
self.info("🟢 Found lyrics: {}", item)
|
||||||
if translator := self.translator:
|
if translator := self.translator:
|
||||||
lyrics = translator.translate(lyrics, item.lyrics)
|
lyrics = translator.translate(lyrics, item.lyrics)
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -154,10 +154,10 @@ class MusicBrainzCollectionPlugin(BeetsPlugin):
|
||||||
if re.match(UUID_REGEX, aid):
|
if re.match(UUID_REGEX, aid):
|
||||||
album_ids.append(aid)
|
album_ids.append(aid)
|
||||||
else:
|
else:
|
||||||
self._log.info("skipping invalid MBID: {0}", aid)
|
self._log.info("skipping invalid MBID: {}", aid)
|
||||||
|
|
||||||
# Submit to MusicBrainz.
|
# Submit to MusicBrainz.
|
||||||
self._log.info("Updating MusicBrainz collection {0}...", collection_id)
|
self._log.info("Updating MusicBrainz collection {}...", collection_id)
|
||||||
submit_albums(collection_id, album_ids)
|
submit_albums(collection_id, album_ids)
|
||||||
if remove_missing:
|
if remove_missing:
|
||||||
self.remove_missing(collection_id, lib.albums())
|
self.remove_missing(collection_id, lib.albums())
|
||||||
|
|
|
||||||
|
|
@ -226,7 +226,7 @@ class MissingPlugin(BeetsPlugin):
|
||||||
for track_info in album_info.tracks:
|
for track_info in album_info.tracks:
|
||||||
if track_info.track_id not in item_mbids:
|
if track_info.track_id not in item_mbids:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"track {0} in album {1}",
|
"track {} in album {}",
|
||||||
track_info.track_id,
|
track_info.track_id,
|
||||||
album_info.album_id,
|
album_info.album_id,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -51,8 +51,8 @@ class MPDClientWrapper:
|
||||||
if not self.strip_path.endswith("/"):
|
if not self.strip_path.endswith("/"):
|
||||||
self.strip_path += "/"
|
self.strip_path += "/"
|
||||||
|
|
||||||
self._log.debug("music_directory: {0}", self.music_directory)
|
self._log.debug("music_directory: {}", self.music_directory)
|
||||||
self._log.debug("strip_path: {0}", self.strip_path)
|
self._log.debug("strip_path: {}", self.strip_path)
|
||||||
|
|
||||||
self.client = mpd.MPDClient()
|
self.client = mpd.MPDClient()
|
||||||
|
|
||||||
|
|
@ -64,7 +64,7 @@ class MPDClientWrapper:
|
||||||
if host[0] in ["/", "~"]:
|
if host[0] in ["/", "~"]:
|
||||||
host = os.path.expanduser(host)
|
host = os.path.expanduser(host)
|
||||||
|
|
||||||
self._log.info("connecting to {0}:{1}", host, port)
|
self._log.info("connecting to {}:{}", host, port)
|
||||||
try:
|
try:
|
||||||
self.client.connect(host, port)
|
self.client.connect(host, port)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
|
|
@ -89,7 +89,7 @@ class MPDClientWrapper:
|
||||||
try:
|
try:
|
||||||
return getattr(self.client, command)()
|
return getattr(self.client, command)()
|
||||||
except (OSError, mpd.ConnectionError) as err:
|
except (OSError, mpd.ConnectionError) as err:
|
||||||
self._log.error("{0}", err)
|
self._log.error("{}", err)
|
||||||
|
|
||||||
if retries <= 0:
|
if retries <= 0:
|
||||||
# if we exited without breaking, we couldn't reconnect in time :(
|
# if we exited without breaking, we couldn't reconnect in time :(
|
||||||
|
|
@ -123,7 +123,7 @@ class MPDClientWrapper:
|
||||||
result = os.path.join(self.music_directory, file)
|
result = os.path.join(self.music_directory, file)
|
||||||
else:
|
else:
|
||||||
result = entry["file"]
|
result = entry["file"]
|
||||||
self._log.debug("returning: {0}", result)
|
self._log.debug("returning: {}", result)
|
||||||
return result, entry.get("id")
|
return result, entry.get("id")
|
||||||
|
|
||||||
def status(self):
|
def status(self):
|
||||||
|
|
@ -169,7 +169,7 @@ class MPDStats:
|
||||||
if item:
|
if item:
|
||||||
return item
|
return item
|
||||||
else:
|
else:
|
||||||
self._log.info("item not found: {0}", displayable_path(path))
|
self._log.info("item not found: {}", displayable_path(path))
|
||||||
|
|
||||||
def update_item(self, item, attribute, value=None, increment=None):
|
def update_item(self, item, attribute, value=None, increment=None):
|
||||||
"""Update the beets item. Set attribute to value or increment the value
|
"""Update the beets item. Set attribute to value or increment the value
|
||||||
|
|
@ -188,7 +188,7 @@ class MPDStats:
|
||||||
item.store()
|
item.store()
|
||||||
|
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"updated: {0} = {1} [{2}]",
|
"updated: {} = {} [{}]",
|
||||||
attribute,
|
attribute,
|
||||||
item[attribute],
|
item[attribute],
|
||||||
displayable_path(item.path),
|
displayable_path(item.path),
|
||||||
|
|
@ -234,12 +234,12 @@ class MPDStats:
|
||||||
def handle_played(self, song):
|
def handle_played(self, song):
|
||||||
"""Updates the play count of a song."""
|
"""Updates the play count of a song."""
|
||||||
self.update_item(song["beets_item"], "play_count", increment=1)
|
self.update_item(song["beets_item"], "play_count", increment=1)
|
||||||
self._log.info("played {0}", displayable_path(song["path"]))
|
self._log.info("played {}", displayable_path(song["path"]))
|
||||||
|
|
||||||
def handle_skipped(self, song):
|
def handle_skipped(self, song):
|
||||||
"""Updates the skip count of a song."""
|
"""Updates the skip count of a song."""
|
||||||
self.update_item(song["beets_item"], "skip_count", increment=1)
|
self.update_item(song["beets_item"], "skip_count", increment=1)
|
||||||
self._log.info("skipped {0}", displayable_path(song["path"]))
|
self._log.info("skipped {}", displayable_path(song["path"]))
|
||||||
|
|
||||||
def on_stop(self, status):
|
def on_stop(self, status):
|
||||||
self._log.info("stop")
|
self._log.info("stop")
|
||||||
|
|
@ -278,11 +278,11 @@ class MPDStats:
|
||||||
self.handle_song_change(self.now_playing)
|
self.handle_song_change(self.now_playing)
|
||||||
|
|
||||||
if is_url(path):
|
if is_url(path):
|
||||||
self._log.info("playing stream {0}", displayable_path(path))
|
self._log.info("playing stream {}", displayable_path(path))
|
||||||
self.now_playing = None
|
self.now_playing = None
|
||||||
return
|
return
|
||||||
|
|
||||||
self._log.info("playing {0}", displayable_path(path))
|
self._log.info("playing {}", displayable_path(path))
|
||||||
|
|
||||||
self.now_playing = {
|
self.now_playing = {
|
||||||
"started": time.time(),
|
"started": time.time(),
|
||||||
|
|
@ -312,7 +312,7 @@ class MPDStats:
|
||||||
if handler:
|
if handler:
|
||||||
handler(status)
|
handler(status)
|
||||||
else:
|
else:
|
||||||
self._log.debug('unhandled status "{0}"', status)
|
self._log.debug('unhandled status "{}"', status)
|
||||||
|
|
||||||
events = self.mpd.events()
|
events = self.mpd.events()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ class MPDUpdatePlugin(BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
s = BufferedSocket(host, port)
|
s = BufferedSocket(host, port)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self._log.warning("MPD connection failed: {0}", str(e.strerror))
|
self._log.warning("MPD connection failed: {}", str(e.strerror))
|
||||||
return
|
return
|
||||||
|
|
||||||
resp = s.readline()
|
resp = s.readline()
|
||||||
|
|
|
||||||
|
|
@ -836,7 +836,7 @@ class MusicBrainzPlugin(MetadataSourcePlugin):
|
||||||
"""
|
"""
|
||||||
self._log.debug("Requesting MusicBrainz release {}", album_id)
|
self._log.debug("Requesting MusicBrainz release {}", album_id)
|
||||||
if not (albumid := self._extract_id(album_id)):
|
if not (albumid := self._extract_id(album_id)):
|
||||||
self._log.debug("Invalid MBID ({0}).", album_id)
|
self._log.debug("Invalid MBID ({}).", album_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -873,7 +873,7 @@ class MusicBrainzPlugin(MetadataSourcePlugin):
|
||||||
or None if no track is found. May raise a MusicBrainzAPIError.
|
or None if no track is found. May raise a MusicBrainzAPIError.
|
||||||
"""
|
"""
|
||||||
if not (trackid := self._extract_id(track_id)):
|
if not (trackid := self._extract_id(track_id)):
|
||||||
self._log.debug("Invalid MBID ({0}).", track_id)
|
self._log.debug("Invalid MBID ({}).", track_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ class RgTask:
|
||||||
item.rg_track_peak = track_gain.peak
|
item.rg_track_peak = track_gain.peak
|
||||||
item.store()
|
item.store()
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"applied track gain {0} LU, peak {1} of FS",
|
"applied track gain {} LU, peak {} of FS",
|
||||||
item.rg_track_gain,
|
item.rg_track_gain,
|
||||||
item.rg_track_peak,
|
item.rg_track_peak,
|
||||||
)
|
)
|
||||||
|
|
@ -155,7 +155,7 @@ class RgTask:
|
||||||
item.rg_album_peak = album_gain.peak
|
item.rg_album_peak = album_gain.peak
|
||||||
item.store()
|
item.store()
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"applied album gain {0} LU, peak {1} of FS",
|
"applied album gain {} LU, peak {} of FS",
|
||||||
item.rg_album_gain,
|
item.rg_album_gain,
|
||||||
item.rg_album_peak,
|
item.rg_album_peak,
|
||||||
)
|
)
|
||||||
|
|
@ -175,7 +175,7 @@ class RgTask:
|
||||||
self._store_track_gain(item, self.track_gains[0])
|
self._store_track_gain(item, self.track_gains[0])
|
||||||
if write:
|
if write:
|
||||||
item.try_write()
|
item.try_write()
|
||||||
self._log.debug("done analyzing {0}", item)
|
self._log.debug("done analyzing {}", item)
|
||||||
|
|
||||||
def _store_album(self, write: bool):
|
def _store_album(self, write: bool):
|
||||||
"""Store track/album gains for all tracks of the task in the database."""
|
"""Store track/album gains for all tracks of the task in the database."""
|
||||||
|
|
@ -196,7 +196,7 @@ class RgTask:
|
||||||
self._store_album_gain(item, self.album_gain)
|
self._store_album_gain(item, self.album_gain)
|
||||||
if write:
|
if write:
|
||||||
item.try_write()
|
item.try_write()
|
||||||
self._log.debug("done analyzing {0}", item)
|
self._log.debug("done analyzing {}", item)
|
||||||
|
|
||||||
def store(self, write: bool):
|
def store(self, write: bool):
|
||||||
"""Store computed gains for the items of this task in the database."""
|
"""Store computed gains for the items of this task in the database."""
|
||||||
|
|
@ -230,7 +230,7 @@ class R128Task(RgTask):
|
||||||
def _store_track_gain(self, item: Item, track_gain: Gain):
|
def _store_track_gain(self, item: Item, track_gain: Gain):
|
||||||
item.r128_track_gain = track_gain.gain
|
item.r128_track_gain = track_gain.gain
|
||||||
item.store()
|
item.store()
|
||||||
self._log.debug("applied r128 track gain {0} LU", item.r128_track_gain)
|
self._log.debug("applied r128 track gain {} LU", item.r128_track_gain)
|
||||||
|
|
||||||
def _store_album_gain(self, item: Item, album_gain: Gain):
|
def _store_album_gain(self, item: Item, album_gain: Gain):
|
||||||
"""
|
"""
|
||||||
|
|
@ -239,7 +239,7 @@ class R128Task(RgTask):
|
||||||
"""
|
"""
|
||||||
item.r128_album_gain = album_gain.gain
|
item.r128_album_gain = album_gain.gain
|
||||||
item.store()
|
item.store()
|
||||||
self._log.debug("applied r128 album gain {0} LU", item.r128_album_gain)
|
self._log.debug("applied r128 album gain {} LU", item.r128_album_gain)
|
||||||
|
|
||||||
|
|
||||||
AnyRgTask = TypeVar("AnyRgTask", bound=RgTask)
|
AnyRgTask = TypeVar("AnyRgTask", bound=RgTask)
|
||||||
|
|
@ -428,7 +428,7 @@ class FfmpegBackend(Backend):
|
||||||
# call ffmpeg
|
# call ffmpeg
|
||||||
self._log.debug(f"analyzing {item}")
|
self._log.debug(f"analyzing {item}")
|
||||||
cmd = self._construct_cmd(item, peak_method)
|
cmd = self._construct_cmd(item, peak_method)
|
||||||
self._log.debug("executing {0}", " ".join(map(displayable_path, cmd)))
|
self._log.debug("executing {}", " ".join(map(displayable_path, cmd)))
|
||||||
output = call(cmd, self._log).stderr.splitlines()
|
output = call(cmd, self._log).stderr.splitlines()
|
||||||
|
|
||||||
# parse output
|
# parse output
|
||||||
|
|
@ -654,8 +654,8 @@ class CommandBackend(Backend):
|
||||||
cmd = cmd + ["-d", str(int(target_level - 89))]
|
cmd = cmd + ["-d", str(int(target_level - 89))]
|
||||||
cmd = cmd + [syspath(i.path) for i in items]
|
cmd = cmd + [syspath(i.path) for i in items]
|
||||||
|
|
||||||
self._log.debug("analyzing {0} files", len(items))
|
self._log.debug("analyzing {} files", len(items))
|
||||||
self._log.debug("executing {0}", " ".join(map(displayable_path, cmd)))
|
self._log.debug("executing {}", " ".join(map(displayable_path, cmd)))
|
||||||
output = call(cmd, self._log).stdout
|
output = call(cmd, self._log).stdout
|
||||||
self._log.debug("analysis finished")
|
self._log.debug("analysis finished")
|
||||||
return self.parse_tool_output(
|
return self.parse_tool_output(
|
||||||
|
|
@ -671,7 +671,7 @@ class CommandBackend(Backend):
|
||||||
for line in text.split(b"\n")[1 : num_lines + 1]:
|
for line in text.split(b"\n")[1 : num_lines + 1]:
|
||||||
parts = line.split(b"\t")
|
parts = line.split(b"\t")
|
||||||
if len(parts) != 6 or parts[0] == b"File":
|
if len(parts) != 6 or parts[0] == b"File":
|
||||||
self._log.debug("bad tool output: {0}", text)
|
self._log.debug("bad tool output: {}", text)
|
||||||
raise ReplayGainError("mp3gain failed")
|
raise ReplayGainError("mp3gain failed")
|
||||||
|
|
||||||
# _file = parts[0]
|
# _file = parts[0]
|
||||||
|
|
@ -1096,7 +1096,7 @@ class AudioToolsBackend(Backend):
|
||||||
)
|
)
|
||||||
|
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"ReplayGain for track {0} - {1}: {2:.2f}, {3:.2f}",
|
"ReplayGain for track {} - {}: {2:.2f}, {3:.2f}",
|
||||||
item.artist,
|
item.artist,
|
||||||
item.title,
|
item.title,
|
||||||
rg_track_gain,
|
rg_track_gain,
|
||||||
|
|
@ -1123,7 +1123,7 @@ class AudioToolsBackend(Backend):
|
||||||
)
|
)
|
||||||
track_gains.append(Gain(gain=rg_track_gain, peak=rg_track_peak))
|
track_gains.append(Gain(gain=rg_track_gain, peak=rg_track_peak))
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"ReplayGain for track {0}: {1:.2f}, {2:.2f}",
|
"ReplayGain for track {}: {.2f}, {.2f}",
|
||||||
item,
|
item,
|
||||||
rg_track_gain,
|
rg_track_gain,
|
||||||
rg_track_peak,
|
rg_track_peak,
|
||||||
|
|
@ -1136,7 +1136,7 @@ class AudioToolsBackend(Backend):
|
||||||
rg_album_gain, task.target_level
|
rg_album_gain, task.target_level
|
||||||
)
|
)
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"ReplayGain for album {0}: {1:.2f}, {2:.2f}",
|
"ReplayGain for album {}: {.2f}, {.2f}",
|
||||||
task.items[0].album,
|
task.items[0].album,
|
||||||
rg_album_gain,
|
rg_album_gain,
|
||||||
rg_album_peak,
|
rg_album_peak,
|
||||||
|
|
@ -1336,19 +1336,19 @@ class ReplayGainPlugin(BeetsPlugin):
|
||||||
items, nothing is done.
|
items, nothing is done.
|
||||||
"""
|
"""
|
||||||
if not force and not self.album_requires_gain(album):
|
if not force and not self.album_requires_gain(album):
|
||||||
self._log.info("Skipping album {0}", album)
|
self._log.info("Skipping album {}", album)
|
||||||
return
|
return
|
||||||
|
|
||||||
items_iter = iter(album.items())
|
items_iter = iter(album.items())
|
||||||
use_r128 = self.should_use_r128(next(items_iter))
|
use_r128 = self.should_use_r128(next(items_iter))
|
||||||
if any(use_r128 != self.should_use_r128(i) for i in items_iter):
|
if any(use_r128 != self.should_use_r128(i) for i in items_iter):
|
||||||
self._log.error(
|
self._log.error(
|
||||||
"Cannot calculate gain for album {0} (incompatible formats)",
|
"Cannot calculate gain for album {} (incompatible formats)",
|
||||||
album,
|
album,
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
self._log.info("analyzing {0}", album)
|
self._log.info("analyzing {}", album)
|
||||||
|
|
||||||
discs: dict[int, list[Item]] = {}
|
discs: dict[int, list[Item]] = {}
|
||||||
if self.config["per_disc"].get(bool):
|
if self.config["per_disc"].get(bool):
|
||||||
|
|
@ -1372,7 +1372,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
||||||
callback=store_cb,
|
callback=store_cb,
|
||||||
)
|
)
|
||||||
except ReplayGainError as e:
|
except ReplayGainError as e:
|
||||||
self._log.info("ReplayGain error: {0}", e)
|
self._log.info("ReplayGain error: {}", e)
|
||||||
except FatalReplayGainError as e:
|
except FatalReplayGainError as e:
|
||||||
raise ui.UserError(f"Fatal replay gain error: {e}")
|
raise ui.UserError(f"Fatal replay gain error: {e}")
|
||||||
|
|
||||||
|
|
@ -1384,7 +1384,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
||||||
in the item, nothing is done.
|
in the item, nothing is done.
|
||||||
"""
|
"""
|
||||||
if not force and not self.track_requires_gain(item):
|
if not force and not self.track_requires_gain(item):
|
||||||
self._log.info("Skipping track {0}", item)
|
self._log.info("Skipping track {}", item)
|
||||||
return
|
return
|
||||||
|
|
||||||
use_r128 = self.should_use_r128(item)
|
use_r128 = self.should_use_r128(item)
|
||||||
|
|
@ -1401,7 +1401,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
||||||
callback=store_cb,
|
callback=store_cb,
|
||||||
)
|
)
|
||||||
except ReplayGainError as e:
|
except ReplayGainError as e:
|
||||||
self._log.info("ReplayGain error: {0}", e)
|
self._log.info("ReplayGain error: {}", e)
|
||||||
except FatalReplayGainError as e:
|
except FatalReplayGainError as e:
|
||||||
raise ui.UserError(f"Fatal replay gain error: {e}")
|
raise ui.UserError(f"Fatal replay gain error: {e}")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ class RewritePlugin(BeetsPlugin):
|
||||||
raise ui.UserError(
|
raise ui.UserError(
|
||||||
f"invalid field name ({fieldname}) in rewriter"
|
f"invalid field name ({fieldname}) in rewriter"
|
||||||
)
|
)
|
||||||
self._log.debug("adding template field {0}", key)
|
self._log.debug("adding template field {}", key)
|
||||||
pattern = re.compile(pattern.lower())
|
pattern = re.compile(pattern.lower())
|
||||||
rules[fieldname].append((pattern, value))
|
rules[fieldname].append((pattern, value))
|
||||||
if fieldname == "artist":
|
if fieldname == "artist":
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ class ScrubPlugin(BeetsPlugin):
|
||||||
# Walk through matching files and remove tags.
|
# Walk through matching files and remove tags.
|
||||||
for item in lib.items(args):
|
for item in lib.items(args):
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"scrubbing: {0}", util.displayable_path(item.path)
|
"scrubbing: {}", util.displayable_path(item.path)
|
||||||
)
|
)
|
||||||
self._scrub_item(item, opts.write)
|
self._scrub_item(item, opts.write)
|
||||||
|
|
||||||
|
|
@ -110,7 +110,7 @@ class ScrubPlugin(BeetsPlugin):
|
||||||
f.save()
|
f.save()
|
||||||
except (OSError, mutagen.MutagenError) as exc:
|
except (OSError, mutagen.MutagenError) as exc:
|
||||||
self._log.error(
|
self._log.error(
|
||||||
"could not scrub {0}: {1}", util.displayable_path(path), exc
|
"could not scrub {}: {}", util.displayable_path(path), exc
|
||||||
)
|
)
|
||||||
|
|
||||||
def _scrub_item(self, item, restore):
|
def _scrub_item(self, item, restore):
|
||||||
|
|
@ -124,7 +124,7 @@ class ScrubPlugin(BeetsPlugin):
|
||||||
util.syspath(item.path), config["id3v23"].get(bool)
|
util.syspath(item.path), config["id3v23"].get(bool)
|
||||||
)
|
)
|
||||||
except mediafile.UnreadableFileError as exc:
|
except mediafile.UnreadableFileError as exc:
|
||||||
self._log.error("could not open file to scrub: {0}", exc)
|
self._log.error("could not open file to scrub: {}", exc)
|
||||||
return
|
return
|
||||||
images = mf.images
|
images = mf.images
|
||||||
|
|
||||||
|
|
@ -144,12 +144,12 @@ class ScrubPlugin(BeetsPlugin):
|
||||||
mf.images = images
|
mf.images = images
|
||||||
mf.save()
|
mf.save()
|
||||||
except mediafile.UnreadableFileError as exc:
|
except mediafile.UnreadableFileError as exc:
|
||||||
self._log.error("could not write tags: {0}", exc)
|
self._log.error("could not write tags: {}", exc)
|
||||||
|
|
||||||
def import_task_files(self, session, task):
|
def import_task_files(self, session, task):
|
||||||
"""Automatically scrub imported files."""
|
"""Automatically scrub imported files."""
|
||||||
for item in task.imported_items():
|
for item in task.imported_items():
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"auto-scrubbing {0}", util.displayable_path(item.path)
|
"auto-scrubbing {}", util.displayable_path(item.path)
|
||||||
)
|
)
|
||||||
self._scrub_item(item, ui.should_write())
|
self._scrub_item(item, ui.should_write())
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
||||||
for playlist in self._unmatched_playlists:
|
for playlist in self._unmatched_playlists:
|
||||||
n, (q, _), (a_q, _) = playlist
|
n, (q, _), (a_q, _) = playlist
|
||||||
if self.matches(model, q, a_q):
|
if self.matches(model, q, a_q):
|
||||||
self._log.debug("{0} will be updated because of {1}", n, model)
|
self._log.debug("{} will be updated because of {}", n, model)
|
||||||
self._matched_playlists.add(playlist)
|
self._matched_playlists.add(playlist)
|
||||||
self.register_listener("cli_exit", self.update_playlists)
|
self.register_listener("cli_exit", self.update_playlists)
|
||||||
|
|
||||||
|
|
@ -243,12 +243,12 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
||||||
def update_playlists(self, lib, pretend=False):
|
def update_playlists(self, lib, pretend=False):
|
||||||
if pretend:
|
if pretend:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Showing query results for {0} smart playlists...",
|
"Showing query results for {} smart playlists...",
|
||||||
len(self._matched_playlists),
|
len(self._matched_playlists),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Updating {0} smart playlists...", len(self._matched_playlists)
|
"Updating {} smart playlists...", len(self._matched_playlists)
|
||||||
)
|
)
|
||||||
|
|
||||||
playlist_dir = self.config["playlist_dir"].as_filename()
|
playlist_dir = self.config["playlist_dir"].as_filename()
|
||||||
|
|
@ -267,7 +267,7 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
||||||
if pretend:
|
if pretend:
|
||||||
self._log.info("Results for playlist {}:", name)
|
self._log.info("Results for playlist {}:", name)
|
||||||
else:
|
else:
|
||||||
self._log.info("Creating playlist {0}", name)
|
self._log.info("Creating playlist {}", name)
|
||||||
items = []
|
items = []
|
||||||
|
|
||||||
if query:
|
if query:
|
||||||
|
|
@ -340,13 +340,11 @@ class SmartPlaylistPlugin(BeetsPlugin):
|
||||||
|
|
||||||
if pretend:
|
if pretend:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Displayed results for {0} playlists",
|
"Displayed results for {} playlists",
|
||||||
len(self._matched_playlists),
|
len(self._matched_playlists),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._log.info(
|
self._log.info("{} playlists updated", len(self._matched_playlists))
|
||||||
"{0} playlists updated", len(self._matched_playlists)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class PlaylistItem:
|
class PlaylistItem:
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,7 @@ class SpotifyPlugin(
|
||||||
|
|
||||||
if self.config["mode"].get() not in ["list", "open"]:
|
if self.config["mode"].get() not in ["list", "open"]:
|
||||||
self._log.warning(
|
self._log.warning(
|
||||||
"{0} is not a valid mode", self.config["mode"].get()
|
"{} is not a valid mode", self.config["mode"].get()
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,8 +107,8 @@ class SubsonicUpdate(BeetsPlugin):
|
||||||
user = self.config["user"].as_str()
|
user = self.config["user"].as_str()
|
||||||
auth = self.config["auth"].as_str()
|
auth = self.config["auth"].as_str()
|
||||||
url = self.__format_url("startScan")
|
url = self.__format_url("startScan")
|
||||||
self._log.debug("URL is {0}", url)
|
self._log.debug("URL is {}", url)
|
||||||
self._log.debug("auth type is {0}", self.config["auth"])
|
self._log.debug("auth type is {}", self.config["auth"])
|
||||||
|
|
||||||
if auth == "token":
|
if auth == "token":
|
||||||
salt, token = self.__create_token()
|
salt, token = self.__create_token()
|
||||||
|
|
@ -153,6 +153,6 @@ class SubsonicUpdate(BeetsPlugin):
|
||||||
error_message = json["subsonic-response"]["error"]["message"]
|
error_message = json["subsonic-response"]["error"]["message"]
|
||||||
self._log.error(f"Error: {error_message}")
|
self._log.error(f"Error: {error_message}")
|
||||||
else:
|
else:
|
||||||
self._log.error("Error: {0}", json)
|
self._log.error("Error: {}", json)
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
self._log.error(f"Error: {error}")
|
self._log.error(f"Error: {error}")
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ __version__ = "1.1"
|
||||||
|
|
||||||
PATTERN_THE = "^the\\s"
|
PATTERN_THE = "^the\\s"
|
||||||
PATTERN_A = "^[a][n]?\\s"
|
PATTERN_A = "^[a][n]?\\s"
|
||||||
FORMAT = "{0}, {1}"
|
FORMAT = "{}, {}"
|
||||||
|
|
||||||
|
|
||||||
class ThePlugin(BeetsPlugin):
|
class ThePlugin(BeetsPlugin):
|
||||||
|
|
@ -38,7 +38,7 @@ class ThePlugin(BeetsPlugin):
|
||||||
{
|
{
|
||||||
"the": True,
|
"the": True,
|
||||||
"a": True,
|
"a": True,
|
||||||
"format": "{0}, {1}",
|
"format": "{}, {}",
|
||||||
"strip": False,
|
"strip": False,
|
||||||
"patterns": [],
|
"patterns": [],
|
||||||
}
|
}
|
||||||
|
|
@ -50,11 +50,11 @@ class ThePlugin(BeetsPlugin):
|
||||||
try:
|
try:
|
||||||
re.compile(p)
|
re.compile(p)
|
||||||
except re.error:
|
except re.error:
|
||||||
self._log.error("invalid pattern: {0}", p)
|
self._log.error("invalid pattern: {}", p)
|
||||||
else:
|
else:
|
||||||
if not (p.startswith("^") or p.endswith("$")):
|
if not (p.startswith("^") or p.endswith("$")):
|
||||||
self._log.warning(
|
self._log.warning(
|
||||||
'warning: "{0}" will not match string start/end',
|
'warning: "{}" will not match string start/end',
|
||||||
p,
|
p,
|
||||||
)
|
)
|
||||||
if self.config["a"]:
|
if self.config["a"]:
|
||||||
|
|
@ -94,7 +94,7 @@ class ThePlugin(BeetsPlugin):
|
||||||
for p in self.patterns:
|
for p in self.patterns:
|
||||||
r = self.unthe(text, p)
|
r = self.unthe(text, p)
|
||||||
if r != text:
|
if r != text:
|
||||||
self._log.debug('"{0}" -> "{1}"', text, r)
|
self._log.debug('"{}" -> "{}"', text, r)
|
||||||
break
|
break
|
||||||
return r
|
return r
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -109,16 +109,16 @@ class ThumbnailsPlugin(BeetsPlugin):
|
||||||
uri_getter = GioURI()
|
uri_getter = GioURI()
|
||||||
if not uri_getter.available:
|
if not uri_getter.available:
|
||||||
uri_getter = PathlibURI()
|
uri_getter = PathlibURI()
|
||||||
self._log.debug("using {0.name} to compute URIs", uri_getter)
|
self._log.debug("using {.name} to compute URIs", uri_getter)
|
||||||
self.get_uri = uri_getter.uri
|
self.get_uri = uri_getter.uri
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def process_album(self, album):
|
def process_album(self, album):
|
||||||
"""Produce thumbnails for the album folder."""
|
"""Produce thumbnails for the album folder."""
|
||||||
self._log.debug("generating thumbnail for {0}", album)
|
self._log.debug("generating thumbnail for {}", album)
|
||||||
if not album.artpath:
|
if not album.artpath:
|
||||||
self._log.info("album {0} has no art", album)
|
self._log.info("album {} has no art", album)
|
||||||
return
|
return
|
||||||
|
|
||||||
if self.config["dolphin"]:
|
if self.config["dolphin"]:
|
||||||
|
|
@ -127,7 +127,7 @@ class ThumbnailsPlugin(BeetsPlugin):
|
||||||
size = ArtResizer.shared.get_size(album.artpath)
|
size = ArtResizer.shared.get_size(album.artpath)
|
||||||
if not size:
|
if not size:
|
||||||
self._log.warning(
|
self._log.warning(
|
||||||
"problem getting the picture size for {0}", album.artpath
|
"problem getting the picture size for {}", album.artpath
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
@ -137,9 +137,9 @@ class ThumbnailsPlugin(BeetsPlugin):
|
||||||
wrote &= self.make_cover_thumbnail(album, 128, NORMAL_DIR)
|
wrote &= self.make_cover_thumbnail(album, 128, NORMAL_DIR)
|
||||||
|
|
||||||
if wrote:
|
if wrote:
|
||||||
self._log.info("wrote thumbnail for {0}", album)
|
self._log.info("wrote thumbnail for {}", album)
|
||||||
else:
|
else:
|
||||||
self._log.info("nothing to do for {0}", album)
|
self._log.info("nothing to do for {}", album)
|
||||||
|
|
||||||
def make_cover_thumbnail(self, album, size, target_dir):
|
def make_cover_thumbnail(self, album, size, target_dir):
|
||||||
"""Make a thumbnail of given size for `album` and put it in
|
"""Make a thumbnail of given size for `album` and put it in
|
||||||
|
|
@ -154,16 +154,16 @@ class ThumbnailsPlugin(BeetsPlugin):
|
||||||
):
|
):
|
||||||
if self.config["force"]:
|
if self.config["force"]:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"found a suitable {1}x{1} thumbnail for {0}, "
|
"found a suitable {0}x{0} thumbnail for {1}, "
|
||||||
"forcing regeneration",
|
"forcing regeneration",
|
||||||
album,
|
|
||||||
size,
|
size,
|
||||||
|
album,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._log.debug(
|
self._log.debug(
|
||||||
"{1}x{1} thumbnail for {0} exists and is recent enough",
|
"{0}x{0} thumbnail for {1} exists and is recent enough",
|
||||||
album,
|
|
||||||
size,
|
size,
|
||||||
|
album,
|
||||||
)
|
)
|
||||||
return False
|
return False
|
||||||
resized = ArtResizer.shared.resize(size, album.artpath, target)
|
resized = ArtResizer.shared.resize(size, album.artpath, target)
|
||||||
|
|
@ -192,7 +192,7 @@ class ThumbnailsPlugin(BeetsPlugin):
|
||||||
ArtResizer.shared.write_metadata(image_path, metadata)
|
ArtResizer.shared.write_metadata(image_path, metadata)
|
||||||
except Exception:
|
except Exception:
|
||||||
self._log.exception(
|
self._log.exception(
|
||||||
"could not write metadata to {0}", displayable_path(image_path)
|
"could not write metadata to {}", displayable_path(image_path)
|
||||||
)
|
)
|
||||||
|
|
||||||
def make_dolphin_cover_thumbnail(self, album):
|
def make_dolphin_cover_thumbnail(self, album):
|
||||||
|
|
@ -204,7 +204,7 @@ class ThumbnailsPlugin(BeetsPlugin):
|
||||||
f.write("[Desktop Entry]\n")
|
f.write("[Desktop Entry]\n")
|
||||||
f.write(f"Icon=./{artfile.decode('utf-8')}")
|
f.write(f"Icon=./{artfile.decode('utf-8')}")
|
||||||
f.close()
|
f.close()
|
||||||
self._log.debug("Wrote file {0}", displayable_path(outfilename))
|
self._log.debug("Wrote file {}", displayable_path(outfilename))
|
||||||
|
|
||||||
|
|
||||||
class URIGetter:
|
class URIGetter:
|
||||||
|
|
|
||||||
|
|
@ -474,7 +474,7 @@ class WebPlugin(BeetsPlugin):
|
||||||
# Enable CORS if required.
|
# Enable CORS if required.
|
||||||
if self.config["cors"]:
|
if self.config["cors"]:
|
||||||
self._log.info(
|
self._log.info(
|
||||||
"Enabling CORS with origin: {0}", self.config["cors"]
|
"Enabling CORS with origin: {}", self.config["cors"]
|
||||||
)
|
)
|
||||||
from flask_cors import CORS
|
from flask_cors import CORS
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,10 +90,10 @@ class ZeroPlugin(BeetsPlugin):
|
||||||
Do some sanity checks then compile the regexes.
|
Do some sanity checks then compile the regexes.
|
||||||
"""
|
"""
|
||||||
if field not in MediaFile.fields():
|
if field not in MediaFile.fields():
|
||||||
self._log.error("invalid field: {0}", field)
|
self._log.error("invalid field: {}", field)
|
||||||
elif field in ("id", "path", "album_id"):
|
elif field in ("id", "path", "album_id"):
|
||||||
self._log.warning(
|
self._log.warning(
|
||||||
"field '{0}' ignored, zeroing it would be dangerous", field
|
"field '{}' ignored, zeroing it would be dangerous", field
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
|
|
@ -137,7 +137,7 @@ class ZeroPlugin(BeetsPlugin):
|
||||||
|
|
||||||
if match:
|
if match:
|
||||||
fields_set = True
|
fields_set = True
|
||||||
self._log.debug("{0}: {1} -> None", field, value)
|
self._log.debug("{}: {} -> None", field, value)
|
||||||
tags[field] = None
|
tags[field] = None
|
||||||
if self.config["update_database"]:
|
if self.config["update_database"]:
|
||||||
item[field] = None
|
item[field] = None
|
||||||
|
|
|
||||||
|
|
@ -56,21 +56,21 @@ class FtInTitlePluginFunctional(PluginTestCase):
|
||||||
assert item["title"] == "Song 1"
|
assert item["title"] == "Song 1"
|
||||||
|
|
||||||
def test_functional_custom_format(self):
|
def test_functional_custom_format(self):
|
||||||
self._ft_set_config("feat. {0}")
|
self._ft_set_config("feat. {}")
|
||||||
item = self._ft_add_item("/", "Alice ft Bob", "Song 1", "Alice")
|
item = self._ft_add_item("/", "Alice ft Bob", "Song 1", "Alice")
|
||||||
self.run_command("ftintitle")
|
self.run_command("ftintitle")
|
||||||
item.load()
|
item.load()
|
||||||
assert item["artist"] == "Alice"
|
assert item["artist"] == "Alice"
|
||||||
assert item["title"] == "Song 1 feat. Bob"
|
assert item["title"] == "Song 1 feat. Bob"
|
||||||
|
|
||||||
self._ft_set_config("featuring {0}")
|
self._ft_set_config("featuring {}")
|
||||||
item = self._ft_add_item("/", "Alice feat. Bob", "Song 1", "Alice")
|
item = self._ft_add_item("/", "Alice feat. Bob", "Song 1", "Alice")
|
||||||
self.run_command("ftintitle")
|
self.run_command("ftintitle")
|
||||||
item.load()
|
item.load()
|
||||||
assert item["artist"] == "Alice"
|
assert item["artist"] == "Alice"
|
||||||
assert item["title"] == "Song 1 featuring Bob"
|
assert item["title"] == "Song 1 featuring Bob"
|
||||||
|
|
||||||
self._ft_set_config("with {0}")
|
self._ft_set_config("with {}")
|
||||||
item = self._ft_add_item("/", "Alice feat Bob", "Song 1", "Alice")
|
item = self._ft_add_item("/", "Alice feat Bob", "Song 1", "Alice")
|
||||||
self.run_command("ftintitle")
|
self.run_command("ftintitle")
|
||||||
item.load()
|
item.load()
|
||||||
|
|
@ -78,7 +78,7 @@ class FtInTitlePluginFunctional(PluginTestCase):
|
||||||
assert item["title"] == "Song 1 with Bob"
|
assert item["title"] == "Song 1 with Bob"
|
||||||
|
|
||||||
def test_functional_keep_in_artist(self):
|
def test_functional_keep_in_artist(self):
|
||||||
self._ft_set_config("feat. {0}", keep_in_artist=True)
|
self._ft_set_config("feat. {}", keep_in_artist=True)
|
||||||
item = self._ft_add_item("/", "Alice ft Bob", "Song 1", "Alice")
|
item = self._ft_add_item("/", "Alice ft Bob", "Song 1", "Alice")
|
||||||
self.run_command("ftintitle")
|
self.run_command("ftintitle")
|
||||||
item.load()
|
item.load()
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,7 @@ class MPDStatsTest(PluginTestCase):
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
log.debug.assert_has_calls([call('unhandled status "{0}"', ANY)])
|
log.debug.assert_has_calls([call('unhandled status "{}"', ANY)])
|
||||||
log.info.assert_has_calls(
|
log.info.assert_has_calls(
|
||||||
[call("pause"), call("playing {0}", ANY), call("stop")]
|
[call("pause"), call("playing {}", ANY), call("stop")]
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ class LoggingTest(unittest.TestCase):
|
||||||
logger.addHandler(handler)
|
logger.addHandler(handler)
|
||||||
logger.propagate = False
|
logger.propagate = False
|
||||||
|
|
||||||
logger.warning("foo {0} {bar}", "oof", bar="baz")
|
logger.warning("foo {} {bar}", "oof", bar="baz")
|
||||||
handler.flush()
|
handler.flush()
|
||||||
assert stream.getvalue(), "foo oof baz"
|
assert stream.getvalue(), "foo oof baz"
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue