mirror of
https://github.com/beetbox/beets.git
synced 2026-01-18 06:05:06 +01:00
Merge pull request #1269 from brunal/libmodels-formatting
Automatic formatting for Album & Item
This commit is contained in:
commit
94020963d2
16 changed files with 98 additions and 112 deletions
|
|
@ -229,6 +229,8 @@ class WriteError(FileOperationError):
|
|||
class LibModel(dbcore.Model):
|
||||
"""Shared concrete functionality for Items and Albums.
|
||||
"""
|
||||
_format_config_key = None
|
||||
"""Config key that specifies how an instance should be formatted"""
|
||||
|
||||
def _template_funcs(self):
|
||||
funcs = DefaultTemplateFunctions(self, self._db).functions()
|
||||
|
|
@ -247,6 +249,22 @@ class LibModel(dbcore.Model):
|
|||
super(LibModel, self).add(lib)
|
||||
plugins.send('database_change', lib=self._db)
|
||||
|
||||
def __format__(self, spec):
|
||||
if not spec:
|
||||
spec = beets.config[self._format_config_key].get(unicode)
|
||||
result = self.evaluate_template(spec)
|
||||
if isinstance(spec, bytes):
|
||||
# if spec is a byte string then we must return a one as well
|
||||
return result.encode('utf8')
|
||||
else:
|
||||
return result
|
||||
|
||||
def __str__(self):
|
||||
return format(self).encode('utf8')
|
||||
|
||||
def __unicode__(self):
|
||||
return format(self)
|
||||
|
||||
|
||||
class FormattedItemMapping(dbcore.db.FormattedMapping):
|
||||
"""Add lookup for album-level fields.
|
||||
|
|
@ -383,6 +401,8 @@ class Item(LibModel):
|
|||
|
||||
_sorts = {'artist': SmartArtistSort}
|
||||
|
||||
_format_config_key = 'list_format_item'
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
getters = plugins.item_field_getters()
|
||||
|
|
@ -789,6 +809,8 @@ class Album(LibModel):
|
|||
"""List of keys that are set on an album's items.
|
||||
"""
|
||||
|
||||
_format_config_key = 'list_format_album'
|
||||
|
||||
@classmethod
|
||||
def _getters(cls):
|
||||
# In addition to plugin-provided computed fields, also expose
|
||||
|
|
|
|||
|
|
@ -97,6 +97,9 @@ def print_(*strings):
|
|||
"""Like print, but rather than raising an error when a character
|
||||
is not in the terminal's encoding's character set, just silently
|
||||
replaces it.
|
||||
|
||||
If the arguments are strings then they're expected to share the same type:
|
||||
either bytes or unicode.
|
||||
"""
|
||||
if strings:
|
||||
if isinstance(strings[0], unicode):
|
||||
|
|
@ -471,31 +474,6 @@ def get_replacements():
|
|||
return replacements
|
||||
|
||||
|
||||
def _pick_format(album, fmt=None):
|
||||
"""Pick a format string for printing Album or Item objects,
|
||||
falling back to config options and defaults.
|
||||
"""
|
||||
if fmt:
|
||||
return fmt
|
||||
if album:
|
||||
return config['list_format_album'].get(unicode)
|
||||
else:
|
||||
return config['list_format_item'].get(unicode)
|
||||
|
||||
|
||||
def print_obj(obj, lib, fmt=None):
|
||||
"""Print an Album or Item object. If `fmt` is specified, use that
|
||||
format string. Otherwise, use the configured template.
|
||||
"""
|
||||
album = isinstance(obj, library.Album)
|
||||
fmt = _pick_format(album, fmt)
|
||||
if isinstance(fmt, Template):
|
||||
template = fmt
|
||||
else:
|
||||
template = Template(fmt)
|
||||
print_(obj.evaluate_template(template))
|
||||
|
||||
|
||||
def term_width():
|
||||
"""Get the width (columns) of the terminal."""
|
||||
fallback = config['ui']['terminal_width'].get(int)
|
||||
|
|
@ -587,7 +565,7 @@ def show_model_changes(new, old=None, fields=None, always=False):
|
|||
|
||||
# Print changes.
|
||||
if changes or always:
|
||||
print_obj(old, old._db)
|
||||
print_(format(old))
|
||||
if changes:
|
||||
print_(u'\n'.join(changes))
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ from beets import plugins
|
|||
from beets import importer
|
||||
from beets import util
|
||||
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
|
||||
|
|
@ -951,20 +950,16 @@ def list_items(lib, query, album, fmt):
|
|||
"""Print out items in lib matching query. If album, then search for
|
||||
albums instead of single items.
|
||||
"""
|
||||
tmpl = Template(ui._pick_format(album, fmt))
|
||||
if album:
|
||||
for album in lib.albums(query):
|
||||
ui.print_obj(album, lib, tmpl)
|
||||
ui.print_(format(album, fmt))
|
||||
else:
|
||||
for item in lib.items(query):
|
||||
ui.print_obj(item, lib, tmpl)
|
||||
ui.print_(format(item, fmt))
|
||||
|
||||
|
||||
def list_func(lib, opts, args):
|
||||
if opts.path:
|
||||
fmt = '$path'
|
||||
else:
|
||||
fmt = opts.format
|
||||
fmt = '$path' if opts.path else opts.format
|
||||
list_items(lib, decargs(args), opts.album, fmt)
|
||||
|
||||
|
||||
|
|
@ -979,7 +974,7 @@ list_cmd.parser.add_option(
|
|||
)
|
||||
list_cmd.parser.add_option(
|
||||
'-f', '--format', action='store',
|
||||
help='print with custom format', default=None
|
||||
help='print with custom format', default=''
|
||||
)
|
||||
list_cmd.func = list_func
|
||||
default_commands.append(list_cmd)
|
||||
|
|
@ -999,7 +994,7 @@ def update_items(lib, query, album, move, pretend):
|
|||
for item in items:
|
||||
# Item deleted?
|
||||
if not os.path.exists(syspath(item.path)):
|
||||
ui.print_obj(item, lib)
|
||||
ui.print_(format(item))
|
||||
ui.print_(ui.colorize('red', u' deleted'))
|
||||
if not pretend:
|
||||
item.remove(True)
|
||||
|
|
@ -1095,7 +1090,7 @@ update_cmd.parser.add_option(
|
|||
)
|
||||
update_cmd.parser.add_option(
|
||||
'-f', '--format', action='store',
|
||||
help='print with custom format', default=None
|
||||
help='print with custom format', default=''
|
||||
)
|
||||
update_cmd.func = update_func
|
||||
default_commands.append(update_cmd)
|
||||
|
|
@ -1116,13 +1111,13 @@ def remove_items(lib, query, album, delete):
|
|||
fmt = u'$path - $title'
|
||||
prompt = 'Really DELETE %i files (y/n)?' % len(items)
|
||||
else:
|
||||
fmt = None
|
||||
fmt = ''
|
||||
prompt = 'Really remove %i items from the library (y/n)?' % \
|
||||
len(items)
|
||||
|
||||
# Show all the items.
|
||||
for item in items:
|
||||
ui.print_obj(item, lib, fmt)
|
||||
ui.print_(format(item, fmt))
|
||||
|
||||
# Confirm with user.
|
||||
if not ui.input_yn(prompt, True):
|
||||
|
|
@ -1352,7 +1347,7 @@ modify_cmd.parser.add_option(
|
|||
)
|
||||
modify_cmd.parser.add_option(
|
||||
'-f', '--format', action='store',
|
||||
help='print with custom format', default=None
|
||||
help='print with custom format', default=''
|
||||
)
|
||||
modify_cmd.func = modify_func
|
||||
default_commands.append(modify_cmd)
|
||||
|
|
|
|||
|
|
@ -356,7 +356,7 @@ class ConvertPlugin(BeetsPlugin):
|
|||
self.config['pretend'].get(bool)
|
||||
|
||||
if not pretend:
|
||||
ui.commands.list_items(lib, ui.decargs(args), opts.album, None)
|
||||
ui.commands.list_items(lib, ui.decargs(args), opts.album, '')
|
||||
|
||||
if not (opts.yes or ui.input_yn("Convert? (Y/n)")):
|
||||
return
|
||||
|
|
|
|||
|
|
@ -17,14 +17,14 @@
|
|||
import shlex
|
||||
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import decargs, print_obj, vararg_callback, Subcommand, UserError
|
||||
from beets.ui import decargs, print_, vararg_callback, Subcommand, UserError
|
||||
from beets.util import command_output, displayable_path, subprocess
|
||||
|
||||
PLUGIN = 'duplicates'
|
||||
|
||||
|
||||
def _process_item(item, lib, copy=False, move=False, delete=False,
|
||||
tag=False, format=None):
|
||||
tag=False, format=''):
|
||||
"""Process Item `item` in `lib`.
|
||||
"""
|
||||
if copy:
|
||||
|
|
@ -42,7 +42,7 @@ def _process_item(item, lib, copy=False, move=False, delete=False,
|
|||
raise UserError('%s: can\'t parse k=v tag: %s' % (PLUGIN, tag))
|
||||
setattr(k, v)
|
||||
item.store()
|
||||
print_obj(item, lib, fmt=format)
|
||||
print_(format(item, format))
|
||||
|
||||
|
||||
def _checksum(item, prog, log):
|
||||
|
|
@ -126,7 +126,7 @@ class DuplicatesPlugin(BeetsPlugin):
|
|||
self._command.parser.add_option('-f', '--format', dest='format',
|
||||
action='store', type='string',
|
||||
help='print with custom format',
|
||||
metavar='FMT')
|
||||
metavar='FMT', default='')
|
||||
|
||||
self._command.parser.add_option('-a', '--album', dest='album',
|
||||
action='store_true',
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ def similar(lib, src_item, threshold=0.15, fmt='${difference}: ${path}'):
|
|||
d = diff(item, src_item)
|
||||
if d < threshold:
|
||||
s = fmt.replace('${difference}', '{:2.2f}'.format(d))
|
||||
ui.print_obj(item, lib, s)
|
||||
ui.print_(format(item, s))
|
||||
|
||||
|
||||
class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
||||
|
|
@ -401,10 +401,9 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
for method in methods:
|
||||
song = method(item)
|
||||
if song:
|
||||
self._log.debug(u'got song through {0}: {1} - {2} [{3}]',
|
||||
self._log.debug(u'got song through {0}: {1} [{2}]',
|
||||
method.__name__,
|
||||
item.artist,
|
||||
item.title,
|
||||
item,
|
||||
song.get('duration'),
|
||||
)
|
||||
return song
|
||||
|
|
@ -471,7 +470,7 @@ class EchonestMetadataPlugin(plugins.BeetsPlugin):
|
|||
self.config.set_args(opts)
|
||||
write = config['import']['write'].get(bool)
|
||||
for item in lib.items(ui.decargs(args)):
|
||||
self._log.info(u'{0} - {1}', item.artist, item.title)
|
||||
self._log.info(u'{0}', item)
|
||||
if self.config['force'] or self.requires_update(item):
|
||||
song = self.fetch_song(item)
|
||||
if song:
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@ from beets.ui import decargs
|
|||
from beets.util import syspath, normpath, displayable_path
|
||||
from beets.util.artresizer import ArtResizer
|
||||
from beets import config
|
||||
from beets.util.functemplate import Template
|
||||
|
||||
__item_template = Template(ui._pick_format(False))
|
||||
fmt_item = lambda item: item.evaluate_template(__item_template)
|
||||
__album_template = Template(ui._pick_format(True))
|
||||
fmt_album = lambda item: item.evaluate_template(__album_template)
|
||||
|
||||
|
||||
class EmbedCoverArtPlugin(BeetsPlugin):
|
||||
|
|
@ -146,16 +140,16 @@ class EmbedCoverArtPlugin(BeetsPlugin):
|
|||
"""
|
||||
imagepath = album.artpath
|
||||
if not imagepath:
|
||||
self._log.info(u'No album art present for {0}', fmt_album(album))
|
||||
self._log.info(u'No album art present for {0}', album)
|
||||
return
|
||||
if not os.path.isfile(syspath(imagepath)):
|
||||
self._log.info(u'Album art not found at {0} for {1}',
|
||||
displayable_path(imagepath), fmt_album(album))
|
||||
displayable_path(imagepath), album)
|
||||
return
|
||||
if maxwidth:
|
||||
imagepath = self.resize_image(imagepath, maxwidth)
|
||||
|
||||
self._log.info(u'Embedding album art into {0}', fmt_album(album))
|
||||
self._log.info(u'Embedding album art into {0}', album)
|
||||
|
||||
for item in album.items():
|
||||
thresh = self.config['compare_threshold'].get(int)
|
||||
|
|
@ -244,8 +238,7 @@ class EmbedCoverArtPlugin(BeetsPlugin):
|
|||
art = self.get_art(item)
|
||||
|
||||
if not art:
|
||||
self._log.info(u'No album art present in {0}, skipping.',
|
||||
fmt_item(item))
|
||||
self._log.info(u'No album art present in {0}, skipping.', item)
|
||||
return
|
||||
|
||||
# Add an extension to the filename.
|
||||
|
|
@ -257,7 +250,7 @@ class EmbedCoverArtPlugin(BeetsPlugin):
|
|||
outpath += '.' + ext
|
||||
|
||||
self._log.info(u'Extracting album art from: {0} to: {1}',
|
||||
fmt_item(item), displayable_path(outpath))
|
||||
item, displayable_path(outpath))
|
||||
with open(syspath(outpath), 'wb') as f:
|
||||
f.write(art)
|
||||
return outpath
|
||||
|
|
@ -269,7 +262,7 @@ class EmbedCoverArtPlugin(BeetsPlugin):
|
|||
items = lib.items(query)
|
||||
self._log.info(u'Clearing album art from {0} items', len(items))
|
||||
for item in items:
|
||||
self._log.debug(u'Clearing art for {0}', fmt_item(item))
|
||||
self._log.debug(u'Clearing art for {0}', item)
|
||||
try:
|
||||
mf = mediafile.MediaFile(syspath(item.path), id3v23)
|
||||
except mediafile.UnreadableFileError as exc:
|
||||
|
|
|
|||
|
|
@ -448,7 +448,7 @@ class FetchArtPlugin(plugins.BeetsPlugin):
|
|||
else:
|
||||
message = ui.colorize('red', 'no art found')
|
||||
|
||||
self._log.info(u'{0.albumartist} - {0.album}: {1}', album, message)
|
||||
self._log.info(u'{0}: {1}', album, message)
|
||||
|
||||
def _source_urls(self, album):
|
||||
"""Generate possible source URLs for an album's art. The URLs are
|
||||
|
|
|
|||
|
|
@ -337,8 +337,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
|
||||
for album in lib.albums(ui.decargs(args)):
|
||||
album.genre, src = self._get_genre(album)
|
||||
self._log.info(u'genre for album {0.albumartist} - {0.album} '
|
||||
u'({1}): {0.genre}', album, src)
|
||||
self._log.info(u'genre for album {0} ({1}): {0.genre}',
|
||||
album, src)
|
||||
album.store()
|
||||
|
||||
for item in album.items():
|
||||
|
|
@ -347,8 +347,8 @@ class LastGenrePlugin(plugins.BeetsPlugin):
|
|||
if 'track' in self.sources:
|
||||
item.genre, src = self._get_genre(item)
|
||||
item.store()
|
||||
self._log.info(u'genre for track {0.artist} - {0.tit'
|
||||
u'le} ({1}): {0.genre}', item, src)
|
||||
self._log.info(u'genre for track {0} ({1}): {0.genre}',
|
||||
item, src)
|
||||
|
||||
if write:
|
||||
item.try_write()
|
||||
|
|
|
|||
|
|
@ -508,8 +508,7 @@ class LyricsPlugin(plugins.BeetsPlugin):
|
|||
lyrics will also be written to the file itself."""
|
||||
# Skip if the item already has lyrics.
|
||||
if not force and item.lyrics:
|
||||
self._log.info(u'lyrics already present: {0.artist} - {0.title}',
|
||||
item)
|
||||
self._log.info(u'lyrics already present: {0}', item)
|
||||
return
|
||||
|
||||
lyrics = None
|
||||
|
|
@ -521,9 +520,9 @@ class LyricsPlugin(plugins.BeetsPlugin):
|
|||
lyrics = u"\n\n---\n\n".join([l for l in lyrics if l])
|
||||
|
||||
if lyrics:
|
||||
self._log.info(u'fetched lyrics: {0.artist} - {0.title}', item)
|
||||
self._log.info(u'fetched lyrics: {0}', item)
|
||||
else:
|
||||
self._log.info(u'lyrics not found: {0.artist} - {0.title}', item)
|
||||
self._log.info(u'lyrics not found: {0}', item)
|
||||
fallback = self.config['fallback'].get()
|
||||
if fallback:
|
||||
lyrics = fallback
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ from beets.plugins import BeetsPlugin
|
|||
from beets import autotag, library, ui, util
|
||||
from beets.autotag import hooks
|
||||
from beets import config
|
||||
from beets.util.functemplate import Template
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
|
|
@ -50,7 +49,7 @@ class MBSyncPlugin(BeetsPlugin):
|
|||
cmd.parser.add_option('-W', '--nowrite', action='store_false',
|
||||
default=config['import']['write'], dest='write',
|
||||
help="don't write updated metadata to files")
|
||||
cmd.parser.add_option('-f', '--format', action='store', default=None,
|
||||
cmd.parser.add_option('-f', '--format', action='store', default='',
|
||||
help='print with custom format')
|
||||
cmd.func = self.func
|
||||
return [cmd]
|
||||
|
|
@ -71,10 +70,8 @@ class MBSyncPlugin(BeetsPlugin):
|
|||
"""Retrieve and apply info from the autotagger for items matched by
|
||||
query.
|
||||
"""
|
||||
template = Template(ui._pick_format(False, fmt))
|
||||
|
||||
for item in lib.items(query + ['singleton:true']):
|
||||
item_formatted = item.evaluate_template(template)
|
||||
item_formatted = format(item, fmt)
|
||||
if not item.mb_trackid:
|
||||
self._log.info(u'Skipping singleton with no mb_trackid: {0}',
|
||||
item_formatted)
|
||||
|
|
@ -97,11 +94,9 @@ class MBSyncPlugin(BeetsPlugin):
|
|||
"""Retrieve and apply info from the autotagger for albums matched by
|
||||
query and their items.
|
||||
"""
|
||||
template = Template(ui._pick_format(True, fmt))
|
||||
|
||||
# Process matching albums.
|
||||
for a in lib.albums(query):
|
||||
album_formatted = a.evaluate_template(template)
|
||||
album_formatted = format(a, fmt)
|
||||
if not a.mb_albumid:
|
||||
self._log.info(u'Skipping album with no mb_albumid: {0}',
|
||||
album_formatted)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
from beets.autotag import hooks
|
||||
from beets.library import Item
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import decargs, print_obj, Subcommand
|
||||
from beets.ui import decargs, print_, Subcommand
|
||||
|
||||
|
||||
def _missing_count(album):
|
||||
|
|
@ -95,7 +95,7 @@ class MissingPlugin(BeetsPlugin):
|
|||
self._command.parser.add_option('-f', '--format', dest='format',
|
||||
action='store', type='string',
|
||||
help='print with custom FORMAT',
|
||||
metavar='FORMAT')
|
||||
metavar='FORMAT', default='')
|
||||
|
||||
self._command.parser.add_option('-c', '--count', dest='count',
|
||||
action='store_true',
|
||||
|
|
@ -123,13 +123,12 @@ class MissingPlugin(BeetsPlugin):
|
|||
|
||||
for album in albums:
|
||||
if count:
|
||||
missing = _missing_count(album)
|
||||
if missing:
|
||||
print_obj(album, lib, fmt=fmt)
|
||||
if _missing_count(album):
|
||||
print_(format(album, fmt))
|
||||
|
||||
else:
|
||||
for item in self._missing(album):
|
||||
print_obj(item, lib, fmt=fmt)
|
||||
print_(format(item, fmt))
|
||||
|
||||
self._command.func = _miss
|
||||
return [self._command]
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@
|
|||
"""
|
||||
from __future__ import absolute_import
|
||||
from beets.plugins import BeetsPlugin
|
||||
from beets.ui import Subcommand, decargs, print_obj
|
||||
from beets.util.functemplate import Template
|
||||
from beets.ui import Subcommand, decargs, print_
|
||||
import random
|
||||
from operator import attrgetter
|
||||
from itertools import groupby
|
||||
|
|
@ -25,11 +24,7 @@ from itertools import groupby
|
|||
|
||||
def random_item(lib, opts, args):
|
||||
query = decargs(args)
|
||||
if opts.path:
|
||||
fmt = '$path'
|
||||
else:
|
||||
fmt = opts.format
|
||||
template = Template(fmt) if fmt else None
|
||||
fmt = '$path' if opts.path else opts.format
|
||||
|
||||
if opts.album:
|
||||
objs = list(lib.albums(query))
|
||||
|
|
@ -66,7 +61,7 @@ def random_item(lib, opts, args):
|
|||
objs = random.sample(objs, number)
|
||||
|
||||
for item in objs:
|
||||
print_obj(item, lib, template)
|
||||
print_(format(item, fmt))
|
||||
|
||||
random_cmd = Subcommand('random',
|
||||
help='chose a random track or album')
|
||||
|
|
@ -75,7 +70,7 @@ random_cmd.parser.add_option('-a', '--album', action='store_true',
|
|||
random_cmd.parser.add_option('-p', '--path', action='store_true',
|
||||
help='print the path of the matched item')
|
||||
random_cmd.parser.add_option('-f', '--format', action='store',
|
||||
help='print with custom format', default=None)
|
||||
help='print with custom format', default='')
|
||||
random_cmd.parser.add_option('-n', '--number', action='store', type="int",
|
||||
help='number of objects to choose', default=1)
|
||||
random_cmd.parser.add_option('-e', '--equal-chance', action='store_true',
|
||||
|
|
|
|||
|
|
@ -558,7 +558,7 @@ class AudioToolsBackend(Backend):
|
|||
|
||||
:rtype: :class:`AlbumGain`
|
||||
"""
|
||||
self._log.debug(u'Analysing album {0.albumartist} - {0.album}', album)
|
||||
self._log.debug(u'Analysing album {0}', 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
|
||||
|
|
@ -574,15 +574,13 @@ class AudioToolsBackend(Backend):
|
|||
track_gains.append(
|
||||
Gain(gain=rg_track_gain, peak=rg_track_peak)
|
||||
)
|
||||
self._log.debug(u'ReplayGain for track {0.artist} - {0.title}: '
|
||||
u'{1:.2f}, {2:.2f}',
|
||||
self._log.debug(u'ReplayGain for track {0}: {1:.2f}, {2:.2f}',
|
||||
item, 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()
|
||||
self._log.debug(u'ReplayGain for album {0.albumartist} - {0.album}: '
|
||||
u'{1:.2f}, {2:.2f}',
|
||||
self._log.debug(u'ReplayGain for album {0}: {1:.2f}, {2:.2f}',
|
||||
album, rg_album_gain, rg_album_peak)
|
||||
|
||||
return AlbumGain(
|
||||
|
|
@ -674,20 +672,17 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
items, nothing is done.
|
||||
"""
|
||||
if not self.album_requires_gain(album):
|
||||
self._log.info(u'Skipping album {0} - {1}',
|
||||
album.albumartist, album.album)
|
||||
self._log.info(u'Skipping album {0}', album)
|
||||
return
|
||||
|
||||
self._log.info(u'analyzing {0} - {1}', album.albumartist, album.album)
|
||||
self._log.info(u'analyzing {0}', album)
|
||||
|
||||
try:
|
||||
album_gain = self.backend_instance.compute_album_gain(album)
|
||||
if len(album_gain.track_gains) != len(album.items()):
|
||||
raise ReplayGainError(
|
||||
u"ReplayGain backend failed "
|
||||
u"for some tracks in album {0} - {1}".format(
|
||||
album.albumartist, album.album
|
||||
)
|
||||
u"for some tracks in album {0}".format(album)
|
||||
)
|
||||
|
||||
self.store_album_gain(album, album_gain.album_gain)
|
||||
|
|
@ -711,18 +706,16 @@ class ReplayGainPlugin(BeetsPlugin):
|
|||
in the item, nothing is done.
|
||||
"""
|
||||
if not self.track_requires_gain(item):
|
||||
self._log.info(u'Skipping track {0.artist} - {0.title}', item)
|
||||
self._log.info(u'Skipping track {0}', item)
|
||||
return
|
||||
|
||||
self._log.info(u'analyzing {0} - {1}', item.artist, item.title)
|
||||
self._log.info(u'analyzing {0}', item)
|
||||
|
||||
try:
|
||||
track_gains = self.backend_instance.compute_track_gain([item])
|
||||
if len(track_gains) != 1:
|
||||
raise ReplayGainError(
|
||||
u"ReplayGain backend failed for track {0} - {1}".format(
|
||||
item.artist, item.title
|
||||
)
|
||||
u"ReplayGain backend failed for track {0}".format(item)
|
||||
)
|
||||
|
||||
self.store_track_gain(item, track_gains[0])
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# This file is part of beets.
|
||||
# Copyright 2015, Adrian Sampson.
|
||||
#
|
||||
|
|
@ -1078,6 +1079,23 @@ class TemplateTest(_common.LibTestCase):
|
|||
self.album.store()
|
||||
self.assertEqual(self.i.evaluate_template('$foo'), 'baz')
|
||||
|
||||
def test_album_and_item_format(self):
|
||||
config['list_format_album'] = u'foö $foo'
|
||||
album = beets.library.Album()
|
||||
album.foo = 'bar'
|
||||
album.tagada = 'togodo'
|
||||
self.assertEqual(u"{0}".format(album), u"foö bar")
|
||||
self.assertEqual(u"{0:$tagada}".format(album), u"togodo")
|
||||
self.assertEqual(unicode(album), u"foö bar")
|
||||
self.assertEqual(str(album), b"fo\xc3\xb6 bar")
|
||||
|
||||
config['list_format_item'] = 'bar $foo'
|
||||
item = beets.library.Item()
|
||||
item.foo = 'bar'
|
||||
item.tagada = 'togodo'
|
||||
self.assertEqual("{0}".format(item), "bar bar")
|
||||
self.assertEqual("{0:$tagada}".format(item), "togodo")
|
||||
|
||||
|
||||
class UnicodePathTest(_common.LibTestCase):
|
||||
def test_unicode_path(self):
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class ListTest(unittest.TestCase):
|
|||
self.lib.add(self.item)
|
||||
self.lib.add_album([self.item])
|
||||
|
||||
def _run_list(self, query='', album=False, path=False, fmt=None):
|
||||
def _run_list(self, query='', album=False, path=False, fmt=''):
|
||||
commands.list_items(self.lib, query, album, fmt)
|
||||
|
||||
def test_list_outputs_item(self):
|
||||
|
|
|
|||
Loading…
Reference in a new issue