mirror of
https://github.com/beetbox/beets.git
synced 2025-12-26 18:43:38 +01:00
Merge pull request #1198 from brunal/logging
Lazy {}-style logging everywhere
This commit is contained in:
commit
f6dc2cd81c
48 changed files with 542 additions and 563 deletions
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
"""Facilities for automatically determining files' correct metadata.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from beets import logging
|
||||
from beets import config
|
||||
|
||||
# Parts of external interface.
|
||||
|
|
|
|||
|
|
@ -13,10 +13,10 @@
|
|||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
"""Glue between metadata sources and the matching logic."""
|
||||
import logging
|
||||
from collections import namedtuple
|
||||
import re
|
||||
|
||||
from beets import logging
|
||||
from beets import plugins
|
||||
from beets import config
|
||||
from beets.autotag import mb
|
||||
|
|
|
|||
|
|
@ -18,10 +18,10 @@ releases and tracks.
|
|||
from __future__ import division
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import re
|
||||
from munkres import Munkres
|
||||
|
||||
from beets import logging
|
||||
from beets import plugins
|
||||
from beets import config
|
||||
from beets.util import plurality
|
||||
|
|
@ -267,7 +267,7 @@ def match_by_id(items):
|
|||
# If all album IDs are equal, look up the album.
|
||||
if bool(reduce(lambda x, y: x if x == y else (), albumids)):
|
||||
albumid = albumids[0]
|
||||
log.debug(u'Searching for discovered album ID: {0}'.format(albumid))
|
||||
log.debug(u'Searching for discovered album ID: {0}', albumid)
|
||||
return hooks.album_for_mbid(albumid)
|
||||
else:
|
||||
log.debug(u'No album ID consensus.')
|
||||
|
|
@ -330,7 +330,7 @@ def _add_candidate(items, results, info):
|
|||
checking the track count, ordering the items, checking for
|
||||
duplicates, and calculating the distance.
|
||||
"""
|
||||
log.debug(u'Candidate: {0} - {1}'.format(info.artist, info.album))
|
||||
log.debug(u'Candidate: {0} - {1}', info.artist, info.album)
|
||||
|
||||
# Discard albums with zero tracks.
|
||||
if not info.tracks:
|
||||
|
|
@ -345,7 +345,7 @@ def _add_candidate(items, results, info):
|
|||
# Discard matches without required tags.
|
||||
for req_tag in config['match']['required'].as_str_seq():
|
||||
if getattr(info, req_tag) is None:
|
||||
log.debug(u'Ignored. Missing required tag: {0}'.format(req_tag))
|
||||
log.debug(u'Ignored. Missing required tag: {0}', req_tag)
|
||||
return
|
||||
|
||||
# Find mapping between the items and the track info.
|
||||
|
|
@ -358,10 +358,10 @@ def _add_candidate(items, results, info):
|
|||
penalties = [key for _, key in dist]
|
||||
for penalty in config['match']['ignored'].as_str_seq():
|
||||
if penalty in penalties:
|
||||
log.debug(u'Ignored. Penalty: {0}'.format(penalty))
|
||||
log.debug(u'Ignored. Penalty: {0}', penalty)
|
||||
return
|
||||
|
||||
log.debug(u'Success. Distance: {0}'.format(dist))
|
||||
log.debug(u'Success. Distance: {0}', dist)
|
||||
results[info.album_id] = hooks.AlbumMatch(dist, info, mapping,
|
||||
extra_items, extra_tracks)
|
||||
|
||||
|
|
@ -387,7 +387,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
likelies, consensus = current_metadata(items)
|
||||
cur_artist = likelies['artist']
|
||||
cur_album = likelies['album']
|
||||
log.debug(u'Tagging {0} - {1}'.format(cur_artist, cur_album))
|
||||
log.debug(u'Tagging {0} - {1}', cur_artist, cur_album)
|
||||
|
||||
# The output result (distance, AlbumInfo) tuples (keyed by MB album
|
||||
# ID).
|
||||
|
|
@ -395,7 +395,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
|
||||
# Search by explicit ID.
|
||||
if search_id is not None:
|
||||
log.debug(u'Searching for album ID: {0}'.format(search_id))
|
||||
log.debug(u'Searching for album ID: {0}', search_id)
|
||||
search_cands = hooks.albums_for_id(search_id)
|
||||
|
||||
# Use existing metadata or text search.
|
||||
|
|
@ -405,7 +405,7 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
if id_info:
|
||||
_add_candidate(items, candidates, id_info)
|
||||
rec = _recommendation(candidates.values())
|
||||
log.debug(u'Album ID match recommendation is {0}'.format(str(rec)))
|
||||
log.debug(u'Album ID match recommendation is {0}', str(rec))
|
||||
if candidates and not config['import']['timid']:
|
||||
# If we have a very good MBID match, return immediately.
|
||||
# Otherwise, this match will compete against metadata-based
|
||||
|
|
@ -418,20 +418,19 @@ def tag_album(items, search_artist=None, search_album=None,
|
|||
if not (search_artist and search_album):
|
||||
# No explicit search terms -- use current metadata.
|
||||
search_artist, search_album = cur_artist, cur_album
|
||||
log.debug(u'Search terms: {0} - {1}'.format(search_artist,
|
||||
search_album))
|
||||
log.debug(u'Search terms: {0} - {1}', search_artist, search_album)
|
||||
|
||||
# Is this album likely to be a "various artist" release?
|
||||
va_likely = ((not consensus['artist']) or
|
||||
(search_artist.lower() in VA_ARTISTS) or
|
||||
any(item.comp for item in items))
|
||||
log.debug(u'Album might be VA: {0}'.format(str(va_likely)))
|
||||
log.debug(u'Album might be VA: {0}', str(va_likely))
|
||||
|
||||
# Get the results from the data sources.
|
||||
search_cands = hooks.album_candidates(items, search_artist,
|
||||
search_album, va_likely)
|
||||
|
||||
log.debug(u'Evaluating {0} candidates.'.format(len(search_cands)))
|
||||
log.debug(u'Evaluating {0} candidates.', len(search_cands))
|
||||
for info in search_cands:
|
||||
_add_candidate(items, candidates, info)
|
||||
|
||||
|
|
@ -456,7 +455,7 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
# First, try matching by MusicBrainz ID.
|
||||
trackid = search_id or item.mb_trackid
|
||||
if trackid:
|
||||
log.debug(u'Searching for track ID: {0}'.format(trackid))
|
||||
log.debug(u'Searching for track ID: {0}', trackid)
|
||||
for track_info in hooks.tracks_for_id(trackid):
|
||||
dist = track_distance(item, track_info, incl_artist=True)
|
||||
candidates[track_info.track_id] = \
|
||||
|
|
@ -477,8 +476,7 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
# Search terms.
|
||||
if not (search_artist and search_title):
|
||||
search_artist, search_title = item.artist, item.title
|
||||
log.debug(u'Item search terms: {0} - {1}'.format(search_artist,
|
||||
search_title))
|
||||
log.debug(u'Item search terms: {0} - {1}', search_artist, search_title)
|
||||
|
||||
# Get and evaluate candidate metadata.
|
||||
for track_info in hooks.item_candidates(item, search_artist, search_title):
|
||||
|
|
@ -486,7 +484,7 @@ def tag_item(item, search_artist=None, search_title=None,
|
|||
candidates[track_info.track_id] = hooks.TrackMatch(dist, track_info)
|
||||
|
||||
# Sort by distance and return with recommendation.
|
||||
log.debug(u'Found {0} candidates.'.format(len(candidates)))
|
||||
log.debug(u'Found {0} candidates.', len(candidates))
|
||||
candidates = sorted(candidates.itervalues())
|
||||
rec = _recommendation(candidates)
|
||||
return candidates, rec
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@
|
|||
|
||||
"""Searches for albums in the MusicBrainz database.
|
||||
"""
|
||||
import logging
|
||||
import musicbrainzngs
|
||||
import re
|
||||
import traceback
|
||||
from urlparse import urljoin
|
||||
|
||||
from beets import logging
|
||||
import beets.autotag.hooks
|
||||
import beets
|
||||
from beets import util
|
||||
|
|
@ -374,7 +374,7 @@ def album_for_id(releaseid):
|
|||
"""
|
||||
albumid = _parse_id(releaseid)
|
||||
if not albumid:
|
||||
log.debug(u'Invalid MBID ({0}).'.format(releaseid))
|
||||
log.debug(u'Invalid MBID ({0}).', releaseid)
|
||||
return
|
||||
try:
|
||||
res = musicbrainzngs.get_release_by_id(albumid,
|
||||
|
|
@ -394,7 +394,7 @@ def track_for_id(releaseid):
|
|||
"""
|
||||
trackid = _parse_id(releaseid)
|
||||
if not trackid:
|
||||
log.debug(u'Invalid MBID ({0}).'.format(releaseid))
|
||||
log.debug(u'Invalid MBID ({0}).', releaseid)
|
||||
return
|
||||
try:
|
||||
res = musicbrainzngs.get_recording_by_id(trackid, TRACK_INCLUDES)
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ from __future__ import print_function
|
|||
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
import pickle
|
||||
import itertools
|
||||
from collections import defaultdict
|
||||
|
|
@ -28,6 +27,7 @@ from bisect import insort, bisect_left
|
|||
from contextlib import contextmanager
|
||||
import shutil
|
||||
|
||||
from beets import logging
|
||||
from beets import autotag
|
||||
from beets import library
|
||||
from beets import dbcore
|
||||
|
|
@ -71,7 +71,7 @@ def _open_state():
|
|||
# unpickling, including ImportError. We use a catch-all
|
||||
# exception to avoid enumerating them all (the docs don't even have a
|
||||
# full list!).
|
||||
log.debug(u'state file could not be read: {0}'.format(exc))
|
||||
log.debug(u'state file could not be read: {0}', exc)
|
||||
return {}
|
||||
|
||||
|
||||
|
|
@ -81,7 +81,7 @@ def _save_state(state):
|
|||
with open(config['statefile'].as_filename(), 'w') as f:
|
||||
pickle.dump(state, f)
|
||||
except IOError as exc:
|
||||
log.error(u'state file could not be written: {0}'.format(exc))
|
||||
log.error(u'state file could not be written: {0}', exc)
|
||||
|
||||
|
||||
# Utilities for reading and writing the beets progress file, which
|
||||
|
|
@ -347,8 +347,8 @@ class ImportSession(object):
|
|||
# Either accept immediately or prompt for input to decide.
|
||||
if self.want_resume is True or \
|
||||
self.should_resume(toppath):
|
||||
log.warn(u'Resuming interrupted import of {0}'.format(
|
||||
util.displayable_path(toppath)))
|
||||
log.warn(u'Resuming interrupted import of {0}',
|
||||
util.displayable_path(toppath))
|
||||
self._is_resuming[toppath] = True
|
||||
else:
|
||||
# Clear progress; we're starting from the top.
|
||||
|
|
@ -481,13 +481,12 @@ class ImportTask(object):
|
|||
|
||||
def remove_duplicates(self, lib):
|
||||
duplicate_items = self.duplicate_items(lib)
|
||||
log.debug(u'removing {0} old duplicated items'
|
||||
.format(len(duplicate_items)))
|
||||
log.debug(u'removing {0} old duplicated items', len(duplicate_items))
|
||||
for item in duplicate_items:
|
||||
item.remove()
|
||||
if lib.directory in util.ancestry(item.path):
|
||||
log.debug(u'deleting duplicate {0}'
|
||||
.format(util.displayable_path(item.path)))
|
||||
log.debug(u'deleting duplicate {0}',
|
||||
util.displayable_path(item.path))
|
||||
util.remove(item.path)
|
||||
util.prune_dirs(os.path.dirname(item.path),
|
||||
lib.directory)
|
||||
|
|
@ -686,12 +685,11 @@ class ImportTask(object):
|
|||
self.album.store()
|
||||
log.debug(
|
||||
u'Reimported album: added {0}, flexible '
|
||||
u'attributes {1} from album {2} for {3}'.format(
|
||||
self.album.added,
|
||||
replaced_album._values_flex.keys(),
|
||||
replaced_album.id,
|
||||
displayable_path(self.album.path),
|
||||
)
|
||||
u'attributes {1} from album {2} for {3}',
|
||||
self.album.added,
|
||||
replaced_album._values_flex.keys(),
|
||||
replaced_album.id,
|
||||
displayable_path(self.album.path)
|
||||
)
|
||||
|
||||
for item in self.imported_items():
|
||||
|
|
@ -701,20 +699,18 @@ class ImportTask(object):
|
|||
item.added = dup_item.added
|
||||
log.debug(
|
||||
u'Reimported item added {0} '
|
||||
u'from item {1} for {2}'.format(
|
||||
item.added,
|
||||
dup_item.id,
|
||||
displayable_path(item.path),
|
||||
)
|
||||
u'from item {1} for {2}',
|
||||
item.added,
|
||||
dup_item.id,
|
||||
displayable_path(item.path)
|
||||
)
|
||||
item.update(dup_item._values_flex)
|
||||
log.debug(
|
||||
u'Reimported item flexible attributes {0} '
|
||||
u'from item {1} for {2}'.format(
|
||||
dup_item._values_flex.keys(),
|
||||
dup_item.id,
|
||||
displayable_path(item.path),
|
||||
)
|
||||
u'from item {1} for {2}',
|
||||
dup_item._values_flex.keys(),
|
||||
dup_item.id,
|
||||
displayable_path(item.path)
|
||||
)
|
||||
item.store()
|
||||
|
||||
|
|
@ -724,13 +720,12 @@ class ImportTask(object):
|
|||
"""
|
||||
for item in self.imported_items():
|
||||
for dup_item in self.replaced_items[item]:
|
||||
log.debug(u'Replacing item {0}: {1}'
|
||||
.format(dup_item.id,
|
||||
displayable_path(item.path)))
|
||||
log.debug(u'Replacing item {0}: {1}',
|
||||
dup_item.id, displayable_path(item.path))
|
||||
dup_item.remove()
|
||||
log.debug(u'{0} of {1} items replaced'
|
||||
.format(sum(bool(l) for l in self.replaced_items.values()),
|
||||
len(self.imported_items())))
|
||||
log.debug(u'{0} of {1} items replaced',
|
||||
sum(bool(l) for l in self.replaced_items.values()),
|
||||
len(self.imported_items()))
|
||||
|
||||
def choose_match(self, session):
|
||||
"""Ask the session which match should apply and apply it.
|
||||
|
|
@ -1002,8 +997,8 @@ class ImportTaskFactory(object):
|
|||
|
||||
def singleton(self, path):
|
||||
if self.session.already_imported(self.toppath, [path]):
|
||||
log.debug(u'Skipping previously-imported path: {0}'
|
||||
.format(displayable_path(path)))
|
||||
log.debug(u'Skipping previously-imported path: {0}',
|
||||
displayable_path(path))
|
||||
self.skipped += 1
|
||||
return None
|
||||
|
||||
|
|
@ -1026,8 +1021,8 @@ class ImportTaskFactory(object):
|
|||
dirs = list(set(os.path.dirname(p) for p in paths))
|
||||
|
||||
if self.session.already_imported(self.toppath, dirs):
|
||||
log.debug(u'Skipping previously-imported path: {0}'
|
||||
.format(displayable_path(dirs)))
|
||||
log.debug(u'Skipping previously-imported path: {0}',
|
||||
displayable_path(dirs))
|
||||
self.skipped += 1
|
||||
return None
|
||||
|
||||
|
|
@ -1055,14 +1050,10 @@ class ImportTaskFactory(object):
|
|||
# Silently ignore non-music files.
|
||||
pass
|
||||
elif isinstance(exc.reason, mediafile.UnreadableFileError):
|
||||
log.warn(u'unreadable file: {0}'.format(
|
||||
displayable_path(path))
|
||||
)
|
||||
log.warn(u'unreadable file: {0}', displayable_path(path))
|
||||
else:
|
||||
log.error(u'error reading {0}: {1}'.format(
|
||||
displayable_path(path),
|
||||
exc,
|
||||
))
|
||||
log.error(u'error reading {0}: {1}',
|
||||
displayable_path(path), exc)
|
||||
|
||||
|
||||
# Full-album pipeline stages.
|
||||
|
|
@ -1086,13 +1077,13 @@ def read_tasks(session):
|
|||
"'copy' or 'move' to be enabled.")
|
||||
continue
|
||||
|
||||
log.debug(u'extracting archive {0}'
|
||||
.format(displayable_path(toppath)))
|
||||
log.debug(u'extracting archive {0}',
|
||||
displayable_path(toppath))
|
||||
archive_task = ArchiveImportTask(toppath)
|
||||
try:
|
||||
archive_task.extract()
|
||||
except Exception as exc:
|
||||
log.error(u'extraction failed: {0}'.format(exc))
|
||||
log.error(u'extraction failed: {0}', exc)
|
||||
continue
|
||||
|
||||
# Continue reading albums from the extracted directory.
|
||||
|
|
@ -1112,12 +1103,12 @@ def read_tasks(session):
|
|||
yield archive_task
|
||||
|
||||
if not imported:
|
||||
log.warn(u'No files imported from {0}'
|
||||
.format(displayable_path(user_toppath)))
|
||||
log.warn(u'No files imported from {0}',
|
||||
displayable_path(user_toppath))
|
||||
|
||||
# Show skipped directories.
|
||||
if skipped:
|
||||
log.info(u'Skipped {0} directories.'.format(skipped))
|
||||
log.info(u'Skipped {0} directories.', skipped)
|
||||
|
||||
|
||||
def query_tasks(session):
|
||||
|
|
@ -1133,8 +1124,8 @@ def query_tasks(session):
|
|||
else:
|
||||
# Search for albums.
|
||||
for album in session.lib.albums(session.query):
|
||||
log.debug(u'yielding album {0}: {1} - {2}'
|
||||
.format(album.id, album.albumartist, album.album))
|
||||
log.debug(u'yielding album {0}: {1} - {2}',
|
||||
album.id, album.albumartist, album.album)
|
||||
items = list(album.items())
|
||||
|
||||
# Clear IDs from re-tagged items so they appear "fresh" when
|
||||
|
|
@ -1159,7 +1150,7 @@ def lookup_candidates(session, task):
|
|||
return
|
||||
|
||||
plugins.send('import_task_start', session=session, task=task)
|
||||
log.debug(u'Looking up: {0}'.format(displayable_path(task.paths)))
|
||||
log.debug(u'Looking up: {0}', displayable_path(task.paths))
|
||||
task.lookup_candidates()
|
||||
|
||||
|
||||
|
|
@ -1300,12 +1291,11 @@ def log_files(session, task):
|
|||
"""A coroutine (pipeline stage) to log each file which will be imported
|
||||
"""
|
||||
if isinstance(task, SingletonImportTask):
|
||||
log.info(
|
||||
'Singleton: {0}'.format(displayable_path(task.item['path'])))
|
||||
log.info('Singleton: {0}', displayable_path(task.item['path']))
|
||||
elif task.items:
|
||||
log.info('Album {0}'.format(displayable_path(task.paths[0])))
|
||||
log.info('Album {0}', displayable_path(task.paths[0]))
|
||||
for item in task.items:
|
||||
log.info(' {0}'.format(displayable_path(item['path'])))
|
||||
log.info(' {0}', displayable_path(item['path']))
|
||||
|
||||
|
||||
def group_albums(session):
|
||||
|
|
|
|||
|
|
@ -16,12 +16,13 @@
|
|||
"""
|
||||
import os
|
||||
import sys
|
||||
import logging
|
||||
import shlex
|
||||
import unicodedata
|
||||
import time
|
||||
import re
|
||||
from unidecode import unidecode
|
||||
|
||||
from beets import logging
|
||||
from beets.mediafile import MediaFile, MutagenError, UnreadableFileError
|
||||
from beets import plugins
|
||||
from beets import util
|
||||
|
|
@ -509,7 +510,7 @@ class Item(LibModel):
|
|||
self.write(path)
|
||||
return True
|
||||
except FileOperationError as exc:
|
||||
log.error(exc)
|
||||
log.error(str(exc))
|
||||
return False
|
||||
|
||||
def try_sync(self, write=None):
|
||||
|
|
@ -837,9 +838,9 @@ class Album(LibModel):
|
|||
return
|
||||
|
||||
new_art = util.unique_path(new_art)
|
||||
log.debug(u'moving album art {0} to {1}'
|
||||
.format(util.displayable_path(old_art),
|
||||
util.displayable_path(new_art)))
|
||||
log.debug(u'moving album art {0} to {1}',
|
||||
util.displayable_path(old_art),
|
||||
util.displayable_path(new_art))
|
||||
if copy:
|
||||
util.copy(old_art, new_art)
|
||||
elif link:
|
||||
|
|
|
|||
72
beets/logging.py
Normal file
72
beets/logging.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
"""Allow {}-style logging on python 2 and 3
|
||||
|
||||
Provide everything the "logging" module does, the only difference is that when
|
||||
getLogger(name) instantiates a logger that logger uses {}-style formatting.
|
||||
|
||||
It requires special hacks for python 2.6 due to logging.Logger being an old-
|
||||
style class and having no loggerClass attribute.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from copy import copy
|
||||
from logging import * # noqa
|
||||
import sys
|
||||
|
||||
|
||||
# create a str.format-based logger
|
||||
class StrFormatLogger(Logger):
|
||||
class _LogMessage(object):
|
||||
def __init__(self, msg, args, kwargs):
|
||||
self.msg = msg
|
||||
self.args = args
|
||||
self.kwargs = kwargs
|
||||
|
||||
def __str__(self):
|
||||
return self.msg.format(*self.args, **self.kwargs)
|
||||
|
||||
def _log(self, level, msg, args, exc_info=None, extra=None, **kwargs):
|
||||
"""Log msg.format(*args, **kwargs)"""
|
||||
m = self._LogMessage(msg, args, kwargs)
|
||||
return Logger._log(self, level, m, (), exc_info, extra)
|
||||
# we cannot call super(StrFormatLogger, self) because it is not
|
||||
# allowed on old-style classes (py2) which Logger is in python 2.6
|
||||
# moreover we cannot make StrFormatLogger a new-style class (by
|
||||
# declaring 'class StrFormatLogger(Logger, object)' because the class-
|
||||
# patching stmt 'logger.__class__ = StrFormatLogger' would not work:
|
||||
# both prev & new __class__ values must be either old- or new- style,
|
||||
# no mixing allowed.
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
def getChild(self, suffix):
|
||||
"""Shameless copy from cpython's Lib/logging/__init__.py"""
|
||||
if self.root is not self:
|
||||
suffix = '.'.join((self.name, suffix))
|
||||
return self.manager.getLogger(suffix)
|
||||
|
||||
my_manager = copy(Logger.manager)
|
||||
my_manager.loggerClass = StrFormatLogger
|
||||
|
||||
|
||||
def getLogger(name=None):
|
||||
if name:
|
||||
return my_manager.getLogger(name)
|
||||
else:
|
||||
return Logger.root
|
||||
|
||||
|
||||
if sys.version_info[:2] == (2, 6):
|
||||
# no Manager.loggerClass so we dynamically change the logger class
|
||||
# we must be careful to do that on new loggers only to avoid side-effects.
|
||||
# Wrap Manager.getLogger
|
||||
old_getLogger = my_manager.getLogger
|
||||
|
||||
def new_getLogger(name):
|
||||
change_its_type = not isinstance(my_manager.loggerDict.get(name),
|
||||
Logger)
|
||||
# it either does not exist or is a placeholder
|
||||
logger = old_getLogger(name)
|
||||
if change_its_type:
|
||||
logger.__class__ = StrFormatLogger
|
||||
return logger
|
||||
|
||||
my_manager.getLogger = new_getLogger
|
||||
|
|
@ -48,10 +48,10 @@ import math
|
|||
import struct
|
||||
import imghdr
|
||||
import os
|
||||
import logging
|
||||
import traceback
|
||||
import enum
|
||||
|
||||
from beets import logging
|
||||
from beets.util import displayable_path
|
||||
|
||||
|
||||
|
|
@ -1313,7 +1313,7 @@ class MediaFile(object):
|
|||
try:
|
||||
self.mgfile = mutagen.File(path)
|
||||
except unreadable_exc as exc:
|
||||
log.debug(u'header parsing failed: {0}'.format(unicode(exc)))
|
||||
log.debug(u'header parsing failed: {0}', unicode(exc))
|
||||
raise UnreadableFileError(path)
|
||||
except IOError as exc:
|
||||
if type(exc) == IOError:
|
||||
|
|
@ -1326,7 +1326,7 @@ class MediaFile(object):
|
|||
except Exception as exc:
|
||||
# Isolate bugs in Mutagen.
|
||||
log.debug(traceback.format_exc())
|
||||
log.error(u'uncaught Mutagen exception in open: {0}'.format(exc))
|
||||
log.error(u'uncaught Mutagen exception in open: {0}', exc)
|
||||
raise MutagenError(path, exc)
|
||||
|
||||
if self.mgfile is None:
|
||||
|
|
@ -1399,7 +1399,7 @@ class MediaFile(object):
|
|||
raise
|
||||
except Exception as exc:
|
||||
log.debug(traceback.format_exc())
|
||||
log.error(u'uncaught Mutagen exception in save: {0}'.format(exc))
|
||||
log.error(u'uncaught Mutagen exception in save: {0}', exc)
|
||||
raise MutagenError(self.path, exc)
|
||||
|
||||
def delete(self):
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
"""Support for beets plugins."""
|
||||
|
||||
import logging
|
||||
import traceback
|
||||
import inspect
|
||||
import re
|
||||
|
|
@ -22,6 +21,7 @@ from collections import defaultdict
|
|||
|
||||
|
||||
import beets
|
||||
from beets import logging
|
||||
from beets import mediafile
|
||||
|
||||
PLUGIN_NAMESPACE = 'beetsplug'
|
||||
|
|
@ -204,7 +204,7 @@ def load_plugins(names=()):
|
|||
except ImportError as exc:
|
||||
# Again, this is hacky:
|
||||
if exc.args[0].endswith(' ' + name):
|
||||
log.warn(u'** plugin {0} not found'.format(name))
|
||||
log.warn(u'** plugin {0} not found', name)
|
||||
else:
|
||||
raise
|
||||
else:
|
||||
|
|
@ -214,7 +214,7 @@ def load_plugins(names=()):
|
|||
_classes.add(obj)
|
||||
|
||||
except:
|
||||
log.warn(u'** error loading plugin {0}'.format(name))
|
||||
log.warn(u'** error loading plugin {0}', name)
|
||||
log.warn(traceback.format_exc())
|
||||
|
||||
|
||||
|
|
@ -398,7 +398,7 @@ def send(event, **arguments):
|
|||
|
||||
Returns a list of return values from the handlers.
|
||||
"""
|
||||
log.debug(u'Sending event: {0}'.format(event))
|
||||
log.debug(u'Sending event: {0}', event)
|
||||
for handler in event_handlers()[event]:
|
||||
# Don't break legacy plugins if we want to pass more arguments
|
||||
argspec = inspect.getargspec(handler).args
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import optparse
|
|||
import textwrap
|
||||
import sys
|
||||
from difflib import SequenceMatcher
|
||||
import logging
|
||||
import sqlite3
|
||||
import errno
|
||||
import re
|
||||
|
|
@ -31,6 +30,7 @@ import struct
|
|||
import traceback
|
||||
import os.path
|
||||
|
||||
from beets import logging
|
||||
from beets import library
|
||||
from beets import plugins
|
||||
from beets import util
|
||||
|
|
@ -866,14 +866,14 @@ def _configure(options):
|
|||
|
||||
config_path = config.user_config_path()
|
||||
if os.path.isfile(config_path):
|
||||
log.debug(u'user configuration: {0}'.format(
|
||||
util.displayable_path(config_path)))
|
||||
log.debug(u'user configuration: {0}',
|
||||
util.displayable_path(config_path))
|
||||
else:
|
||||
log.debug(u'no user configuration found at {0}'.format(
|
||||
util.displayable_path(config_path)))
|
||||
log.debug(u'no user configuration found at {0}',
|
||||
util.displayable_path(config_path))
|
||||
|
||||
log.debug(u'data directory: {0}'
|
||||
.format(util.displayable_path(config.config_dir())))
|
||||
log.debug(u'data directory: {0}',
|
||||
util.displayable_path(config.config_dir()))
|
||||
return config
|
||||
|
||||
|
||||
|
|
@ -895,9 +895,9 @@ def _open_library(config):
|
|||
util.displayable_path(dbpath)
|
||||
))
|
||||
log.debug(u'library database: {0}\n'
|
||||
u'library directory: {1}'
|
||||
.format(util.displayable_path(lib.path),
|
||||
util.displayable_path(lib.directory)))
|
||||
u'library directory: {1}',
|
||||
util.displayable_path(lib.path),
|
||||
util.displayable_path(lib.directory))
|
||||
return lib
|
||||
|
||||
|
||||
|
|
@ -945,7 +945,7 @@ def main(args=None):
|
|||
_raw_main(args)
|
||||
except UserError as exc:
|
||||
message = exc.args[0] if exc.args else None
|
||||
log.error(u'error: {0}'.format(message))
|
||||
log.error(u'error: {0}', message)
|
||||
sys.exit(1)
|
||||
except util.HumanReadableException as exc:
|
||||
exc.log(log)
|
||||
|
|
@ -957,7 +957,7 @@ def main(args=None):
|
|||
log.error(exc)
|
||||
sys.exit(1)
|
||||
except confit.ConfigError as exc:
|
||||
log.error(u'configuration error: {0}'.format(exc))
|
||||
log.error(u'configuration error: {0}', exc)
|
||||
sys.exit(1)
|
||||
except IOError as exc:
|
||||
if exc.errno == errno.EPIPE:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ interface.
|
|||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
import codecs
|
||||
|
|
@ -38,6 +37,7 @@ from beets.util import syspath, normpath, ancestry, displayable_path
|
|||
from beets.util.functemplate import Template
|
||||
from beets import library
|
||||
from beets import config
|
||||
from beets import logging
|
||||
from beets.util.confit import _package_path
|
||||
|
||||
VARIOUS_ARTISTS = u'Various Artists'
|
||||
|
|
@ -765,8 +765,8 @@ class TerminalImportSession(importer.ImportSession):
|
|||
"""Decide what to do when a new album or item seems similar to one
|
||||
that's already in the library.
|
||||
"""
|
||||
log.warn(u"This {0} is already in the library!"
|
||||
.format("album" if task.is_album else "item"))
|
||||
log.warn(u"This {0} is already in the library!",
|
||||
("album" if task.is_album else "item"))
|
||||
|
||||
if config['import']['quiet']:
|
||||
# In quiet mode, don't prompt -- just skip.
|
||||
|
|
@ -1015,16 +1015,16 @@ def update_items(lib, query, album, move, pretend):
|
|||
|
||||
# Did the item change since last checked?
|
||||
if item.current_mtime() <= item.mtime:
|
||||
log.debug(u'skipping {0} because mtime is up to date ({1})'
|
||||
.format(displayable_path(item.path), item.mtime))
|
||||
log.debug(u'skipping {0} because mtime is up to date ({1})',
|
||||
displayable_path(item.path), item.mtime)
|
||||
continue
|
||||
|
||||
# Read new data.
|
||||
try:
|
||||
item.read()
|
||||
except library.ReadError as exc:
|
||||
log.error(u'error reading {0}: {1}'.format(
|
||||
displayable_path(item.path), exc))
|
||||
log.error(u'error reading {0}: {1}',
|
||||
displayable_path(item.path), exc)
|
||||
continue
|
||||
|
||||
# Special-case album artist when it matches track artist. (Hacky
|
||||
|
|
@ -1066,7 +1066,7 @@ def update_items(lib, query, album, move, pretend):
|
|||
continue
|
||||
album = lib.get_album(album_id)
|
||||
if not album: # Empty albums have already been removed.
|
||||
log.debug(u'emptied album {0}'.format(album_id))
|
||||
log.debug(u'emptied album {0}', album_id)
|
||||
continue
|
||||
first_item = album.items().get()
|
||||
|
||||
|
|
@ -1077,7 +1077,7 @@ def update_items(lib, query, album, move, pretend):
|
|||
|
||||
# Move album art (and any inconsistent items).
|
||||
if move and lib.directory in ancestry(first_item.path):
|
||||
log.debug(u'moving album {0}'.format(album_id))
|
||||
log.debug(u'moving album {0}', album_id)
|
||||
album.move()
|
||||
|
||||
|
||||
|
|
@ -1299,8 +1299,7 @@ def modify_items(lib, mods, dels, query, write, move, album, confirm):
|
|||
if move:
|
||||
cur_path = obj.path
|
||||
if lib.directory in ancestry(cur_path): # In library?
|
||||
log.debug(u'moving object {0}'
|
||||
.format(displayable_path(cur_path)))
|
||||
log.debug(u'moving object {0}', displayable_path(cur_path))
|
||||
obj.move()
|
||||
|
||||
obj.try_sync(write)
|
||||
|
|
@ -1378,9 +1377,9 @@ def move_items(lib, dest, query, copy, album):
|
|||
|
||||
action = 'Copying' if copy else 'Moving'
|
||||
entity = 'album' if album else 'item'
|
||||
log.info(u'{0} {1} {2}s.'.format(action, len(objs), entity))
|
||||
log.info(u'{0} {1} {2}s.', action, len(objs), entity)
|
||||
for obj in objs:
|
||||
log.debug(u'moving: {0}'.format(util.displayable_path(obj.path)))
|
||||
log.debug(u'moving: {0}', util.displayable_path(obj.path))
|
||||
|
||||
obj.move(copy, basedir=dest)
|
||||
obj.store()
|
||||
|
|
@ -1426,18 +1425,15 @@ def write_items(lib, query, pretend, force):
|
|||
for item in items:
|
||||
# Item deleted?
|
||||
if not os.path.exists(syspath(item.path)):
|
||||
log.info(u'missing file: {0}'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'missing file: {0}', util.displayable_path(item.path))
|
||||
continue
|
||||
|
||||
# Get an Item object reflecting the "clean" (on-disk) state.
|
||||
try:
|
||||
clean_item = library.Item.from_path(item.path)
|
||||
except library.ReadError as exc:
|
||||
log.error(u'error reading {0}: {1}'.format(
|
||||
displayable_path(item.path), exc
|
||||
))
|
||||
log.error(u'error reading {0}: {1}',
|
||||
displayable_path(item.path), exc)
|
||||
continue
|
||||
|
||||
# Check for and display changes.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ import subprocess
|
|||
import os
|
||||
import re
|
||||
from tempfile import NamedTemporaryFile
|
||||
import logging
|
||||
|
||||
from beets import logging
|
||||
from beets import util
|
||||
|
||||
# Resizing methods
|
||||
|
|
@ -58,9 +59,8 @@ def pil_resize(maxwidth, path_in, path_out=None):
|
|||
"""
|
||||
path_out = path_out or temp_file_for(path_in)
|
||||
from PIL import Image
|
||||
log.debug(u'artresizer: PIL resizing {0} to {1}'.format(
|
||||
util.displayable_path(path_in), util.displayable_path(path_out)
|
||||
))
|
||||
log.debug(u'artresizer: PIL resizing {0} to {1}',
|
||||
util.displayable_path(path_in), util.displayable_path(path_out))
|
||||
|
||||
try:
|
||||
im = Image.open(util.syspath(path_in))
|
||||
|
|
@ -69,9 +69,8 @@ def pil_resize(maxwidth, path_in, path_out=None):
|
|||
im.save(path_out)
|
||||
return path_out
|
||||
except IOError:
|
||||
log.error(u"PIL cannot create thumbnail for '{0}'".format(
|
||||
util.displayable_path(path_in)
|
||||
))
|
||||
log.error(u"PIL cannot create thumbnail for '{0}'",
|
||||
util.displayable_path(path_in))
|
||||
return path_in
|
||||
|
||||
|
||||
|
|
@ -80,9 +79,8 @@ def im_resize(maxwidth, path_in, path_out=None):
|
|||
Return the output path of resized image.
|
||||
"""
|
||||
path_out = path_out or temp_file_for(path_in)
|
||||
log.debug(u'artresizer: ImageMagick resizing {0} to {1}'.format(
|
||||
util.displayable_path(path_in), util.displayable_path(path_out)
|
||||
))
|
||||
log.debug(u'artresizer: ImageMagick resizing {0} to {1}',
|
||||
util.displayable_path(path_in), util.displayable_path(path_out))
|
||||
|
||||
# "-resize widthxheight>" shrinks images with dimension(s) larger
|
||||
# than the corresponding width and/or height dimension(s). The >
|
||||
|
|
@ -94,9 +92,8 @@ def im_resize(maxwidth, path_in, path_out=None):
|
|||
'-resize', '{0}x^>'.format(maxwidth), path_out
|
||||
])
|
||||
except subprocess.CalledProcessError:
|
||||
log.warn(u'artresizer: IM convert failed for {0}'.format(
|
||||
util.displayable_path(path_in)
|
||||
))
|
||||
log.warn(u'artresizer: IM convert failed for {0}',
|
||||
util.displayable_path(path_in))
|
||||
return path_in
|
||||
return path_out
|
||||
|
||||
|
|
@ -134,7 +131,7 @@ class ArtResizer(object):
|
|||
specified, with an inferred method.
|
||||
"""
|
||||
self.method = self._check_method(method)
|
||||
log.debug(u"artresizer: method is {0}".format(self.method))
|
||||
log.debug(u"artresizer: method is {0}", self.method)
|
||||
self.can_compare = self._can_compare()
|
||||
|
||||
def resize(self, maxwidth, path_in, path_out=None):
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@
|
|||
|
||||
"""Adds Beatport release and track search support to the autotagger
|
||||
"""
|
||||
import logging
|
||||
import re
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import requests
|
||||
|
||||
from beets import logging
|
||||
from beets.autotag.hooks import AlbumInfo, TrackInfo, Distance
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
|
|
@ -194,7 +194,7 @@ class BeatportPlugin(BeetsPlugin):
|
|||
try:
|
||||
return self._get_releases(query)
|
||||
except BeatportAPIError as e:
|
||||
log.debug(u'Beatport API Error: {0} (query: {1})'.format(e, query))
|
||||
log.debug(u'Beatport API Error: {0} (query: {1})', e, query)
|
||||
return []
|
||||
|
||||
def item_candidates(self, item, artist, title):
|
||||
|
|
@ -205,14 +205,14 @@ class BeatportPlugin(BeetsPlugin):
|
|||
try:
|
||||
return self._get_tracks(query)
|
||||
except BeatportAPIError as e:
|
||||
log.debug(u'Beatport API Error: {0} (query: {1})'.format(e, query))
|
||||
log.debug(u'Beatport API Error: {0} (query: {1})', e, query)
|
||||
return []
|
||||
|
||||
def album_for_id(self, release_id):
|
||||
"""Fetches a release by its Beatport ID and returns an AlbumInfo object
|
||||
or None if the release is not found.
|
||||
"""
|
||||
log.debug(u'Searching Beatport for release {0}'.format(release_id))
|
||||
log.debug(u'Searching Beatport for release {0}', release_id)
|
||||
match = re.search(r'(^|beatport\.com/release/.+/)(\d+)$', release_id)
|
||||
if not match:
|
||||
return None
|
||||
|
|
@ -224,7 +224,7 @@ class BeatportPlugin(BeetsPlugin):
|
|||
"""Fetches a track by its Beatport ID and returns a TrackInfo object
|
||||
or None if the track is not found.
|
||||
"""
|
||||
log.debug(u'Searching Beatport for track {0}'.format(str(track_id)))
|
||||
log.debug(u'Searching Beatport for track {0}', track_id)
|
||||
match = re.search(r'(^|beatport\.com/track/.+/)(\d+)$', track_id)
|
||||
if not match:
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -21,13 +21,13 @@ from __future__ import print_function
|
|||
import re
|
||||
from string import Template
|
||||
import traceback
|
||||
import logging
|
||||
import random
|
||||
import time
|
||||
|
||||
import beets
|
||||
from beets.plugins import BeetsPlugin
|
||||
import beets.ui
|
||||
from beets import logging
|
||||
from beets import vfs
|
||||
from beets.util import bluelet
|
||||
from beets.library import Item
|
||||
|
|
|
|||
|
|
@ -15,9 +15,8 @@
|
|||
"""Determine BPM by pressing a key to the rhythm."""
|
||||
|
||||
import time
|
||||
import logging
|
||||
|
||||
from beets import ui
|
||||
from beets import ui, logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
|
@ -73,15 +72,15 @@ class BPMPlugin(BeetsPlugin):
|
|||
|
||||
item = items[0]
|
||||
if item['bpm']:
|
||||
log.info(u'Found bpm {0}'.format(item['bpm']))
|
||||
log.info(u'Found bpm {0}', item['bpm'])
|
||||
if not overwrite:
|
||||
return
|
||||
|
||||
log.info(u'Press Enter {0} times to the rhythm or Ctrl-D '
|
||||
u'to exit'.format(self.config['max_strokes'].get(int)))
|
||||
u'to exit', self.config['max_strokes'].get(int))
|
||||
new_bpm = bpm(self.config['max_strokes'].get(int))
|
||||
item['bpm'] = int(new_bpm)
|
||||
if write:
|
||||
item.try_write()
|
||||
item.store()
|
||||
log.info(u'Added new bpm {0}'.format(item['bpm']))
|
||||
log.info(u'Added new bpm {0}', item['bpm'])
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@
|
|||
"""
|
||||
|
||||
from datetime import datetime
|
||||
import logging
|
||||
import re
|
||||
import string
|
||||
from itertools import tee, izip
|
||||
|
||||
from beets import logging
|
||||
from beets import plugins, ui
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
|
|
|||
|
|
@ -19,10 +19,10 @@ from beets import plugins
|
|||
from beets import ui
|
||||
from beets import util
|
||||
from beets import config
|
||||
from beets import logging
|
||||
from beets.util import confit
|
||||
from beets.autotag import hooks
|
||||
import acoustid
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
API_KEY = '1vOwZtEn'
|
||||
|
|
@ -64,19 +64,19 @@ def acoustid_match(path):
|
|||
try:
|
||||
duration, fp = acoustid.fingerprint_file(util.syspath(path))
|
||||
except acoustid.FingerprintGenerationError as exc:
|
||||
log.error(u'fingerprinting of {0} failed: {1}'
|
||||
.format(util.displayable_path(repr(path)), str(exc)))
|
||||
log.error(u'fingerprinting of {0} failed: {1}',
|
||||
util.displayable_path(repr(path)), str(exc))
|
||||
return None
|
||||
_fingerprints[path] = fp
|
||||
try:
|
||||
res = acoustid.lookup(API_KEY, fp, duration,
|
||||
meta='recordings releases')
|
||||
except acoustid.AcoustidError as exc:
|
||||
log.debug(u'fingerprint matching {0} failed: {1}'
|
||||
.format(util.displayable_path(repr(path)), str(exc)))
|
||||
log.debug(u'fingerprint matching {0} failed: {1}',
|
||||
util.displayable_path(repr(path)), exc)
|
||||
return None
|
||||
log.debug(u'chroma: fingerprinted {0}'
|
||||
.format(util.displayable_path(repr(path))))
|
||||
log.debug(u'chroma: fingerprinted {0}',
|
||||
util.displayable_path(repr(path)))
|
||||
|
||||
# Ensure the response is usable and parse it.
|
||||
if res['status'] != 'ok' or not res.get('results'):
|
||||
|
|
@ -99,9 +99,8 @@ def acoustid_match(path):
|
|||
if 'releases' in recording:
|
||||
release_ids += [rel['id'] for rel in recording['releases']]
|
||||
|
||||
log.debug(u'chroma: matched recordings {0} on releases {1}'.format(
|
||||
recording_ids, release_ids,
|
||||
))
|
||||
log.debug(u'chroma: matched recordings {0} on releases {1}',
|
||||
recording_ids, release_ids)
|
||||
_matches[path] = recording_ids, release_ids
|
||||
|
||||
|
||||
|
|
@ -155,7 +154,7 @@ class AcoustidPlugin(plugins.BeetsPlugin):
|
|||
if album:
|
||||
albums.append(album)
|
||||
|
||||
log.debug(u'acoustid album candidates: {0}'.format(len(albums)))
|
||||
log.debug(u'acoustid album candidates: {0}', len(albums))
|
||||
return albums
|
||||
|
||||
def item_candidates(self, item, artist, title):
|
||||
|
|
@ -168,7 +167,7 @@ class AcoustidPlugin(plugins.BeetsPlugin):
|
|||
track = hooks.track_for_mbid(recording_id)
|
||||
if track:
|
||||
tracks.append(track)
|
||||
log.debug(u'acoustid item candidates: {0}'.format(len(tracks)))
|
||||
log.debug(u'acoustid item candidates: {0}', len(tracks))
|
||||
return tracks
|
||||
|
||||
def commands(self):
|
||||
|
|
@ -230,11 +229,11 @@ def submit_items(userkey, items, chunksize=64):
|
|||
|
||||
def submit_chunk():
|
||||
"""Submit the current accumulated fingerprint data."""
|
||||
log.info(u'submitting {0} fingerprints'.format(len(data)))
|
||||
log.info(u'submitting {0} fingerprints', len(data))
|
||||
try:
|
||||
acoustid.submit(API_KEY, userkey, data)
|
||||
except acoustid.AcoustidError as exc:
|
||||
log.warn(u'acoustid submission error: {0}'.format(exc))
|
||||
log.warn(u'acoustid submission error: {0}', exc)
|
||||
del data[:]
|
||||
|
||||
for item in items:
|
||||
|
|
@ -279,34 +278,28 @@ def fingerprint_item(item, write=False):
|
|||
"""
|
||||
# Get a fingerprint and length for this track.
|
||||
if not item.length:
|
||||
log.info(u'{0}: no duration available'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'{0}: no duration available',
|
||||
util.displayable_path(item.path))
|
||||
elif item.acoustid_fingerprint:
|
||||
if write:
|
||||
log.info(u'{0}: fingerprint exists, skipping'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'{0}: fingerprint exists, skipping',
|
||||
util.displayable_path(item.path))
|
||||
else:
|
||||
log.info(u'{0}: using existing fingerprint'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'{0}: using existing fingerprint',
|
||||
util.displayable_path(item.path))
|
||||
return item.acoustid_fingerprint
|
||||
else:
|
||||
log.info(u'{0}: fingerprinting'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'{0}: fingerprinting',
|
||||
util.displayable_path(item.path))
|
||||
try:
|
||||
_, fp = acoustid.fingerprint_file(item.path)
|
||||
item.acoustid_fingerprint = fp
|
||||
if write:
|
||||
log.info(u'{0}: writing fingerprint'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'{0}: writing fingerprint',
|
||||
util.displayable_path(item.path))
|
||||
item.try_write()
|
||||
if item._db:
|
||||
item.store()
|
||||
return item.acoustid_fingerprint
|
||||
except acoustid.FingerprintGenerationError as exc:
|
||||
log.info(u'fingerprint generation failed: {0}'
|
||||
.format(exc))
|
||||
log.info(u'fingerprint generation failed: {0}', exc)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
"""Converts tracks or albums to external directory
|
||||
"""
|
||||
import logging
|
||||
import os
|
||||
import threading
|
||||
import subprocess
|
||||
|
|
@ -22,7 +21,7 @@ import tempfile
|
|||
import shlex
|
||||
from string import Template
|
||||
|
||||
from beets import ui, util, plugins, config
|
||||
from beets import logging, ui, util, plugins, config
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beetsplug.embedart import embed_item
|
||||
from beets.util.confit import ConfigTypeError
|
||||
|
|
@ -92,7 +91,7 @@ def encode(command, source, dest, pretend=False):
|
|||
quiet = config['convert']['quiet'].get()
|
||||
|
||||
if not quiet and not pretend:
|
||||
log.info(u'Encoding {0}'.format(util.displayable_path(source)))
|
||||
log.info(u'Encoding {0}', util.displayable_path(source))
|
||||
|
||||
# Substitute $source and $dest in the argument list.
|
||||
args = shlex.split(command)
|
||||
|
|
@ -110,12 +109,11 @@ def encode(command, source, dest, pretend=False):
|
|||
util.command_output(args)
|
||||
except subprocess.CalledProcessError as exc:
|
||||
# Something went wrong (probably Ctrl+C), remove temporary files
|
||||
log.info(u'Encoding {0} failed. Cleaning up...'
|
||||
.format(util.displayable_path(source)))
|
||||
log.debug(u'Command {0} exited with status {1}'.format(
|
||||
exc.cmd.decode('utf8', 'ignore'),
|
||||
exc.returncode,
|
||||
))
|
||||
log.info(u'Encoding {0} failed. Cleaning up...',
|
||||
util.displayable_path(source))
|
||||
log.debug(u'Command {0} exited with status {1}',
|
||||
exc.cmd.decode('utf8', 'ignore'),
|
||||
exc.returncode)
|
||||
util.remove(dest)
|
||||
util.prune_dirs(os.path.dirname(dest))
|
||||
raise
|
||||
|
|
@ -127,9 +125,8 @@ def encode(command, source, dest, pretend=False):
|
|||
)
|
||||
|
||||
if not quiet and not pretend:
|
||||
log.info(u'Finished encoding {0}'.format(
|
||||
util.displayable_path(source))
|
||||
)
|
||||
log.info(u'Finished encoding {0}',
|
||||
util.displayable_path(source))
|
||||
|
||||
|
||||
def should_transcode(item, format):
|
||||
|
|
@ -173,21 +170,17 @@ def convert_item(dest_dir, keep_new, path_formats, format, pretend=False):
|
|||
util.mkdirall(dest)
|
||||
|
||||
if os.path.exists(util.syspath(dest)):
|
||||
log.info(u'Skipping {0} (target file exists)'.format(
|
||||
util.displayable_path(item.path)
|
||||
))
|
||||
log.info(u'Skipping {0} (target file exists)',
|
||||
util.displayable_path(item.path))
|
||||
continue
|
||||
|
||||
if keep_new:
|
||||
if pretend:
|
||||
log.info(u'mv {0} {1}'.format(
|
||||
util.displayable_path(item.path),
|
||||
util.displayable_path(original),
|
||||
))
|
||||
log.info(u'mv {0} {1}',
|
||||
util.displayable_path(item.path),
|
||||
util.displayable_path(original))
|
||||
else:
|
||||
log.info(u'Moving to {0}'.format(
|
||||
util.displayable_path(original))
|
||||
)
|
||||
log.info(u'Moving to {0}', util.displayable_path(original))
|
||||
util.move(item.path, original)
|
||||
|
||||
if should_transcode(item, format):
|
||||
|
|
@ -197,15 +190,12 @@ def convert_item(dest_dir, keep_new, path_formats, format, pretend=False):
|
|||
continue
|
||||
else:
|
||||
if pretend:
|
||||
log.info(u'cp {0} {1}'.format(
|
||||
util.displayable_path(original),
|
||||
util.displayable_path(converted),
|
||||
))
|
||||
log.info(u'cp {0} {1}',
|
||||
util.displayable_path(original),
|
||||
util.displayable_path(converted))
|
||||
else:
|
||||
# No transcoding necessary.
|
||||
log.info(u'Copying {0}'.format(
|
||||
util.displayable_path(item.path))
|
||||
)
|
||||
log.info(u'Copying {0}', util.displayable_path(item.path))
|
||||
util.copy(original, converted)
|
||||
|
||||
if pretend:
|
||||
|
|
@ -281,19 +271,17 @@ def copy_album_art(album, dest_dir, path_formats, pretend=False):
|
|||
util.mkdirall(dest)
|
||||
|
||||
if os.path.exists(util.syspath(dest)):
|
||||
log.info(u'Skipping {0} (target file exists)'.format(
|
||||
util.displayable_path(album.artpath)
|
||||
))
|
||||
log.info(u'Skipping {0} (target file exists)',
|
||||
util.displayable_path(album.artpath))
|
||||
return
|
||||
|
||||
if pretend:
|
||||
log.info(u'cp {0} {1}'.format(
|
||||
util.displayable_path(album.artpath),
|
||||
util.displayable_path(dest),
|
||||
))
|
||||
log.info(u'cp {0} {1}',
|
||||
util.displayable_path(album.artpath),
|
||||
util.displayable_path(dest))
|
||||
else:
|
||||
log.info(u'Copying cover art to {0}'.format(
|
||||
util.displayable_path(dest)))
|
||||
log.info(u'Copying cover art to {0}',
|
||||
util.displayable_path(dest))
|
||||
util.copy(album.artpath, dest)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
"""Adds Discogs album search support to the autotagger. Requires the
|
||||
discogs-client library.
|
||||
"""
|
||||
from beets import logging
|
||||
from beets.autotag.hooks import AlbumInfo, TrackInfo, Distance
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.util import confit
|
||||
|
|
@ -22,7 +23,6 @@ from discogs_client import Release, Client
|
|||
from discogs_client.exceptions import DiscogsAPIError
|
||||
from requests.exceptions import ConnectionError
|
||||
import beets
|
||||
import logging
|
||||
import re
|
||||
import time
|
||||
import json
|
||||
|
|
@ -89,7 +89,7 @@ class DiscogsPlugin(BeetsPlugin):
|
|||
raise beets.ui.UserError('Discogs authorization failed')
|
||||
|
||||
# Save the token for later use.
|
||||
log.debug('Discogs token {0}, secret {1}'.format(token, secret))
|
||||
log.debug('Discogs token {0}, secret {1}', token, secret)
|
||||
with open(self._tokenfile(), 'w') as f:
|
||||
json.dump({'token': token, 'secret': secret}, f)
|
||||
|
||||
|
|
@ -117,10 +117,10 @@ class DiscogsPlugin(BeetsPlugin):
|
|||
try:
|
||||
return self.get_albums(query)
|
||||
except DiscogsAPIError as e:
|
||||
log.debug(u'Discogs API Error: {0} (query: {1})'.format(e, query))
|
||||
log.debug(u'Discogs API Error: {0} (query: {1})', e, query)
|
||||
return []
|
||||
except ConnectionError as e:
|
||||
log.debug(u'HTTP Connection Error: {0}'.format(e))
|
||||
log.debug(u'HTTP Connection Error: {0}', e)
|
||||
return []
|
||||
|
||||
def album_for_id(self, album_id):
|
||||
|
|
@ -130,7 +130,7 @@ class DiscogsPlugin(BeetsPlugin):
|
|||
if not self.discogs_client:
|
||||
return
|
||||
|
||||
log.debug(u'Searching Discogs for release {0}'.format(str(album_id)))
|
||||
log.debug(u'Searching Discogs for release {0}', album_id)
|
||||
# Discogs-IDs are simple integers. We only look for those at the end
|
||||
# of an input string as to avoid confusion with other metadata plugins.
|
||||
# An optional bracket can follow the integer, as this is how discogs
|
||||
|
|
@ -145,11 +145,11 @@ class DiscogsPlugin(BeetsPlugin):
|
|||
getattr(result, 'title')
|
||||
except DiscogsAPIError as e:
|
||||
if e.message != '404 Not Found':
|
||||
log.debug(u'Discogs API Error: {0} (query: {1})'
|
||||
.format(e, result._uri))
|
||||
log.debug(u'Discogs API Error: {0} (query: {1})',
|
||||
e, result._uri)
|
||||
return None
|
||||
except ConnectionError as e:
|
||||
log.debug(u'HTTP Connection Error: {0}'.format(e))
|
||||
log.debug(u'HTTP Connection Error: {0}', e)
|
||||
return None
|
||||
return self.get_album_info(result)
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ class DiscogsPlugin(BeetsPlugin):
|
|||
if match:
|
||||
medium, index = match.groups()
|
||||
else:
|
||||
log.debug(u'Invalid Discogs position: {0}'.format(position))
|
||||
log.debug(u'Invalid Discogs position: {0}', position)
|
||||
medium = index = None
|
||||
return medium or None, index or None
|
||||
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
"""List duplicate tracks or albums.
|
||||
"""
|
||||
import shlex
|
||||
import logging
|
||||
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import decargs, print_obj, vararg_callback, Subcommand, UserError
|
||||
from beets.util import command_output, displayable_path, subprocess
|
||||
|
|
@ -56,20 +56,20 @@ def _checksum(item, prog):
|
|||
key = args[0]
|
||||
checksum = getattr(item, key, False)
|
||||
if not checksum:
|
||||
log.debug(u'{0}: key {1} on item {2} not cached: computing checksum'
|
||||
.format(PLUGIN, key, displayable_path(item.path)))
|
||||
log.debug(u'{0}: key {1} on item {2} not cached: computing checksum',
|
||||
PLUGIN, key, displayable_path(item.path))
|
||||
try:
|
||||
checksum = command_output(args)
|
||||
setattr(item, key, checksum)
|
||||
item.store()
|
||||
log.debug(u'{)}: computed checksum for {1} using {2}'
|
||||
.format(PLUGIN, item.title, key))
|
||||
log.debug(u'{0}: computed checksum for {1} using {2}',
|
||||
PLUGIN, item.title, key)
|
||||
except subprocess.CalledProcessError as e:
|
||||
log.debug(u'{0}: failed to checksum {1}: {2}'
|
||||
.format(PLUGIN, displayable_path(item.path), e))
|
||||
log.debug(u'{0}: failed to checksum {1}: {2}',
|
||||
PLUGIN, displayable_path(item.path), e)
|
||||
else:
|
||||
log.debug(u'{0}: key {1} on item {2} cached: not computing checksum'
|
||||
.format(PLUGIN, key, displayable_path(item.path)))
|
||||
log.debug(u'{0}: key {1} on item {2} cached: not computing checksum',
|
||||
PLUGIN, key, displayable_path(item.path))
|
||||
return key, checksum
|
||||
|
||||
|
||||
|
|
@ -86,8 +86,8 @@ def _group_by(objs, keys):
|
|||
key = '\001'.join(values)
|
||||
counts[key].append(obj)
|
||||
else:
|
||||
log.debug(u'{0}: all keys {1} on item {2} are null: skipping'
|
||||
.format(PLUGIN, str(keys), displayable_path(obj.path)))
|
||||
log.debug(u'{0}: all keys {1} on item {2} are null: skipping',
|
||||
PLUGIN, str(keys), displayable_path(obj.path))
|
||||
|
||||
return counts
|
||||
|
||||
|
|
|
|||
|
|
@ -15,14 +15,13 @@
|
|||
"""Fetch a variety of acoustic metrics from The Echo Nest.
|
||||
"""
|
||||
import time
|
||||
import logging
|
||||
import socket
|
||||
import os
|
||||
import tempfile
|
||||
from string import Template
|
||||
import subprocess
|
||||
|
||||
from beets import util, config, plugins, ui
|
||||
from beets import util, config, plugins, ui, logging
|
||||
from beets.dbcore import types
|
||||
import pyechonest
|
||||
import pyechonest.song
|
||||
|
|
@ -154,23 +153,23 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
if e.code == 3:
|
||||
# reached access limit per minute
|
||||
log.debug(u'echonest: rate-limited on try {0}; '
|
||||
u'waiting {1} seconds'
|
||||
.format(i + 1, RETRY_INTERVAL))
|
||||
u'waiting {1} seconds',
|
||||
i + 1, RETRY_INTERVAL)
|
||||
time.sleep(RETRY_INTERVAL)
|
||||
elif e.code == 5:
|
||||
# specified identifier does not exist
|
||||
# no use in trying again.
|
||||
log.debug(u'echonest: {0}'.format(e))
|
||||
log.debug(u'echonest: {0}', e)
|
||||
return None
|
||||
else:
|
||||
log.error(u'echonest: {0}'.format(e.args[0][0]))
|
||||
log.error(u'echonest: {0}', e.args[0][0])
|
||||
return None
|
||||
except (pyechonest.util.EchoNestIOError, socket.error) as e:
|
||||
log.warn(u'echonest: IO error: {0}'.format(e))
|
||||
log.warn(u'echonest: IO error: {0}', e)
|
||||
time.sleep(RETRY_INTERVAL)
|
||||
except Exception as e:
|
||||
# there was an error analyzing the track, status: error
|
||||
log.debug(u'echonest: {0}'.format(e))
|
||||
log.debug(u'echonest: {0}', e)
|
||||
return None
|
||||
else:
|
||||
break
|
||||
|
|
@ -292,10 +291,9 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
fd, dest = tempfile.mkstemp(u'.ogg')
|
||||
os.close(fd)
|
||||
|
||||
log.info(u'echonest: encoding {0} to {1}'.format(
|
||||
util.displayable_path(source),
|
||||
util.displayable_path(dest),
|
||||
))
|
||||
log.info(u'echonest: encoding {0} to {1}',
|
||||
util.displayable_path(source),
|
||||
util.displayable_path(dest))
|
||||
|
||||
opts = []
|
||||
for arg in CONVERT_COMMAND.split():
|
||||
|
|
@ -306,13 +304,12 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
try:
|
||||
util.command_output(opts)
|
||||
except (OSError, subprocess.CalledProcessError) as exc:
|
||||
log.debug(u'echonest: encode failed: {0}'.format(exc))
|
||||
log.debug(u'echonest: encode failed: {0}', exc)
|
||||
util.remove(dest)
|
||||
return
|
||||
|
||||
log.info(u'echonest: finished encoding {0}'.format(
|
||||
util.displayable_path(source))
|
||||
)
|
||||
log.info(u'echonest: finished encoding {0}',
|
||||
util.displayable_path(source))
|
||||
return dest
|
||||
|
||||
def truncate(self, source):
|
||||
|
|
@ -320,10 +317,9 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
fd, dest = tempfile.mkstemp(u'.ogg')
|
||||
os.close(fd)
|
||||
|
||||
log.info(u'echonest: truncating {0} to {1}'.format(
|
||||
util.displayable_path(source),
|
||||
util.displayable_path(dest),
|
||||
))
|
||||
log.info(u'echonest: truncating {0} to {1}',
|
||||
util.displayable_path(source),
|
||||
util.displayable_path(dest))
|
||||
|
||||
opts = []
|
||||
for arg in TRUNCATE_COMMAND.split():
|
||||
|
|
@ -334,13 +330,12 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
try:
|
||||
util.command_output(opts)
|
||||
except (OSError, subprocess.CalledProcessError) as exc:
|
||||
log.debug(u'echonest: truncate failed: {0}'.format(exc))
|
||||
log.debug(u'echonest: truncate failed: {0}', exc)
|
||||
util.remove(dest)
|
||||
return
|
||||
|
||||
log.info(u'echonest: truncate encoding {0}'.format(
|
||||
util.displayable_path(source))
|
||||
)
|
||||
log.info(u'echonest: truncate encoding {0}',
|
||||
util.displayable_path(source))
|
||||
return dest
|
||||
|
||||
def analyze(self, item):
|
||||
|
|
@ -411,14 +406,12 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
for method in methods:
|
||||
song = method(item)
|
||||
if song:
|
||||
log.debug(
|
||||
u'echonest: got song through {0}: {1} - {2} [{3}]'.format(
|
||||
method.__name__,
|
||||
item.artist,
|
||||
item.title,
|
||||
song.get('duration'),
|
||||
)
|
||||
)
|
||||
log.debug(u'echonest: got song through {0}: {1} - {2} [{3}]',
|
||||
method.__name__,
|
||||
item.artist,
|
||||
item.title,
|
||||
song.get('duration'),
|
||||
)
|
||||
return song
|
||||
|
||||
def apply_metadata(self, item, values, write=False):
|
||||
|
|
@ -429,7 +422,7 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
for k, v in values.iteritems():
|
||||
if k in ATTRIBUTES:
|
||||
field = ATTRIBUTES[k]
|
||||
log.debug(u'echonest: metadata: {0} = {1}'.format(field, v))
|
||||
log.debug(u'echonest: metadata: {0} = {1}', field, v)
|
||||
if field == 'bpm':
|
||||
item[field] = int(v)
|
||||
else:
|
||||
|
|
@ -441,7 +434,7 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
item['initial_key'] = key
|
||||
if 'id' in values:
|
||||
enid = values['id']
|
||||
log.debug(u'echonest: metadata: {0} = {1}'.format(ID_KEY, enid))
|
||||
log.debug(u'echonest: metadata: {0} = {1}', ID_KEY, enid)
|
||||
item[ID_KEY] = enid
|
||||
|
||||
# Write and save.
|
||||
|
|
@ -483,8 +476,7 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
self.config.set_args(opts)
|
||||
write = config['import']['write'].get(bool)
|
||||
for item in lib.items(ui.decargs(args)):
|
||||
log.info(u'echonest: {0} - {1}'.format(item.artist,
|
||||
item.title))
|
||||
log.info(u'echonest: {0} - {1}', item.artist, item.title)
|
||||
if self.config['force'] or self.requires_update(item):
|
||||
song = self.fetch_song(item)
|
||||
if song:
|
||||
|
|
|
|||
|
|
@ -14,12 +14,12 @@
|
|||
|
||||
"""Allows beets to embed album art into file metadata."""
|
||||
import os.path
|
||||
import logging
|
||||
import imghdr
|
||||
import subprocess
|
||||
import platform
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import mediafile
|
||||
from beets import ui
|
||||
|
|
@ -122,20 +122,17 @@ def embed_item(item, imagepath, maxwidth=None, itempath=None,
|
|||
if not art:
|
||||
pass
|
||||
else:
|
||||
log.debug(u'embedart: media file contained art already {0}'.format(
|
||||
displayable_path(imagepath)
|
||||
))
|
||||
log.debug(u'embedart: media file contained art already {0}',
|
||||
displayable_path(imagepath))
|
||||
return
|
||||
if maxwidth and not as_album:
|
||||
imagepath = resize_image(imagepath, maxwidth)
|
||||
|
||||
try:
|
||||
log.debug(u'embedart: embedding {0}'.format(
|
||||
displayable_path(imagepath)
|
||||
))
|
||||
log.debug(u'embedart: embedding {0}', displayable_path(imagepath))
|
||||
item['images'] = [_mediafile_image(imagepath, maxwidth)]
|
||||
except IOError as exc:
|
||||
log.error(u'embedart: could not read image file: {0}'.format(exc))
|
||||
log.error(u'embedart: could not read image file: {0}', exc)
|
||||
else:
|
||||
# We don't want to store the image in the database.
|
||||
item.try_write(itempath)
|
||||
|
|
@ -147,19 +144,18 @@ def embed_album(album, maxwidth=None, quiet=False):
|
|||
"""
|
||||
imagepath = album.artpath
|
||||
if not imagepath:
|
||||
log.info(u'No album art present: {0} - {1}'.
|
||||
format(album.albumartist, album.album))
|
||||
log.info(u'No album art present: {0} - {1}',
|
||||
album.albumartist, album.album)
|
||||
return
|
||||
if not os.path.isfile(syspath(imagepath)):
|
||||
log.error(u'Album art not found at {0}'
|
||||
.format(displayable_path(imagepath)))
|
||||
log.error(u'Album art not found at {0}', displayable_path(imagepath))
|
||||
return
|
||||
if maxwidth:
|
||||
imagepath = resize_image(imagepath, maxwidth)
|
||||
|
||||
log.log(
|
||||
logging.DEBUG if quiet else logging.INFO,
|
||||
u'Embedding album art into {0.albumartist} - {0.album}.'.format(album),
|
||||
u'Embedding album art into {0.albumartist} - {0.album}.', album
|
||||
)
|
||||
|
||||
for item in album.items():
|
||||
|
|
@ -171,8 +167,7 @@ def embed_album(album, maxwidth=None, quiet=False):
|
|||
def resize_image(imagepath, maxwidth):
|
||||
"""Returns path to an image resized to maxwidth.
|
||||
"""
|
||||
log.info(u'Resizing album art to {0} pixels wide'
|
||||
.format(maxwidth))
|
||||
log.info(u'Resizing album art to {0} pixels wide', maxwidth)
|
||||
imagepath = ArtResizer.shared.resize(maxwidth, syspath(imagepath))
|
||||
return imagepath
|
||||
|
||||
|
|
@ -197,15 +192,15 @@ def check_art_similarity(item, imagepath, compare_threshold):
|
|||
stdout, stderr = proc.communicate()
|
||||
if proc.returncode:
|
||||
if proc.returncode != 1:
|
||||
log.warn(u'embedart: IM phashes compare failed for {0}, \
|
||||
{1}'.format(displayable_path(imagepath),
|
||||
displayable_path(art)))
|
||||
log.warn(u'embedart: IM phashes compare failed for '
|
||||
u'{0}, {1}', displayable_path(imagepath),
|
||||
displayable_path(art))
|
||||
return
|
||||
phashDiff = float(stderr)
|
||||
else:
|
||||
phashDiff = float(stdout)
|
||||
|
||||
log.info(u'embedart: compare PHASH score is {0}'.format(phashDiff))
|
||||
log.info(u'embedart: compare PHASH score is {0}', phashDiff)
|
||||
if phashDiff > compare_threshold:
|
||||
return False
|
||||
|
||||
|
|
@ -226,9 +221,8 @@ def get_art(item):
|
|||
try:
|
||||
mf = mediafile.MediaFile(syspath(item.path))
|
||||
except mediafile.UnreadableFileError as exc:
|
||||
log.error(u'Could not extract art from {0}: {1}'.format(
|
||||
displayable_path(item.path), exc
|
||||
))
|
||||
log.error(u'Could not extract art from {0}: {1}',
|
||||
displayable_path(item.path), exc)
|
||||
return
|
||||
|
||||
return mf.art
|
||||
|
|
@ -244,8 +238,8 @@ def extract(outpath, item):
|
|||
art = get_art(item)
|
||||
|
||||
if not art:
|
||||
log.error(u'No album art present in {0} - {1}.'
|
||||
.format(item.artist, item.title))
|
||||
log.error(u'No album art present in {0} - {1}.',
|
||||
item.artist, item.title)
|
||||
return
|
||||
|
||||
# Add an extension to the filename.
|
||||
|
|
@ -255,8 +249,8 @@ def extract(outpath, item):
|
|||
return
|
||||
outpath += '.' + ext
|
||||
|
||||
log.info(u'Extracting album art from: {0.artist} - {0.title} '
|
||||
u'to: {1}'.format(item, displayable_path(outpath)))
|
||||
log.info(u'Extracting album art from: {0.artist} - {0.title} to: {1}',
|
||||
item, displayable_path(outpath))
|
||||
with open(syspath(outpath), 'wb') as f:
|
||||
f.write(art)
|
||||
return outpath
|
||||
|
|
@ -267,14 +261,13 @@ def extract(outpath, item):
|
|||
def clear(lib, query):
|
||||
log.info(u'Clearing album art from items:')
|
||||
for item in lib.items(query):
|
||||
log.info(u'{0} - {1}'.format(item.artist, item.title))
|
||||
log.info(u'{0} - {1}', item.artist, item.title)
|
||||
try:
|
||||
mf = mediafile.MediaFile(syspath(item.path),
|
||||
config['id3v23'].get(bool))
|
||||
except mediafile.UnreadableFileError as exc:
|
||||
log.error(u'Could not clear art from {0}: {1}'.format(
|
||||
displayable_path(item.path), exc
|
||||
))
|
||||
log.error(u'Could not clear art from {0}: {1}',
|
||||
displayable_path(item.path), exc)
|
||||
continue
|
||||
del mf.art
|
||||
mf.save()
|
||||
|
|
|
|||
|
|
@ -15,13 +15,13 @@
|
|||
"""Fetches album art.
|
||||
"""
|
||||
from contextlib import closing
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
import requests
|
||||
|
||||
from beets import logging
|
||||
from beets import plugins
|
||||
from beets import importer
|
||||
from beets import ui
|
||||
|
|
@ -50,7 +50,7 @@ def _fetch_image(url):
|
|||
actually be an image. If so, returns a path to the downloaded image.
|
||||
Otherwise, returns None.
|
||||
"""
|
||||
log.debug(u'fetchart: downloading art: {0}'.format(url))
|
||||
log.debug(u'fetchart: downloading art: {0}', url)
|
||||
try:
|
||||
with closing(requests_session.get(url, stream=True)) as resp:
|
||||
if 'Content-Type' not in resp.headers \
|
||||
|
|
@ -63,9 +63,8 @@ def _fetch_image(url):
|
|||
as fh:
|
||||
for chunk in resp.iter_content():
|
||||
fh.write(chunk)
|
||||
log.debug(u'fetchart: downloaded art to: {0}'.format(
|
||||
util.displayable_path(fh.name)
|
||||
))
|
||||
log.debug(u'fetchart: downloaded art to: {0}',
|
||||
util.displayable_path(fh.name))
|
||||
return fh.name
|
||||
except (IOError, requests.RequestException):
|
||||
log.debug(u'fetchart: error fetching art')
|
||||
|
|
@ -117,7 +116,7 @@ def aao_art(album):
|
|||
# Get the page from albumart.org.
|
||||
try:
|
||||
resp = requests_session.get(AAO_URL, params={'asin': album.asin})
|
||||
log.debug(u'fetchart: scraped art URL: {0}'.format(resp.url))
|
||||
log.debug(u'fetchart: scraped art URL: {0}', resp.url)
|
||||
except requests.RequestException:
|
||||
log.debug(u'fetchart: error scraping art page')
|
||||
return
|
||||
|
|
@ -172,7 +171,7 @@ def itunes_art(album):
|
|||
try:
|
||||
itunes_album = itunes.search_album(search_string)[0]
|
||||
except Exception as exc:
|
||||
log.debug('fetchart: iTunes search failed: {0}'.format(exc))
|
||||
log.debug('fetchart: iTunes search failed: {0}', exc)
|
||||
return
|
||||
|
||||
if itunes_album.get_artwork()['100']:
|
||||
|
|
@ -216,16 +215,14 @@ def art_in_path(path, cover_names, cautious):
|
|||
cover_pat = r"(\b|_)({0})(\b|_)".format('|'.join(cover_names))
|
||||
for fn in images:
|
||||
if re.search(cover_pat, os.path.splitext(fn)[0], re.I):
|
||||
log.debug(u'fetchart: using well-named art file {0}'.format(
|
||||
util.displayable_path(fn)
|
||||
))
|
||||
log.debug(u'fetchart: using well-named art file {0}',
|
||||
util.displayable_path(fn))
|
||||
return os.path.join(path, fn)
|
||||
|
||||
# Fall back to any image in the folder.
|
||||
if images and not cautious:
|
||||
log.debug(u'fetchart: using fallback art file {0}'.format(
|
||||
util.displayable_path(images[0])
|
||||
))
|
||||
log.debug(u'fetchart: using fallback art file {0}',
|
||||
util.displayable_path(images[0]))
|
||||
return os.path.join(path, images[0])
|
||||
|
||||
|
||||
|
|
@ -315,8 +312,7 @@ def batch_fetch_art(lib, albums, force, maxwidth=None):
|
|||
else:
|
||||
message = ui.colorize('red', 'no art found')
|
||||
|
||||
log.info(u'{0} - {1}: {2}'.format(album.albumartist, album.album,
|
||||
message))
|
||||
log.info(u'{0} - {1}: {2}', album.albumartist, album.album, message)
|
||||
|
||||
|
||||
class FetchArtPlugin(plugins.BeetsPlugin):
|
||||
|
|
|
|||
|
|
@ -15,12 +15,12 @@
|
|||
"""Creates freedesktop.org-compliant .directory files on an album level.
|
||||
"""
|
||||
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand
|
||||
from beets.ui import decargs
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
log = logging.getLogger('beets.freedesktop')
|
||||
|
||||
|
|
|
|||
|
|
@ -14,12 +14,13 @@
|
|||
|
||||
"""Moves "featured" artists to the title from the artist field.
|
||||
"""
|
||||
import re
|
||||
|
||||
from beets import plugins
|
||||
from beets import ui
|
||||
from beets.util import displayable_path
|
||||
from beets import config
|
||||
import logging
|
||||
import re
|
||||
from beets import logging
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
||||
|
|
@ -52,8 +53,7 @@ def update_metadata(item, feat_part, drop_feat, loglevel=logging.DEBUG):
|
|||
remove it from the artist field.
|
||||
"""
|
||||
# In all cases, update the artist fields.
|
||||
log.log(loglevel, u'artist: {0} -> {1}'.format(
|
||||
item.artist, item.albumartist))
|
||||
log.log(loglevel, u'artist: {0} -> {1}', item.artist, item.albumartist)
|
||||
item.artist = item.albumartist
|
||||
if item.artist_sort:
|
||||
# Just strip the featured artist from the sort name.
|
||||
|
|
@ -63,7 +63,7 @@ def update_metadata(item, feat_part, drop_feat, loglevel=logging.DEBUG):
|
|||
# artist and if we do not drop featuring information.
|
||||
if not drop_feat and not contains_feat(item.title):
|
||||
new_title = u"{0} feat. {1}".format(item.title, feat_part)
|
||||
log.log(loglevel, u'title: {0} -> {1}'.format(item.title, new_title))
|
||||
log.log(loglevel, u'title: {0} -> {1}', item.title, new_title)
|
||||
item.title = new_title
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
"""Warns you about things you hate (or even blocks import)."""
|
||||
|
||||
import logging
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.importer import action
|
||||
from beets.library import parse_query_string
|
||||
|
|
@ -72,12 +72,11 @@ class IHatePlugin(BeetsPlugin):
|
|||
self._log.debug(u'[ihate] processing your hate')
|
||||
if self.do_i_hate_this(task, skip_queries):
|
||||
task.choice_flag = action.SKIP
|
||||
self._log.info(u'[ihate] skipped: {0}'
|
||||
.format(summary(task)))
|
||||
self._log.info(u'[ihate] skipped: {0}', summary(task))
|
||||
return
|
||||
if self.do_i_hate_this(task, warn_queries):
|
||||
self._log.info(u'[ihate] you maybe hate this: {0}'
|
||||
.format(summary(task)))
|
||||
self._log.info(u'[ihate] you maybe hate this: {0}',
|
||||
summary(task))
|
||||
else:
|
||||
self._log.debug(u'[ihate] nothing to do')
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -6,9 +6,9 @@ Reimported albums and items are skipped.
|
|||
|
||||
from __future__ import unicode_literals, absolute_import, print_function
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
from beets import logging
|
||||
from beets import config
|
||||
from beets import util
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
@ -75,8 +75,8 @@ def write_item_mtime(item, mtime):
|
|||
item's file.
|
||||
"""
|
||||
if mtime is None:
|
||||
log.warn(u"No mtime to be preserved for item '{0}'"
|
||||
.format(util.displayable_path(item.path)))
|
||||
log.warn(u"No mtime to be preserved for item '{0}'",
|
||||
util.displayable_path(item.path))
|
||||
return
|
||||
|
||||
# The file's mtime on disk must be in sync with the item's mtime
|
||||
|
|
@ -97,17 +97,17 @@ def record_import_mtime(item, source, destination):
|
|||
"""
|
||||
mtime = os.stat(util.syspath(source)).st_mtime
|
||||
item_mtime[destination] = mtime
|
||||
log.debug(u"Recorded mtime {0} for item '{1}' imported from '{2}'".format(
|
||||
mtime, util.displayable_path(destination),
|
||||
util.displayable_path(source)))
|
||||
log.debug(u"Recorded mtime {0} for item '{1}' imported from '{2}'",
|
||||
mtime, util.displayable_path(destination),
|
||||
util.displayable_path(source))
|
||||
|
||||
|
||||
@ImportAddedPlugin.listen('album_imported')
|
||||
def update_album_times(lib, album):
|
||||
if reimported_album(album):
|
||||
log.debug(u"Album '{0}' is reimported, skipping import of added dates"
|
||||
u" for the album and its items."
|
||||
.format(util.displayable_path(album.path)))
|
||||
u" for the album and its items.",
|
||||
util.displayable_path(album.path))
|
||||
return
|
||||
|
||||
album_mtimes = []
|
||||
|
|
@ -120,7 +120,7 @@ def update_album_times(lib, album):
|
|||
item.store()
|
||||
album.added = min(album_mtimes)
|
||||
log.debug(u"Import of album '{0}', selected album.added={1} from item"
|
||||
u" file mtimes.".format(album.album, album.added))
|
||||
u" file mtimes.", album.album, album.added)
|
||||
album.store()
|
||||
|
||||
|
||||
|
|
@ -128,13 +128,13 @@ def update_album_times(lib, album):
|
|||
def update_item_times(lib, item):
|
||||
if reimported_item(item):
|
||||
log.debug(u"Item '{0}' is reimported, skipping import of added "
|
||||
u"date.".format(util.displayable_path(item.path)))
|
||||
u"date.", util.displayable_path(item.path))
|
||||
return
|
||||
mtime = item_mtime.pop(item.path, None)
|
||||
if mtime:
|
||||
item.added = mtime
|
||||
if config['importadded']['preserve_mtimes'].get(bool):
|
||||
write_item_mtime(item, mtime)
|
||||
log.debug(u"Import of item '{0}', selected item.added={1}"
|
||||
.format(util.displayable_path(item.path), item.added))
|
||||
log.debug(u"Import of item '{0}', selected item.added={1}",
|
||||
util.displayable_path(item.path), item.added)
|
||||
item.store()
|
||||
|
|
|
|||
|
|
@ -19,11 +19,10 @@ one wants to manually add music to a player by its path.
|
|||
import datetime
|
||||
import os
|
||||
import re
|
||||
import logging
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.util import normpath, syspath, bytestring_path
|
||||
from beets import config
|
||||
from beets import config, logging
|
||||
|
||||
M3U_DEFAULT_NAME = 'imported.m3u'
|
||||
log = logging.getLogger('beets')
|
||||
|
|
@ -132,7 +131,7 @@ def _record_items(lib, basename, items):
|
|||
if 'echo' in formats:
|
||||
log.info("Location of imported music:")
|
||||
for path in paths:
|
||||
log.info(" " + path)
|
||||
log.info(" {0}", path)
|
||||
|
||||
|
||||
@ImportFeedsPlugin.listen('library_opened')
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@
|
|||
"""
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
from beets import mediafile
|
||||
|
|
@ -52,7 +52,7 @@ def run(lib, opts, args):
|
|||
try:
|
||||
data = data_emitter()
|
||||
except mediafile.UnreadableFileError as ex:
|
||||
log.error(u'cannot read file: {0}'.format(ex.message))
|
||||
log.error(u'cannot read file: {0}', ex.message)
|
||||
continue
|
||||
|
||||
if opts.summarize:
|
||||
|
|
|
|||
|
|
@ -14,12 +14,11 @@
|
|||
|
||||
"""Allows inline path template customization code in the config file.
|
||||
"""
|
||||
import logging
|
||||
import traceback
|
||||
import itertools
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import config
|
||||
from beets import config, logging
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
||||
|
|
@ -64,9 +63,8 @@ def compile_inline(python_code, album):
|
|||
try:
|
||||
func = _compile_func(python_code)
|
||||
except SyntaxError:
|
||||
log.error(u'syntax error in inline field definition:\n{0}'.format(
|
||||
traceback.format_exc()
|
||||
))
|
||||
log.error(u'syntax error in inline field definition:\n{0}',
|
||||
traceback.format_exc())
|
||||
return
|
||||
else:
|
||||
is_expr = False
|
||||
|
|
@ -113,14 +111,14 @@ class InlinePlugin(BeetsPlugin):
|
|||
# Item fields.
|
||||
for key, view in itertools.chain(config['item_fields'].items(),
|
||||
config['pathfields'].items()):
|
||||
log.debug(u'inline: adding item field {0}'.format(key))
|
||||
log.debug(u'inline: adding item field {0}', key)
|
||||
func = compile_inline(view.get(unicode), False)
|
||||
if func is not None:
|
||||
self.template_fields[key] = func
|
||||
|
||||
# Album fields.
|
||||
for key, view in config['album_fields'].items():
|
||||
log.debug(u'inline: adding album field {0}'.format(key))
|
||||
log.debug(u'inline: adding album field {0}', key)
|
||||
func = compile_inline(view.get(unicode), True)
|
||||
if func is not None:
|
||||
self.album_template_fields[key] = func
|
||||
|
|
|
|||
|
|
@ -15,9 +15,9 @@
|
|||
"""Uses the `KeyFinder` program to add the `initial_key` field.
|
||||
"""
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from beets import logging
|
||||
from beets import ui
|
||||
from beets import util
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
@ -62,11 +62,11 @@ class KeyFinderPlugin(BeetsPlugin):
|
|||
try:
|
||||
key = util.command_output([bin, '-f', item.path])
|
||||
except (subprocess.CalledProcessError, OSError) as exc:
|
||||
log.error(u'KeyFinder execution failed: {0}'.format(exc))
|
||||
log.error(u'KeyFinder execution failed: {0}', exc)
|
||||
continue
|
||||
|
||||
item['initial_key'] = key
|
||||
log.debug(u'added computed initial key {0} for {1}'
|
||||
.format(key, util.displayable_path(item.path)))
|
||||
log.debug(u'added computed initial key {0} for {1}',
|
||||
key, util.displayable_path(item.path))
|
||||
item.try_write()
|
||||
item.store()
|
||||
|
|
|
|||
|
|
@ -20,11 +20,11 @@ and has been edited to remove some questionable entries.
|
|||
The scraper script used is available here:
|
||||
https://gist.github.com/1241307
|
||||
"""
|
||||
import logging
|
||||
import pylast
|
||||
import os
|
||||
import yaml
|
||||
|
||||
from beets import logging
|
||||
from beets import plugins
|
||||
from beets import ui
|
||||
from beets.util import normpath, plurality
|
||||
|
|
@ -71,7 +71,7 @@ def _tags_for(obj, min_weight=None):
|
|||
else:
|
||||
res = obj.get_top_tags()
|
||||
except PYLAST_EXCEPTIONS as exc:
|
||||
log.debug(u'last.fm error: {0}'.format(exc))
|
||||
log.debug(u'last.fm error: {0}', exc)
|
||||
return []
|
||||
|
||||
# Filter by weight (optionally).
|
||||
|
|
@ -371,9 +371,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
|
||||
for album in lib.albums(ui.decargs(args)):
|
||||
album.genre, src = self._get_genre(album)
|
||||
log.info(u'genre for album {0} - {1} ({2}): {3}'.format(
|
||||
album.albumartist, album.album, src, album.genre
|
||||
))
|
||||
log.info(u'genre for album {0} - {1} ({2}): {3}',
|
||||
album.albumartist, album.album, src, album.genre)
|
||||
album.store()
|
||||
|
||||
for item in album.items():
|
||||
|
|
@ -382,9 +381,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
if 'track' in self.sources:
|
||||
item.genre, src = self._get_genre(item)
|
||||
item.store()
|
||||
log.info(u'genre for track {0} - {1} ({2}): {3}'
|
||||
.format(item.artist, item.title, src,
|
||||
item.genre))
|
||||
log.info(u'genre for track {0} - {1} ({2}): {3}',
|
||||
item.artist, item.title, src, item.genre)
|
||||
|
||||
if write:
|
||||
item.try_write()
|
||||
|
|
@ -397,20 +395,20 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
if task.is_album:
|
||||
album = task.album
|
||||
album.genre, src = self._get_genre(album)
|
||||
log.debug(u'added last.fm album genre ({0}): {1}'.format(
|
||||
src, album.genre))
|
||||
log.debug(u'added last.fm album genre ({0}): {1}',
|
||||
src, album.genre)
|
||||
album.store()
|
||||
|
||||
if 'track' in self.sources:
|
||||
for item in album.items():
|
||||
item.genre, src = self._get_genre(item)
|
||||
log.debug(u'added last.fm item genre ({0}): {1}'.format(
|
||||
src, item.genre))
|
||||
log.debug(u'added last.fm item genre ({0}): {1}',
|
||||
src, item.genre)
|
||||
item.store()
|
||||
|
||||
else:
|
||||
item = task.item
|
||||
item.genre, src = self._get_genre(item)
|
||||
log.debug(u'added last.fm item genre ({0}): {1}'.format(
|
||||
src, item.genre))
|
||||
log.debug(u'added last.fm item genre ({0}): {1}',
|
||||
src, item.genre)
|
||||
item.store()
|
||||
|
|
|
|||
|
|
@ -12,12 +12,12 @@
|
|||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
import logging
|
||||
import requests
|
||||
from beets import ui
|
||||
from beets import dbcore
|
||||
from beets import config
|
||||
from beets import plugins
|
||||
from beets import logging
|
||||
from beets.dbcore import types
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
|
@ -56,7 +56,7 @@ def import_lastfm(lib):
|
|||
if not user:
|
||||
raise ui.UserError('You must specify a user name for lastimport')
|
||||
|
||||
log.info('Fetching last.fm library for @{0}'.format(user))
|
||||
log.info('Fetching last.fm library for @{0}', user)
|
||||
|
||||
page_total = 1
|
||||
page_current = 0
|
||||
|
|
@ -65,10 +65,9 @@ def import_lastfm(lib):
|
|||
retry_limit = config['lastimport']['retry_limit'].get(int)
|
||||
# Iterate through a yet to be known page total count
|
||||
while page_current < page_total:
|
||||
log.info('lastimport: Querying page #{0}{1}...'.format(
|
||||
page_current + 1,
|
||||
'/' + str(page_total) if page_total > 1 else ''
|
||||
))
|
||||
log.info('lastimport: Querying page #{0}{1}...',
|
||||
page_current + 1,
|
||||
'/{}'.format(page_total) if page_total > 1 else '')
|
||||
|
||||
for retry in range(0, retry_limit):
|
||||
page = fetch_tracks(user, page_current + 1, per_page)
|
||||
|
|
@ -84,27 +83,22 @@ def import_lastfm(lib):
|
|||
unknown_total += unknown
|
||||
break
|
||||
else:
|
||||
log.error('lastimport: ERROR: unable to read page #{0}'.format(
|
||||
page_current + 1
|
||||
))
|
||||
log.error('lastimport: ERROR: unable to read page #{0}',
|
||||
page_current + 1)
|
||||
if retry < retry_limit:
|
||||
log.info(
|
||||
'lastimport: Retrying page #{0}... ({1}/{2} retry)'
|
||||
.format(page_current + 1, retry + 1, retry_limit)
|
||||
'lastimport: Retrying page #{0}... ({1}/{2} retry)',
|
||||
page_current + 1, retry + 1, retry_limit
|
||||
)
|
||||
else:
|
||||
log.error(
|
||||
'lastimport: FAIL: unable to fetch page #{0}, '
|
||||
'tried {1} times'.format(page_current, retry + 1)
|
||||
)
|
||||
log.error('lastimport: FAIL: unable to fetch page #{0}, ',
|
||||
'tried {1} times', page_current, retry + 1)
|
||||
page_current += 1
|
||||
|
||||
log.info('lastimport: ... done!')
|
||||
log.info('lastimport: finished processing {0} song pages'.format(
|
||||
page_total
|
||||
))
|
||||
log.info('lastimport: {0} unknown play-counts'.format(unknown_total))
|
||||
log.info('lastimport: {0} play-counts imported'.format(found_total))
|
||||
log.info('lastimport: finished processing {0} song pages', page_total)
|
||||
log.info('lastimport: {0} unknown play-counts', unknown_total)
|
||||
log.info('lastimport: {0} play-counts imported', found_total)
|
||||
|
||||
|
||||
def fetch_tracks(user, page, limit):
|
||||
|
|
@ -122,10 +116,8 @@ def process_tracks(lib, tracks):
|
|||
total = len(tracks)
|
||||
total_found = 0
|
||||
total_fails = 0
|
||||
log.info(
|
||||
'lastimport: Received {0} tracks in this page, processing...'
|
||||
.format(total)
|
||||
)
|
||||
log.info('lastimport: Received {0} tracks in this page, processing...',
|
||||
total)
|
||||
|
||||
for num in xrange(0, total):
|
||||
song = ''
|
||||
|
|
@ -136,8 +128,7 @@ def process_tracks(lib, tracks):
|
|||
if 'album' in tracks[num]:
|
||||
album = tracks[num]['album'].get('name', '').strip()
|
||||
|
||||
log.debug(u'lastimport: query: {0} - {1} ({2})'
|
||||
.format(artist, title, album))
|
||||
log.debug(u'lastimport: query: {0} - {1} ({2})', artist, title, album)
|
||||
|
||||
# First try to query by musicbrainz's trackid
|
||||
if trackid:
|
||||
|
|
@ -148,7 +139,7 @@ def process_tracks(lib, tracks):
|
|||
# Otherwise try artist/title/album
|
||||
if not song:
|
||||
log.debug(u'lastimport: no match for mb_trackid {0}, trying by '
|
||||
u'artist/title/album'.format(trackid))
|
||||
u'artist/title/album', trackid)
|
||||
query = dbcore.AndQuery([
|
||||
dbcore.query.SubstringQuery('artist', artist),
|
||||
dbcore.query.SubstringQuery('title', title),
|
||||
|
|
@ -178,26 +169,19 @@ def process_tracks(lib, tracks):
|
|||
if song:
|
||||
count = int(song.get('play_count', 0))
|
||||
new_count = int(tracks[num]['playcount'])
|
||||
log.debug(
|
||||
u'lastimport: match: {0} - {1} ({2}) '
|
||||
u'updating: play_count {3} => {4}'.format(
|
||||
song.artist, song.title, song.album, count, new_count
|
||||
)
|
||||
)
|
||||
log.debug(u'lastimport: match: {0} - {1} ({2}) '
|
||||
u'updating: play_count {3} => {4}',
|
||||
song.artist, song.title, song.album, count, new_count)
|
||||
song['play_count'] = new_count
|
||||
song.store()
|
||||
total_found += 1
|
||||
else:
|
||||
total_fails += 1
|
||||
log.info(
|
||||
u'lastimport: - No match: {0} - {1} ({2})'
|
||||
.format(artist, title, album)
|
||||
)
|
||||
log.info(u'lastimport: - No match: {0} - {1} ({2})',
|
||||
artist, title, album)
|
||||
|
||||
if total_fails > 0:
|
||||
log.info(
|
||||
'lastimport: Acquired {0}/{1} play-counts ({2} unknown)'
|
||||
.format(total_found, total, total_fails)
|
||||
)
|
||||
log.info('lastimport: Acquired {0}/{1} play-counts ({2} unknown)',
|
||||
total_found, total, total_fails)
|
||||
|
||||
return total_found, total_fails
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
from __future__ import print_function
|
||||
|
||||
import re
|
||||
import logging
|
||||
import requests
|
||||
import json
|
||||
import unicodedata
|
||||
|
|
@ -26,6 +25,7 @@ import difflib
|
|||
import itertools
|
||||
from HTMLParser import HTMLParseError
|
||||
|
||||
from beets import logging
|
||||
from beets import plugins
|
||||
from beets import config, ui
|
||||
|
||||
|
|
@ -63,12 +63,12 @@ def fetch_url(url):
|
|||
try:
|
||||
r = requests.get(url, verify=False)
|
||||
except requests.RequestException as exc:
|
||||
log.debug(u'lyrics request failed: {0}'.format(exc))
|
||||
log.debug(u'lyrics request failed: {0}', exc)
|
||||
return
|
||||
if r.status_code == requests.codes.ok:
|
||||
return r.text
|
||||
else:
|
||||
log.debug(u'failed to fetch: {0} ({1})'.format(url, r.status_code))
|
||||
log.debug(u'failed to fetch: {0} ({1})', url, r.status_code)
|
||||
|
||||
|
||||
def unescape(text):
|
||||
|
|
@ -272,7 +272,7 @@ def slugify(text):
|
|||
text = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore')
|
||||
text = unicode(re.sub('[-\s]+', ' ', text))
|
||||
except UnicodeDecodeError:
|
||||
log.exception(u"Failing to normalize '{0}'".format(text))
|
||||
log.exception(u"Failing to normalize '{0}'", text)
|
||||
return text
|
||||
|
||||
|
||||
|
|
@ -323,7 +323,7 @@ def is_lyrics(text, artist=None):
|
|||
badTriggersOcc = []
|
||||
nbLines = text.count('\n')
|
||||
if nbLines <= 1:
|
||||
log.debug(u"Ignoring too short lyrics '{0}'".format(text))
|
||||
log.debug(u"Ignoring too short lyrics '{0}'", text)
|
||||
return False
|
||||
elif nbLines < 5:
|
||||
badTriggersOcc.append('too_short')
|
||||
|
|
@ -341,7 +341,7 @@ def is_lyrics(text, artist=None):
|
|||
text, re.I))
|
||||
|
||||
if badTriggersOcc:
|
||||
log.debug(u'Bad triggers detected: {0}'.format(badTriggersOcc))
|
||||
log.debug(u'Bad triggers detected: {0}', badTriggersOcc)
|
||||
return len(badTriggersOcc) < 2
|
||||
|
||||
|
||||
|
|
@ -409,7 +409,7 @@ def fetch_google(artist, title):
|
|||
data = json.load(data)
|
||||
if 'error' in data:
|
||||
reason = data['error']['errors'][0]['reason']
|
||||
log.debug(u'google lyrics backend error: {0}'.format(reason))
|
||||
log.debug(u'google lyrics backend error: {0}', reason)
|
||||
return
|
||||
|
||||
if 'items' in data.keys():
|
||||
|
|
@ -424,7 +424,7 @@ def fetch_google(artist, title):
|
|||
continue
|
||||
|
||||
if is_lyrics(lyrics, artist):
|
||||
log.debug(u'got lyrics from {0}'.format(item['displayLink']))
|
||||
log.debug(u'got lyrics from {0}', item['displayLink'])
|
||||
return lyrics
|
||||
|
||||
|
||||
|
|
@ -502,8 +502,8 @@ class LyricsPlugin(plugins.BeetsPlugin):
|
|||
"""
|
||||
# Skip if the item already has lyrics.
|
||||
if not force and item.lyrics:
|
||||
log.log(loglevel, u'lyrics already present: {0} - {1}'
|
||||
.format(item.artist, item.title))
|
||||
log.log(loglevel, u'lyrics already present: {0} - {1}',
|
||||
item.artist, item.title)
|
||||
return
|
||||
|
||||
lyrics = None
|
||||
|
|
@ -515,11 +515,11 @@ class LyricsPlugin(plugins.BeetsPlugin):
|
|||
lyrics = u"\n\n---\n\n".join([l for l in lyrics if l])
|
||||
|
||||
if lyrics:
|
||||
log.log(loglevel, u'fetched lyrics: {0} - {1}'
|
||||
.format(item.artist, item.title))
|
||||
log.log(loglevel, u'fetched lyrics: {0} - {1}',
|
||||
item.artist, item.title)
|
||||
else:
|
||||
log.log(loglevel, u'lyrics not found: {0} - {1}'
|
||||
.format(item.artist, item.title))
|
||||
log.log(loglevel, u'lyrics not found: {0} - {1}',
|
||||
item.artist, item.title)
|
||||
fallback = self.config['fallback'].get()
|
||||
if fallback:
|
||||
lyrics = fallback
|
||||
|
|
@ -539,6 +539,5 @@ class LyricsPlugin(plugins.BeetsPlugin):
|
|||
for backend in self.backends:
|
||||
lyrics = backend(artist, title)
|
||||
if lyrics:
|
||||
log.debug(u'got lyrics from backend: {0}'
|
||||
.format(backend.__name__))
|
||||
log.debug(u'got lyrics from backend: {0}', backend.__name__)
|
||||
return _scrape_strip_cruft(lyrics, True)
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@ from __future__ import print_function
|
|||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand
|
||||
from beets import logging
|
||||
from beets import ui
|
||||
from beets import config
|
||||
import musicbrainzngs
|
||||
|
||||
import re
|
||||
import logging
|
||||
|
||||
SUBMISSION_CHUNK_SIZE = 200
|
||||
UUID_REGEX = r'^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12}$'
|
||||
|
|
@ -79,7 +79,7 @@ def update_album_list(album_list):
|
|||
if re.match(UUID_REGEX, aid):
|
||||
album_ids.append(aid)
|
||||
else:
|
||||
log.info(u'skipping invalid MBID: {0}'.format(aid))
|
||||
log.info(u'skipping invalid MBID: {0}', aid)
|
||||
|
||||
# Submit to MusicBrainz.
|
||||
print('Updating MusicBrainz collection {0}...'.format(collection_id))
|
||||
|
|
|
|||
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
"""Update library's tags using MusicBrainz.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import autotag, library, ui, util
|
||||
from beets import autotag, library, ui, util, logging
|
||||
from beets.autotag import hooks
|
||||
from beets import config
|
||||
from collections import defaultdict
|
||||
|
|
@ -31,14 +29,13 @@ def mbsync_singletons(lib, query, move, pretend, write):
|
|||
"""
|
||||
for item in lib.items(query + ['singleton:true']):
|
||||
if not item.mb_trackid:
|
||||
log.info(u'Skipping singleton {0}: has no mb_trackid'
|
||||
.format(item.title))
|
||||
log.info(u'Skipping singleton {0}: has no mb_trackid', item.title)
|
||||
continue
|
||||
|
||||
# Get the MusicBrainz recording info.
|
||||
track_info = hooks.track_for_mbid(item.mb_trackid)
|
||||
if not track_info:
|
||||
log.info(u'Recording ID not found: {0}'.format(item.mb_trackid))
|
||||
log.info(u'Recording ID not found: {0}', item.mb_trackid)
|
||||
continue
|
||||
|
||||
# Apply.
|
||||
|
|
@ -54,7 +51,7 @@ def mbsync_albums(lib, query, move, pretend, write):
|
|||
# Process matching albums.
|
||||
for a in lib.albums(query):
|
||||
if not a.mb_albumid:
|
||||
log.info(u'Skipping album {0}: has no mb_albumid'.format(a.id))
|
||||
log.info(u'Skipping album {0}: has no mb_albumid', a.id)
|
||||
continue
|
||||
|
||||
items = list(a.items())
|
||||
|
|
@ -62,7 +59,7 @@ def mbsync_albums(lib, query, move, pretend, write):
|
|||
# Get the MusicBrainz album information.
|
||||
album_info = hooks.album_for_mbid(a.mb_albumid)
|
||||
if not album_info:
|
||||
log.info(u'Release ID not found: {0}'.format(a.mb_albumid))
|
||||
log.info(u'Release ID not found: {0}', a.mb_albumid)
|
||||
continue
|
||||
|
||||
# Map recording MBIDs to their information. Recordings can appear
|
||||
|
|
@ -109,7 +106,7 @@ def mbsync_albums(lib, query, move, pretend, write):
|
|||
|
||||
# Move album art (and any inconsistent items).
|
||||
if move and lib.directory in util.ancestry(items[0].path):
|
||||
log.debug(u'moving album {0}'.format(a.id))
|
||||
log.debug(u'moving album {0}', a.id)
|
||||
a.move()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,8 +14,7 @@
|
|||
|
||||
"""List missing tracks.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from beets import logging
|
||||
from beets.autotag import hooks
|
||||
from beets.library import Item
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
|
@ -43,10 +42,8 @@ def _missing(album):
|
|||
for track_info in getattr(album_info, 'tracks', []):
|
||||
if track_info.track_id not in item_mbids:
|
||||
item = _item(track_info, album_info, album.id)
|
||||
log.debug(u'{0}: track {1} in album {2}'
|
||||
.format(PLUGIN,
|
||||
track_info.track_id,
|
||||
album_info.album_id))
|
||||
log.debug(u'{0}: track {1} in album {2}',
|
||||
PLUGIN, track_info.track_id, album_info.album_id)
|
||||
yield item
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -13,13 +13,13 @@
|
|||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
import logging
|
||||
import mpd
|
||||
import socket
|
||||
import select
|
||||
import time
|
||||
import os
|
||||
|
||||
from beets import logging
|
||||
from beets import ui
|
||||
from beets import config
|
||||
from beets import plugins
|
||||
|
|
@ -71,7 +71,7 @@ class MPDClientWrapper(object):
|
|||
if host[0] in ['/', '~']:
|
||||
host = os.path.expanduser(host)
|
||||
|
||||
log.info(u'mpdstats: connecting to {0}:{1}'.format(host, port))
|
||||
log.info(u'mpdstats: connecting to {0}:{1}', host, port)
|
||||
try:
|
||||
self.client.connect(host, port)
|
||||
except socket.error as e:
|
||||
|
|
@ -99,7 +99,7 @@ class MPDClientWrapper(object):
|
|||
try:
|
||||
return getattr(self.client, command)()
|
||||
except (select.error, mpd.ConnectionError) as err:
|
||||
log.error(u'mpdstats: {0}'.format(err))
|
||||
log.error(u'mpdstats: {0}', err)
|
||||
|
||||
if retries <= 0:
|
||||
# if we exited without breaking, we couldn't reconnect in time :(
|
||||
|
|
@ -171,9 +171,7 @@ class MPDStats(object):
|
|||
if item:
|
||||
return item
|
||||
else:
|
||||
log.info(u'mpdstats: item not found: {0}'.format(
|
||||
displayable_path(path)
|
||||
))
|
||||
log.info(u'mpdstats: item not found: {0}', displayable_path(path))
|
||||
|
||||
@staticmethod
|
||||
def update_item(item, attribute, value=None, increment=None):
|
||||
|
|
@ -192,11 +190,10 @@ class MPDStats(object):
|
|||
item[attribute] = value
|
||||
item.store()
|
||||
|
||||
log.debug(u'mpdstats: updated: {0} = {1} [{2}]'.format(
|
||||
attribute,
|
||||
item[attribute],
|
||||
displayable_path(item.path),
|
||||
))
|
||||
log.debug(u'mpdstats: updated: {0} = {1} [{2}]',
|
||||
attribute,
|
||||
item[attribute],
|
||||
displayable_path(item.path))
|
||||
|
||||
def update_rating(self, item, skipped):
|
||||
"""Update the rating for a beets item.
|
||||
|
|
@ -232,17 +229,13 @@ class MPDStats(object):
|
|||
"""Updates the play count of a song.
|
||||
"""
|
||||
self.update_item(song['beets_item'], 'play_count', increment=1)
|
||||
log.info(u'mpdstats: played {0}'.format(
|
||||
displayable_path(song['path'])
|
||||
))
|
||||
log.info(u'mpdstats: played {0}', displayable_path(song['path']))
|
||||
|
||||
def handle_skipped(self, song):
|
||||
"""Updates the skip count of a song.
|
||||
"""
|
||||
self.update_item(song['beets_item'], 'skip_count', increment=1)
|
||||
log.info(u'mpdstats: skipped {0}'.format(
|
||||
displayable_path(song['path'])
|
||||
))
|
||||
log.info(u'mpdstats: skipped {0}', displayable_path(song['path']))
|
||||
|
||||
def on_stop(self, status):
|
||||
log.info(u'mpdstats: stop')
|
||||
|
|
@ -264,9 +257,7 @@ class MPDStats(object):
|
|||
return
|
||||
|
||||
if is_url(path):
|
||||
log.info(u'mpdstats: playing stream {0}'.format(
|
||||
displayable_path(path)
|
||||
))
|
||||
log.info(u'mpdstats: playing stream {0}', displayable_path(path))
|
||||
return
|
||||
|
||||
played, duration = map(int, status['time'].split(':', 1))
|
||||
|
|
@ -275,9 +266,7 @@ class MPDStats(object):
|
|||
if self.now_playing and self.now_playing['path'] != path:
|
||||
self.handle_song_change(self.now_playing)
|
||||
|
||||
log.info(u'mpdstats: playing {0}'.format(
|
||||
displayable_path(path)
|
||||
))
|
||||
log.info(u'mpdstats: playing {0}', displayable_path(path))
|
||||
|
||||
self.now_playing = {
|
||||
'started': time.time(),
|
||||
|
|
@ -302,8 +291,7 @@ class MPDStats(object):
|
|||
if handler:
|
||||
handler(status)
|
||||
else:
|
||||
log.debug(u'mpdstats: unhandled status "{0}"'.
|
||||
format(status))
|
||||
log.debug(u'mpdstats: unhandled status "{0}"', status)
|
||||
|
||||
events = self.mpd.events()
|
||||
|
||||
|
|
|
|||
|
|
@ -16,12 +16,12 @@
|
|||
"""
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand
|
||||
from beets import logging
|
||||
from beets import config
|
||||
from beets import ui
|
||||
from beets import util
|
||||
from os.path import relpath
|
||||
import platform
|
||||
import logging
|
||||
import shlex
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
|
|
@ -101,10 +101,9 @@ def play_music(lib, opts, args):
|
|||
# Invoke the command and log the output.
|
||||
output = util.command_output(command)
|
||||
if output:
|
||||
log.debug(u'Output of {0}: {1}'.format(
|
||||
util.displayable_path(command[0]),
|
||||
output.decode('utf8', 'ignore'),
|
||||
))
|
||||
log.debug(u'Output of {0}: {1}',
|
||||
util.displayable_path(command[0]),
|
||||
output.decode('utf8', 'ignore'))
|
||||
else:
|
||||
log.debug(u'play: no output')
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@
|
|||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
import collections
|
||||
|
|
@ -20,6 +19,7 @@ import itertools
|
|||
import sys
|
||||
import warnings
|
||||
|
||||
from beets import logging
|
||||
from beets import ui
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.util import syspath, command_output, displayable_path
|
||||
|
|
@ -180,9 +180,9 @@ class CommandBackend(Backend):
|
|||
cmd = cmd + ['-d', str(self.gain_offset)]
|
||||
cmd = cmd + [syspath(i.path) for i in items]
|
||||
|
||||
log.debug(u'replaygain: analyzing {0} files'.format(len(items)))
|
||||
log.debug(u"replaygain: executing {0}"
|
||||
.format(" ".join(map(displayable_path, cmd))))
|
||||
log.debug(u'replaygain: analyzing {0} files', len(items))
|
||||
log.debug(u"replaygain: executing {0}",
|
||||
" ".join(map(displayable_path, cmd)))
|
||||
output = call(cmd)
|
||||
log.debug(u'replaygain: analysis finished')
|
||||
results = self.parse_tool_output(output,
|
||||
|
|
@ -199,7 +199,7 @@ class CommandBackend(Backend):
|
|||
for line in text.split('\n')[1:num_lines + 1]:
|
||||
parts = line.split('\t')
|
||||
if len(parts) != 6 or parts[0] == 'File':
|
||||
log.debug(u'replaygain: bad tool output: {0}'.format(text))
|
||||
log.debug(u'replaygain: bad tool output: {0}', text)
|
||||
raise ReplayGainError('mp3gain failed')
|
||||
d = {
|
||||
'file': parts[0],
|
||||
|
|
@ -548,14 +548,8 @@ class AudioToolsBackend(Backend):
|
|||
# be obtained from an audiofile instance.
|
||||
rg_track_gain, rg_track_peak = rg.title_gain(audiofile.to_pcm())
|
||||
|
||||
log.debug(
|
||||
u'ReplayGain for track {0} - {1}: {2:.2f}, {3:.2f}'.format(
|
||||
item.artist,
|
||||
item.title,
|
||||
rg_track_gain,
|
||||
rg_track_peak
|
||||
)
|
||||
)
|
||||
log.debug(u'ReplayGain for track {0} - {1}: {2:.2f}, {3:.2f}',
|
||||
item.artist, item.title, rg_track_gain, rg_track_peak)
|
||||
return Gain(gain=rg_track_gain, peak=rg_track_peak)
|
||||
|
||||
def compute_album_gain(self, album):
|
||||
|
|
@ -563,12 +557,7 @@ class AudioToolsBackend(Backend):
|
|||
|
||||
:rtype: :class:`AlbumGain`
|
||||
"""
|
||||
log.debug(
|
||||
u'Analysing album {0} - {1}'.format(
|
||||
album.albumartist,
|
||||
album.album
|
||||
)
|
||||
)
|
||||
log.debug(u'Analysing album {0} - {1}', album.albumartist, album.album)
|
||||
|
||||
# The first item is taken and opened to get the sample rate to
|
||||
# initialize the replaygain object. The object is used for all the
|
||||
|
|
@ -584,26 +573,14 @@ class AudioToolsBackend(Backend):
|
|||
track_gains.append(
|
||||
Gain(gain=rg_track_gain, peak=rg_track_peak)
|
||||
)
|
||||
log.debug(
|
||||
u'ReplayGain for track {0} - {1}: {2:.2f}, {3:.2f}'.format(
|
||||
item.artist,
|
||||
item.title,
|
||||
rg_track_gain,
|
||||
rg_track_peak
|
||||
)
|
||||
)
|
||||
log.debug(u'ReplayGain for track {0} - {1}: {2:.2f}, {3:.2f}',
|
||||
item.artist, item.title, rg_track_gain, rg_track_peak)
|
||||
|
||||
# After getting the values for all tracks, it's possible to get the
|
||||
# album values.
|
||||
rg_album_gain, rg_album_peak = rg.album_gain()
|
||||
log.debug(
|
||||
u'ReplayGain for Album {0} - {1}: {2:.2f}, {3:.2f}'.format(
|
||||
album.albumartist,
|
||||
album.album,
|
||||
rg_album_gain,
|
||||
rg_album_peak
|
||||
)
|
||||
)
|
||||
log.debug(u'ReplayGain for Album {0} - {1}: {2:.2f}, {3:.2f}',
|
||||
album.albumartist, album.album, rg_album_gain, rg_album_peak)
|
||||
|
||||
return AlbumGain(
|
||||
Gain(gain=rg_album_gain, peak=rg_album_peak),
|
||||
|
|
@ -674,19 +651,16 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
item.rg_track_peak = track_gain.peak
|
||||
item.store()
|
||||
|
||||
log.debug(u'replaygain: applied track gain {0}, peak {1}'.format(
|
||||
item.rg_track_gain,
|
||||
item.rg_track_peak
|
||||
))
|
||||
log.debug(u'replaygain: applied track gain {0}, peak {1}',
|
||||
item.rg_track_gain, item.rg_track_peak)
|
||||
|
||||
def store_album_gain(self, album, album_gain):
|
||||
album.rg_album_gain = album_gain.gain
|
||||
album.rg_album_peak = album_gain.peak
|
||||
album.store()
|
||||
|
||||
log.debug(u'replaygain: applied album gain {0}, peak {1}'.format(
|
||||
album.rg_album_gain,
|
||||
album.rg_album_peak))
|
||||
log.debug(u'replaygain: applied album gain {0}, peak {1}',
|
||||
album.rg_album_gain, album.rg_album_peak)
|
||||
|
||||
def handle_album(self, album, write):
|
||||
"""Compute album and track replay gain store it in all of the
|
||||
|
|
@ -697,12 +671,11 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
items, nothing is done.
|
||||
"""
|
||||
if not self.album_requires_gain(album):
|
||||
log.info(u'Skipping album {0} - {1}'.format(album.albumartist,
|
||||
album.album))
|
||||
log.info(u'Skipping album {0} - {1}',
|
||||
album.albumartist, album.album)
|
||||
return
|
||||
|
||||
log.info(u'analyzing {0} - {1}'.format(album.albumartist,
|
||||
album.album))
|
||||
log.info(u'analyzing {0} - {1}', album.albumartist, album.album)
|
||||
|
||||
try:
|
||||
album_gain = self.backend_instance.compute_album_gain(album)
|
||||
|
|
@ -721,7 +694,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
if write:
|
||||
item.try_write()
|
||||
except ReplayGainError as e:
|
||||
log.info(u"ReplayGain error: {0}".format(e))
|
||||
log.info(u"ReplayGain error: {0}", e)
|
||||
except FatalReplayGainError as e:
|
||||
raise ui.UserError(
|
||||
u"Fatal replay gain error: {0}".format(e)
|
||||
|
|
@ -735,12 +708,10 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
in the item, nothing is done.
|
||||
"""
|
||||
if not self.track_requires_gain(item):
|
||||
log.info(u'Skipping track {0} - {1}'
|
||||
.format(item.artist, item.title))
|
||||
log.info(u'Skipping track {0} - {1}', item.artist, item.title)
|
||||
return
|
||||
|
||||
log.info(u'analyzing {0} - {1}'
|
||||
.format(item.artist, item.title))
|
||||
log.info(u'analyzing {0} - {1}', item.artist, item.title)
|
||||
|
||||
try:
|
||||
track_gains = self.backend_instance.compute_track_gain([item])
|
||||
|
|
@ -755,7 +726,7 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
if write:
|
||||
item.try_write()
|
||||
except ReplayGainError as e:
|
||||
log.info(u"ReplayGain error: {0}".format(e))
|
||||
log.info(u"ReplayGain error: {0}", e)
|
||||
except FatalReplayGainError as e:
|
||||
raise ui.UserError(
|
||||
u"Fatal replay gain error: {0}".format(e)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@
|
|||
formats.
|
||||
"""
|
||||
import re
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import logging
|
||||
from beets import ui
|
||||
from beets import library
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ class RewritePlugin(BeetsPlugin):
|
|||
if fieldname not in library.Item._fields:
|
||||
raise ui.UserError("invalid field name (%s) in rewriter" %
|
||||
fieldname)
|
||||
log.debug(u'adding template field {0}'.format(key))
|
||||
log.debug(u'adding template field {0}', key)
|
||||
pattern = re.compile(pattern.lower())
|
||||
rules[fieldname].append((pattern, value))
|
||||
if fieldname == 'artist':
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@
|
|||
"""Cleans extraneous metadata from files' tags via a command or
|
||||
automatically whenever tags are written.
|
||||
"""
|
||||
import logging
|
||||
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets import ui
|
||||
from beets import util
|
||||
|
|
@ -64,8 +64,7 @@ class ScrubPlugin(BeetsPlugin):
|
|||
|
||||
# Walk through matching files and remove tags.
|
||||
for item in lib.items(ui.decargs(args)):
|
||||
log.info(u'scrubbing: {0}'.format(
|
||||
util.displayable_path(item.path)))
|
||||
log.info(u'scrubbing: {0}', util.displayable_path(item.path))
|
||||
|
||||
# Get album art if we need to restore it.
|
||||
if opts.write:
|
||||
|
|
@ -132,14 +131,13 @@ def _scrub(path):
|
|||
del f[tag]
|
||||
f.save()
|
||||
except IOError as exc:
|
||||
log.error(u'could not scrub {0}: {1}'.format(
|
||||
util.displayable_path(path), exc,
|
||||
))
|
||||
log.error(u'could not scrub {0}: {1}',
|
||||
util.displayable_path(path), exc)
|
||||
|
||||
|
||||
# Automatically embed art into imported albums.
|
||||
@ScrubPlugin.listen('write')
|
||||
def write_item(path):
|
||||
if not scrubbing and config['scrub']['auto']:
|
||||
log.debug(u'auto-scrubbing {0}'.format(util.displayable_path(path)))
|
||||
log.debug(u'auto-scrubbing {0}', util.displayable_path(path))
|
||||
_scrub(path)
|
||||
|
|
|
|||
|
|
@ -2,10 +2,9 @@ from __future__ import print_function
|
|||
import re
|
||||
import webbrowser
|
||||
import requests
|
||||
import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import decargs
|
||||
from beets import ui
|
||||
from beets import ui, logging
|
||||
from requests.exceptions import HTTPError
|
||||
|
||||
log = logging.getLogger('beets')
|
||||
|
|
@ -63,8 +62,7 @@ class SpotifyPlugin(BeetsPlugin):
|
|||
self.config['show_failures'].set(True)
|
||||
|
||||
if self.config['mode'].get() not in ['list', 'open']:
|
||||
log.warn(u'{0} is not a valid mode'
|
||||
.format(self.config['mode'].get()))
|
||||
log.warn(u'{0} is not a valid mode', self.config['mode'].get())
|
||||
return False
|
||||
|
||||
self.opts = opts
|
||||
|
|
@ -81,7 +79,7 @@ class SpotifyPlugin(BeetsPlugin):
|
|||
log.debug(u'Your beets query returned no items, skipping spotify')
|
||||
return
|
||||
|
||||
log.info(u'Processing {0} tracks...'.format(len(items)))
|
||||
log.info(u'Processing {0} tracks...', len(items))
|
||||
|
||||
for item in items:
|
||||
|
||||
|
|
@ -113,8 +111,7 @@ class SpotifyPlugin(BeetsPlugin):
|
|||
try:
|
||||
r.raise_for_status()
|
||||
except HTTPError as e:
|
||||
log.debug(u'URL returned a {0} error'
|
||||
.format(e.response.status_code))
|
||||
log.debug(u'URL returned a {0} error', e.response.status_code)
|
||||
failures.append(search_url)
|
||||
continue
|
||||
|
||||
|
|
@ -130,33 +127,31 @@ class SpotifyPlugin(BeetsPlugin):
|
|||
# Simplest, take the first result
|
||||
chosen_result = None
|
||||
if len(r_data) == 1 or self.config['tiebreak'].get() == "first":
|
||||
log.debug(u'Spotify track(s) found, count: {0}'
|
||||
.format(len(r_data)))
|
||||
log.debug(u'Spotify track(s) found, count: {0}', len(r_data))
|
||||
chosen_result = r_data[0]
|
||||
elif len(r_data) > 1:
|
||||
# Use the popularity filter
|
||||
log.debug(u'Most popular track chosen, count: {0}'
|
||||
.format(len(r_data)))
|
||||
log.debug(u'Most popular track chosen, count: {0}',
|
||||
len(r_data))
|
||||
chosen_result = max(r_data, key=lambda x: x['popularity'])
|
||||
|
||||
if chosen_result:
|
||||
results.append(chosen_result)
|
||||
else:
|
||||
log.debug(u'No spotify track found: {0}'.format(search_url))
|
||||
log.debug(u'No spotify track found: {0}', search_url)
|
||||
failures.append(search_url)
|
||||
|
||||
failure_count = len(failures)
|
||||
if failure_count > 0:
|
||||
if self.config['show_failures'].get():
|
||||
log.info(u'{0} track(s) did not match a Spotify ID:'
|
||||
.format(failure_count))
|
||||
log.info(u'{0} track(s) did not match a Spotify ID:',
|
||||
failure_count)
|
||||
for track in failures:
|
||||
log.info(u'track: {0}'.format(track))
|
||||
log.info(u'track: {0}', track)
|
||||
log.info(u'')
|
||||
else:
|
||||
log.warn(u'{0} track(s) did not match a Spotify ID;\n'
|
||||
u'use --show-failures to display'
|
||||
.format(failure_count))
|
||||
u'use --show-failures to display', failure_count)
|
||||
|
||||
return results
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
"""Moves patterns in path formats (suitable for moving articles)."""
|
||||
|
||||
import re
|
||||
import logging
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
|
||||
__author__ = 'baobab@heresiarch.info'
|
||||
|
|
@ -56,11 +56,11 @@ class ThePlugin(BeetsPlugin):
|
|||
try:
|
||||
re.compile(p)
|
||||
except re.error:
|
||||
self._log.error(u'[the] invalid pattern: {0}'.format(p))
|
||||
self._log.error(u'[the] invalid pattern: {0}', p)
|
||||
else:
|
||||
if not (p.startswith('^') or p.endswith('$')):
|
||||
self._log.warn(u'[the] warning: \"{0}\" will not '
|
||||
'match string start/end'.format(p))
|
||||
'match string start/end', p)
|
||||
if self.config['a']:
|
||||
self.patterns = [PATTERN_A] + self.patterns
|
||||
if self.config['the']:
|
||||
|
|
@ -99,7 +99,7 @@ class ThePlugin(BeetsPlugin):
|
|||
r = self.unthe(text, p)
|
||||
if r != text:
|
||||
break
|
||||
self._log.debug(u'[the] \"{0}\" -> \"{1}\"'.format(text, r))
|
||||
self._log.debug(u'[the] \"{0}\" -> \"{1}\"', text, r)
|
||||
return r
|
||||
else:
|
||||
return u''
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
""" Clears tag fields in media files."""
|
||||
|
||||
import re
|
||||
import logging
|
||||
from beets import logging
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.mediafile import MediaFile
|
||||
from beets.importer import action
|
||||
|
|
@ -49,10 +49,10 @@ class ZeroPlugin(BeetsPlugin):
|
|||
for field in self.config['fields'].as_str_seq():
|
||||
if field in ('id', 'path', 'album_id'):
|
||||
log.warn(u'[zero] field \'{0}\' ignored, zeroing '
|
||||
u'it would be dangerous'.format(field))
|
||||
u'it would be dangerous', field)
|
||||
continue
|
||||
if field not in MediaFile.fields():
|
||||
log.error(u'[zero] invalid field: {0}'.format(field))
|
||||
log.error(u'[zero] invalid field: {0}', field)
|
||||
continue
|
||||
|
||||
try:
|
||||
|
|
@ -97,5 +97,5 @@ class ZeroPlugin(BeetsPlugin):
|
|||
match = patterns is True
|
||||
|
||||
if match:
|
||||
log.debug(u'[zero] {0}: {1} -> None'.format(field, value))
|
||||
log.debug(u'[zero] {0}: {1} -> None', field, value)
|
||||
tags[field] = None
|
||||
|
|
|
|||
|
|
@ -16,7 +16,6 @@
|
|||
import time
|
||||
import sys
|
||||
import os
|
||||
import logging
|
||||
import tempfile
|
||||
import shutil
|
||||
from contextlib import contextmanager
|
||||
|
|
@ -30,7 +29,7 @@ except ImportError:
|
|||
# Mangle the search path to include the beets sources.
|
||||
sys.path.insert(0, '..')
|
||||
import beets.library
|
||||
from beets import importer
|
||||
from beets import importer, logging
|
||||
from beets.ui import commands
|
||||
import beets
|
||||
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ import os
|
|||
import os.path
|
||||
import shutil
|
||||
import subprocess
|
||||
import logging
|
||||
from tempfile import mkdtemp, mkstemp
|
||||
from contextlib import contextmanager
|
||||
from StringIO import StringIO
|
||||
from enum import Enum
|
||||
|
||||
import beets
|
||||
from beets import logging
|
||||
from beets import config
|
||||
import beets.plugins
|
||||
from beets.library import Library, Item, Album
|
||||
|
|
|
|||
42
test/test_logging.py
Normal file
42
test/test_logging.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
"""Stupid tests that ensure logging works as expected"""
|
||||
import logging as log
|
||||
from StringIO import StringIO
|
||||
|
||||
import beets.logging as blog
|
||||
from _common import unittest, TestCase
|
||||
|
||||
|
||||
class LoggingTest(TestCase):
|
||||
def test_logging_management(self):
|
||||
l1 = log.getLogger("foo123")
|
||||
l2 = blog.getLogger("foo123")
|
||||
self.assertEqual(l1, l2)
|
||||
self.assertEqual(l1.__class__, log.Logger)
|
||||
|
||||
l3 = blog.getLogger("bar123")
|
||||
l4 = log.getLogger("bar123")
|
||||
self.assertEqual(l3, l4)
|
||||
self.assertEqual(l3.__class__, blog.StrFormatLogger)
|
||||
|
||||
l5 = l3.getChild("shalala")
|
||||
self.assertEqual(l5.__class__, blog.StrFormatLogger)
|
||||
|
||||
def test_str_format_logging(self):
|
||||
l = blog.getLogger("baz123")
|
||||
stream = StringIO()
|
||||
handler = log.StreamHandler(stream)
|
||||
|
||||
l.addHandler(handler)
|
||||
l.propagate = False
|
||||
|
||||
l.warning("foo {0} {bar}", "oof", bar="baz")
|
||||
handler.flush()
|
||||
self.assertTrue(stream.getvalue(), "foo oof baz")
|
||||
|
||||
|
||||
def suite():
|
||||
return unittest.TestLoader().loadTestsFromName(__name__)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main(defaultTest='suite')
|
||||
Loading…
Reference in a new issue