mirror of
https://github.com/beetbox/beets.git
synced 2025-12-27 19:12:40 +01:00
Add Item.media_fields
This new property controls which fields to read from a media file.
This commit is contained in:
parent
c4f0928bf5
commit
3c7dd13b72
4 changed files with 28 additions and 20 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
Loading…
Reference in a new issue