Add Item.media_fields

This new property controls which fields to read from a media file.
This commit is contained in:
Thomas Scholtes 2014-04-03 23:35:33 +02:00
parent c4f0928bf5
commit 3c7dd13b72
4 changed files with 28 additions and 20 deletions

View file

@ -186,7 +186,7 @@ ITEM_FIELDS = [
]
ITEM_KEYS = [f[0] for f in ITEM_FIELDS]
ITEM_KEYS_WRITABLE = set(MediaFile.fields()).intersection(ITEM_KEYS)
ITEM_KEYS_META = set(MediaFile.readable_fields()).intersection(ITEM_KEYS)
# Database fields for the "albums" table.
# The third entry in each tuple indicates whether the field reflects an
@ -333,6 +333,13 @@ class Item(LibModel):
_flex_table = 'item_attributes'
_search_fields = ITEM_DEFAULT_FIELDS
media_fields = set(MediaFile.readable_fields()).intersection(ITEM_KEYS)
"""Set of property names to read from ``MediaFile``.
``item.read()`` will read all properties in this set from
``MediaFile`` and set them on the item.
"""
@classmethod
def _getters(cls):
return plugins.item_field_getters()
@ -383,8 +390,11 @@ class Item(LibModel):
# Interaction with file metadata.
def read(self, read_path=None):
"""Read the metadata from the associated file. If read_path is
specified, read metadata from that file instead.
"""Read the metadata from the associated file.
If ``read_path`` is specified, read metadata from that file
instead. Updates all the properties in ``Item.media_fields``
from the media file.
Raises a `ReadError` if the file could not be read.
"""
@ -393,20 +403,19 @@ class Item(LibModel):
else:
read_path = normpath(read_path)
try:
f = MediaFile(syspath(read_path))
mediafile = MediaFile(syspath(read_path))
except (OSError, IOError) as exc:
raise ReadError(read_path, exc)
for key in list(ITEM_KEYS_META) + MediaFile.custom_fields:
value = getattr(f, key)
for key in list(self.media_fields):
value = getattr(mediafile, key)
if isinstance(value, (int, long)):
# Filter values wider than 64 bits (in signed
# representation). SQLite cannot store them.
# py26: Post transition, we can use:
# Filter values wider than 64 bits (in signed representation).
# SQLite cannot store them. py26: Post transition, we can use:
# value.bit_length() > 63
if abs(value) >= 2 ** 63:
value = 0
setattr(self, key, value)
self[key] = value
# Database's mtime should now reflect the on-disk value.
if read_path == self.path:
@ -417,6 +426,8 @@ class Item(LibModel):
def write(self):
"""Write the item's metadata to the associated file.
Updates the mediafile with properties from itself.
Can raise either a `ReadError` or a `WriteError`.
"""
try:

View file

@ -1276,8 +1276,6 @@ class MediaFile(object):
'channels', 'format']:
yield property
custom_fields = []
@classmethod
def add_field(cls, name, descriptor):
"""Add a field to store custom tags.
@ -1295,7 +1293,6 @@ class MediaFile(object):
if name in cls.__dict__:
raise ValueError(
u'property "{0}" already exists on MediaField'.format(name))
cls.custom_fields.append(name)
setattr(cls, name, descriptor)
def update(self, dict, id3v23=False):

View file

@ -923,7 +923,7 @@ def update_items(lib, query, album, move, pretend):
# Check for and display changes.
changed = ui.show_model_changes(item,
fields=library.ITEM_KEYS_META)
fields=library.Item.media_fields)
# Save changes.
if not pretend:

View file

@ -272,9 +272,8 @@ class ExtendedFieldTestMixin(object):
mediafile = MediaFile(mediafile.path)
self.assertEqual(mediafile.initialkey, 'F#')
delattr(MediaFile, 'initialkey')
MediaFile.custom_fields = []
def test_extended_attribute_from_item(self):
def test_write_extended_tag_from_item(self):
MediaFile.add_field('initialkey', field_extension)
mediafile = self._mediafile_fixture('empty')
@ -284,11 +283,12 @@ class ExtendedFieldTestMixin(object):
item.write()
mediafile = MediaFile(mediafile.path)
self.assertEqual(mediafile.initialkey, 'Gb')
delattr(MediaFile, 'initialkey')
MediaFile.custom_fields = []
def test_flexible_attribute_from_file(self):
delattr(MediaFile, 'initialkey')
def test_read_flexible_attribute_from_file(self):
MediaFile.add_field('initialkey', field_extension)
Item.media_fields.add('initialkey')
mediafile = self._mediafile_fixture('empty')
mediafile.update({'initialkey': 'F#'})
@ -297,7 +297,7 @@ class ExtendedFieldTestMixin(object):
self.assertEqual(item['initialkey'], 'F#')
delattr(MediaFile, 'initialkey')
MediaFile.custom_fields = []
Item.media_fields.remove('initialkey')
def test_invalid_descriptor(self):
with self.assertRaises(ValueError) as cm: