mirror of
https://github.com/beetbox/beets.git
synced 2025-12-27 02:52:33 +01:00
begin type-based formatting
This commit is contained in:
parent
342d5e1f8b
commit
7aa4d1e5ba
3 changed files with 122 additions and 142 deletions
|
|
@ -26,47 +26,11 @@ from beets.util.functemplate import Template
|
|||
from .query import MatchQuery
|
||||
|
||||
|
||||
# Path element formatting for templating.
|
||||
# FIXME remove this once we have type-based formatting.
|
||||
def format_for_path(value, key=None):
|
||||
"""Sanitize the value for inclusion in a path: replace separators
|
||||
with _, etc. Doesn't guarantee that the whole path will be valid;
|
||||
you should still call `util.sanitize_path` on the complete path.
|
||||
"""
|
||||
if isinstance(value, basestring):
|
||||
if isinstance(value, str):
|
||||
value = value.decode('utf8', 'ignore')
|
||||
elif key in ('track', 'tracktotal', 'disc', 'disctotal'):
|
||||
# Pad indices with zeros.
|
||||
value = u'%02i' % (value or 0)
|
||||
elif key == 'year':
|
||||
value = u'%04i' % (value or 0)
|
||||
elif key in ('month', 'day'):
|
||||
value = u'%02i' % (value or 0)
|
||||
elif key == 'bitrate':
|
||||
# Bitrate gets formatted as kbps.
|
||||
value = u'%ikbps' % ((value or 0) // 1000)
|
||||
elif key == 'samplerate':
|
||||
# Sample rate formatted as kHz.
|
||||
value = u'%ikHz' % ((value or 0) // 1000)
|
||||
elif key in ('added', 'mtime'):
|
||||
# Times are formatted to be human-readable.
|
||||
value = time.strftime(beets.config['time_format'].get(unicode),
|
||||
time.localtime(value))
|
||||
value = unicode(value)
|
||||
elif value is None:
|
||||
value = u''
|
||||
else:
|
||||
value = unicode(value)
|
||||
|
||||
return value
|
||||
|
||||
|
||||
|
||||
# Abstract base for model classes and their field types.
|
||||
|
||||
|
||||
Type = namedtuple('Type', 'sql query')
|
||||
Type = namedtuple('Type', 'sql query format')
|
||||
|
||||
|
||||
class Model(object):
|
||||
|
|
@ -364,9 +328,11 @@ class Model(object):
|
|||
"""
|
||||
value = self.get(key)
|
||||
|
||||
# FIXME this will get replaced with more sophisticated
|
||||
# (type-based) formatting logic.
|
||||
value = format_for_path(value, key)
|
||||
# Format the value as a string according to its type, if any.
|
||||
if key in self._fields:
|
||||
value = self._fields[key].format(value)
|
||||
elif not isinstance(value, unicode):
|
||||
value = unicode(value)
|
||||
|
||||
if for_path:
|
||||
sep_repl = beets.config['path_sep_replace'].get(unicode)
|
||||
|
|
|
|||
212
beets/library.py
212
beets/library.py
|
|
@ -78,14 +78,27 @@ class SingletonQuery(dbcore.Query):
|
|||
# Model field lists.
|
||||
|
||||
# Common types used in field definitions.
|
||||
TYPES = {
|
||||
int: Type('INTEGER', dbcore.query.NumericQuery),
|
||||
float: Type('REAL', dbcore.query.NumericQuery),
|
||||
datetime: Type('REAL', dbcore.query.NumericQuery),
|
||||
unicode: Type('TEXT', dbcore.query.SubstringQuery),
|
||||
bool: Type('INTEGER', dbcore.query.BooleanQuery),
|
||||
}
|
||||
PATH_TYPE = Type('BLOB', PathQuery)
|
||||
ID_TYPE = Type('INTEGER PRIMARY KEY', dbcore.query.NumericQuery, unicode)
|
||||
INT_TYPE = Type('INTEGER', dbcore.query.NumericQuery, unicode)
|
||||
FLOAT_TYPE = Type('REAL', dbcore.query.NumericQuery,
|
||||
lambda n: u'{0:.1f}'.format(n))
|
||||
DATE_TYPE = Type(
|
||||
'REAL',
|
||||
dbcore.query.NumericQuery,
|
||||
lambda d: time.strftime(beets.config['time_format'].get(unicode),
|
||||
time.localtime(d))
|
||||
)
|
||||
STRING_TYPE = Type('TEXT', dbcore.query.SubstringQuery, unicode)
|
||||
BOOL_TYPE = Type('INTEGER', dbcore.query.BooleanQuery, unicode)
|
||||
PATH_TYPE = Type('BLOB', PathQuery, util.displayable_path)
|
||||
|
||||
def _padded_int(digits):
|
||||
return Type('INTEGER', dbcore.query.NumericQuery,
|
||||
lambda n: u'{0:0{1}d}'.format(n, digits))
|
||||
|
||||
def _scaled_int(suffix=u'', unit=1000):
|
||||
return Type('INTEGER', dbcore.query.NumericQuery,
|
||||
lambda n: u'{0}{1}'.format(n // unit, suffix))
|
||||
|
||||
# Fields in the "items" database table; all the metadata available for
|
||||
# items in the library. These are used directly in SQL; they are
|
||||
|
|
@ -96,68 +109,67 @@ PATH_TYPE = Type('BLOB', PathQuery)
|
|||
# - Is the field writable?
|
||||
# - Does the field reflect an attribute of a MediaFile?
|
||||
ITEM_FIELDS = [
|
||||
('id', Type('INTEGER PRIMARY KEY', dbcore.query.NumericQuery),
|
||||
False, False),
|
||||
('path', PATH_TYPE, False, False),
|
||||
('album_id', TYPES[int], False, False),
|
||||
('id', ID_TYPE, False, False),
|
||||
('path', PATH_TYPE, False, False),
|
||||
('album_id', INT_TYPE, False, False),
|
||||
|
||||
('title', TYPES[unicode], True, True),
|
||||
('artist', TYPES[unicode], True, True),
|
||||
('artist_sort', TYPES[unicode], True, True),
|
||||
('artist_credit', TYPES[unicode], True, True),
|
||||
('album', TYPES[unicode], True, True),
|
||||
('albumartist', TYPES[unicode], True, True),
|
||||
('albumartist_sort', TYPES[unicode], True, True),
|
||||
('albumartist_credit', TYPES[unicode], True, True),
|
||||
('genre', TYPES[unicode], True, True),
|
||||
('composer', TYPES[unicode], True, True),
|
||||
('grouping', TYPES[unicode], True, True),
|
||||
('year', TYPES[int], True, True),
|
||||
('month', TYPES[int], True, True),
|
||||
('day', TYPES[int], True, True),
|
||||
('track', TYPES[int], True, True),
|
||||
('tracktotal', TYPES[int], True, True),
|
||||
('disc', TYPES[int], True, True),
|
||||
('disctotal', TYPES[int], True, True),
|
||||
('lyrics', TYPES[unicode], True, True),
|
||||
('comments', TYPES[unicode], True, True),
|
||||
('bpm', TYPES[int], True, True),
|
||||
('comp', TYPES[bool], True, True),
|
||||
('mb_trackid', TYPES[unicode], True, True),
|
||||
('mb_albumid', TYPES[unicode], True, True),
|
||||
('mb_artistid', TYPES[unicode], True, True),
|
||||
('mb_albumartistid', TYPES[unicode], True, True),
|
||||
('albumtype', TYPES[unicode], True, True),
|
||||
('label', TYPES[unicode], True, True),
|
||||
('acoustid_fingerprint', TYPES[unicode], True, True),
|
||||
('acoustid_id', TYPES[unicode], True, True),
|
||||
('mb_releasegroupid', TYPES[unicode], True, True),
|
||||
('asin', TYPES[unicode], True, True),
|
||||
('catalognum', TYPES[unicode], True, True),
|
||||
('script', TYPES[unicode], True, True),
|
||||
('language', TYPES[unicode], True, True),
|
||||
('country', TYPES[unicode], True, True),
|
||||
('albumstatus', TYPES[unicode], True, True),
|
||||
('media', TYPES[unicode], True, True),
|
||||
('albumdisambig', TYPES[unicode], True, True),
|
||||
('disctitle', TYPES[unicode], True, True),
|
||||
('encoder', TYPES[unicode], True, True),
|
||||
('rg_track_gain', TYPES[float], True, True),
|
||||
('rg_track_peak', TYPES[float], True, True),
|
||||
('rg_album_gain', TYPES[float], True, True),
|
||||
('rg_album_peak', TYPES[float], True, True),
|
||||
('original_year', TYPES[int], True, True),
|
||||
('original_month', TYPES[int], True, True),
|
||||
('original_day', TYPES[int], True, True),
|
||||
('title', STRING_TYPE, True, True),
|
||||
('artist', STRING_TYPE, True, True),
|
||||
('artist_sort', STRING_TYPE, True, True),
|
||||
('artist_credit', STRING_TYPE, True, True),
|
||||
('album', STRING_TYPE, True, True),
|
||||
('albumartist', STRING_TYPE, True, True),
|
||||
('albumartist_sort', STRING_TYPE, True, True),
|
||||
('albumartist_credit', STRING_TYPE, True, True),
|
||||
('genre', STRING_TYPE, True, True),
|
||||
('composer', STRING_TYPE, True, True),
|
||||
('grouping', STRING_TYPE, True, True),
|
||||
('year', _padded_int(4), True, True),
|
||||
('month', _padded_int(2), True, True),
|
||||
('day', _padded_int(2), True, True),
|
||||
('track', _padded_int(2), True, True),
|
||||
('tracktotal', _padded_int(2), True, True),
|
||||
('disc', _padded_int(2), True, True),
|
||||
('disctotal', _padded_int(2), True, True),
|
||||
('lyrics', STRING_TYPE, True, True),
|
||||
('comments', STRING_TYPE, True, True),
|
||||
('bpm', INT_TYPE, True, True),
|
||||
('comp', BOOL_TYPE, True, True),
|
||||
('mb_trackid', STRING_TYPE, True, True),
|
||||
('mb_albumid', STRING_TYPE, True, True),
|
||||
('mb_artistid', STRING_TYPE, True, True),
|
||||
('mb_albumartistid', STRING_TYPE, True, True),
|
||||
('albumtype', STRING_TYPE, True, True),
|
||||
('label', STRING_TYPE, True, True),
|
||||
('acoustid_fingerprint', STRING_TYPE, True, True),
|
||||
('acoustid_id', STRING_TYPE, True, True),
|
||||
('mb_releasegroupid', STRING_TYPE, True, True),
|
||||
('asin', STRING_TYPE, True, True),
|
||||
('catalognum', STRING_TYPE, True, True),
|
||||
('script', STRING_TYPE, True, True),
|
||||
('language', STRING_TYPE, True, True),
|
||||
('country', STRING_TYPE, True, True),
|
||||
('albumstatus', STRING_TYPE, True, True),
|
||||
('media', STRING_TYPE, True, True),
|
||||
('albumdisambig', STRING_TYPE, True, True),
|
||||
('disctitle', STRING_TYPE, True, True),
|
||||
('encoder', STRING_TYPE, True, True),
|
||||
('rg_track_gain', FLOAT_TYPE, True, True),
|
||||
('rg_track_peak', FLOAT_TYPE, True, True),
|
||||
('rg_album_gain', FLOAT_TYPE, True, True),
|
||||
('rg_album_peak', FLOAT_TYPE, True, True),
|
||||
('original_year', _padded_int(4), True, True),
|
||||
('original_month', _padded_int(2), True, True),
|
||||
('original_day', _padded_int(2), True, True),
|
||||
|
||||
('length', TYPES[float], False, True),
|
||||
('bitrate', TYPES[int], False, True),
|
||||
('format', TYPES[unicode], False, True),
|
||||
('samplerate', TYPES[int], False, True),
|
||||
('bitdepth', TYPES[int], False, True),
|
||||
('channels', TYPES[int], False, True),
|
||||
('mtime', TYPES[int], False, False),
|
||||
('added', TYPES[datetime], False, False),
|
||||
('length', FLOAT_TYPE, False, True),
|
||||
('bitrate', _scaled_int(u'kbps'), False, True),
|
||||
('format', STRING_TYPE, False, True),
|
||||
('samplerate', _scaled_int(u'kHz'), False, True),
|
||||
('bitdepth', INT_TYPE, False, True),
|
||||
('channels', INT_TYPE, False, True),
|
||||
('mtime', DATE_TYPE, False, False),
|
||||
('added', DATE_TYPE, False, False),
|
||||
]
|
||||
ITEM_KEYS_WRITABLE = [f[0] for f in ITEM_FIELDS if f[3] and f[2]]
|
||||
ITEM_KEYS_META = [f[0] for f in ITEM_FIELDS if f[3]]
|
||||
|
|
@ -167,39 +179,39 @@ ITEM_KEYS = [f[0] for f in ITEM_FIELDS]
|
|||
# The third entry in each tuple indicates whether the field reflects an
|
||||
# identically-named field in the items table.
|
||||
ALBUM_FIELDS = [
|
||||
('id', Type('INTEGER PRIMARY KEY', dbcore.query.NumericQuery), False),
|
||||
('artpath', PATH_TYPE, False),
|
||||
('added', TYPES[datetime], True),
|
||||
('id', ID_TYPE, False),
|
||||
('artpath', PATH_TYPE, False),
|
||||
('added', DATE_TYPE, True),
|
||||
|
||||
('albumartist', TYPES[unicode], True),
|
||||
('albumartist_sort', TYPES[unicode], True),
|
||||
('albumartist_credit', TYPES[unicode], True),
|
||||
('album', TYPES[unicode], True),
|
||||
('genre', TYPES[unicode], True),
|
||||
('year', TYPES[int], True),
|
||||
('month', TYPES[int], True),
|
||||
('day', TYPES[int], True),
|
||||
('tracktotal', TYPES[int], True),
|
||||
('disctotal', TYPES[int], True),
|
||||
('comp', TYPES[bool], True),
|
||||
('mb_albumid', TYPES[unicode], True),
|
||||
('mb_albumartistid', TYPES[unicode], True),
|
||||
('albumtype', TYPES[unicode], True),
|
||||
('label', TYPES[unicode], True),
|
||||
('mb_releasegroupid', TYPES[unicode], True),
|
||||
('asin', TYPES[unicode], True),
|
||||
('catalognum', TYPES[unicode], True),
|
||||
('script', TYPES[unicode], True),
|
||||
('language', TYPES[unicode], True),
|
||||
('country', TYPES[unicode], True),
|
||||
('albumstatus', TYPES[unicode], True),
|
||||
('media', TYPES[unicode], True),
|
||||
('albumdisambig', TYPES[unicode], True),
|
||||
('rg_album_gain', TYPES[float], True),
|
||||
('rg_album_peak', TYPES[float], True),
|
||||
('original_year', TYPES[int], True),
|
||||
('original_month', TYPES[int], True),
|
||||
('original_day', TYPES[int], True),
|
||||
('albumartist', STRING_TYPE, True),
|
||||
('albumartist_sort', STRING_TYPE, True),
|
||||
('albumartist_credit', STRING_TYPE, True),
|
||||
('album', STRING_TYPE, True),
|
||||
('genre', STRING_TYPE, True),
|
||||
('year', _padded_int(4), True),
|
||||
('month', _padded_int(2), True),
|
||||
('day', _padded_int(2), True),
|
||||
('tracktotal', _padded_int(2), True),
|
||||
('disctotal', _padded_int(2), True),
|
||||
('comp', BOOL_TYPE, True),
|
||||
('mb_albumid', STRING_TYPE, True),
|
||||
('mb_albumartistid', STRING_TYPE, True),
|
||||
('albumtype', STRING_TYPE, True),
|
||||
('label', STRING_TYPE, True),
|
||||
('mb_releasegroupid', STRING_TYPE, True),
|
||||
('asin', STRING_TYPE, True),
|
||||
('catalognum', STRING_TYPE, True),
|
||||
('script', STRING_TYPE, True),
|
||||
('language', STRING_TYPE, True),
|
||||
('country', STRING_TYPE, True),
|
||||
('albumstatus', STRING_TYPE, True),
|
||||
('media', STRING_TYPE, True),
|
||||
('albumdisambig', STRING_TYPE, True),
|
||||
('rg_album_gain', FLOAT_TYPE, True),
|
||||
('rg_album_peak', FLOAT_TYPE, True),
|
||||
('original_year', _padded_int(4), True),
|
||||
('original_month', _padded_int(2), True),
|
||||
('original_day', _padded_int(2), True),
|
||||
]
|
||||
ALBUM_KEYS = [f[0] for f in ALBUM_FIELDS]
|
||||
ALBUM_KEYS_ITEM = [f[0] for f in ALBUM_FIELDS if f[2]]
|
||||
|
|
|
|||
|
|
@ -25,8 +25,10 @@ from beets import dbcore
|
|||
# Fixture: concrete database and model classes. For migration tests, we
|
||||
# have multiple models with different numbers of fields.
|
||||
|
||||
ID_TYPE = dbcore.Type('INTEGER PRIMARY KEY', dbcore.query.NumericQuery)
|
||||
INT_TYPE = dbcore.Type('INTEGER', dbcore.query.NumericQuery)
|
||||
ID_TYPE = dbcore.Type('INTEGER PRIMARY KEY', dbcore.query.NumericQuery,
|
||||
unicode)
|
||||
INT_TYPE = dbcore.Type('INTEGER', dbcore.query.NumericQuery,
|
||||
unicode)
|
||||
|
||||
class TestModel1(dbcore.Model):
|
||||
_table = 'test'
|
||||
|
|
|
|||
Loading…
Reference in a new issue