mirror of
https://github.com/beetbox/beets.git
synced 2025-12-24 01:25:47 +01:00
Delete tags from media files
This commit is contained in:
parent
9d9f1b539f
commit
663d91c4b2
2 changed files with 65 additions and 2 deletions
|
|
@ -342,8 +342,9 @@ class StorageStyle(object):
|
|||
describe more sophisticated translations or format-specific access
|
||||
strategies.
|
||||
|
||||
MediaFile uses a StorageStyle via two methods: ``get()`` and
|
||||
``set()``. It passes a Mutagen file object to each.
|
||||
MediaFile uses a StorageStyle via three methods: ``get()``,
|
||||
``set()``, and ``delete()``. It passes a Mutagen file object to
|
||||
each.
|
||||
|
||||
Internally, the StorageStyle implements ``get()`` and ``set()``
|
||||
using two steps that may be overridden by subtypes. To get a value,
|
||||
|
|
@ -447,6 +448,12 @@ class StorageStyle(object):
|
|||
|
||||
return value
|
||||
|
||||
def delete(self, mutagen_file):
|
||||
"""Remove the tag from the file.
|
||||
"""
|
||||
if self.key in mutagen_file:
|
||||
del mutagen_file[self.key]
|
||||
|
||||
|
||||
class ListStorageStyle(StorageStyle):
|
||||
"""Abstract storage style that provides access to lists.
|
||||
|
|
@ -572,6 +579,12 @@ class MP4TupleStorageStyle(MP4StorageStyle):
|
|||
items[self.index] = int(value)
|
||||
self.store(mutagen_file, items)
|
||||
|
||||
def delete(self, mutagen_file):
|
||||
if self.index == 0:
|
||||
super(MP4TupleStorageStyle, self).delete(mutagen_file)
|
||||
else:
|
||||
self.set(mutagen_file, None)
|
||||
|
||||
|
||||
class MP4ListStorageStyle(ListStorageStyle, MP4StorageStyle):
|
||||
pass
|
||||
|
|
@ -725,6 +738,15 @@ class MP3DescStorageStyle(MP3StorageStyle):
|
|||
except IndexError:
|
||||
return None
|
||||
|
||||
def delete(self, mutagen_file):
|
||||
frame = None
|
||||
for frame in mutagen_file.tags.getall(self.key):
|
||||
if frame.desc.lower() == self.description.lower():
|
||||
break
|
||||
if frame is not None:
|
||||
del mutagen_file[frame.HashKey]
|
||||
|
||||
|
||||
|
||||
class MP3SlashPackStorageStyle(MP3StorageStyle):
|
||||
"""Store value as part of pair that is serialized as a slash-
|
||||
|
|
@ -752,6 +774,12 @@ class MP3SlashPackStorageStyle(MP3StorageStyle):
|
|||
items.pop() # Do not store last value
|
||||
self.store(mutagen_file, '/'.join(map(unicode, items)))
|
||||
|
||||
def delete(self, mutagen_file):
|
||||
if self.pack_pos == 0:
|
||||
super(MP3SlashPackStorageStyle, self).delete(mutagen_file)
|
||||
else:
|
||||
self.set(mutagen_file, None)
|
||||
|
||||
|
||||
class MP3ImageStorageStyle(ListStorageStyle, MP3StorageStyle):
|
||||
"""Converts between APIC frames and ``Image`` instances.
|
||||
|
|
@ -943,6 +971,10 @@ class MediaField(object):
|
|||
value = self._none_value()
|
||||
for style in self.styles(mediafile.mgfile):
|
||||
style.set(mediafile.mgfile, value)
|
||||
|
||||
def __delete__(self, mediafile):
|
||||
for style in self.styles(mediafile.mgfile):
|
||||
style.delete(mediafile.mgfile)
|
||||
|
||||
def _none_value(self):
|
||||
"""Get an appropriate "null" value for this field's type. This
|
||||
|
|
@ -1083,6 +1115,9 @@ class DateItemField(MediaField):
|
|||
items[self.item_pos] = value
|
||||
self.date_field._set_date_tuple(mediafile, *items)
|
||||
|
||||
def __delete__(self, mediafile):
|
||||
self.__set__(mediafile, None)
|
||||
|
||||
|
||||
class CoverArtField(MediaField):
|
||||
"""A descriptor that provides access to the *raw image data* for the
|
||||
|
|
|
|||
|
|
@ -580,6 +580,34 @@ class ReadWriteTestBase(ArtTestMixin, GenreListTestMixin,
|
|||
self.assertEqual(mediafile.year, 0)
|
||||
self.assertEqual(mediafile.date, datetime.date.min)
|
||||
|
||||
def test_delete_tag(self):
|
||||
mediafile = self._mediafile_fixture('full')
|
||||
|
||||
keys = self.full_initial_tags.keys()
|
||||
keys.remove('art')
|
||||
for key in keys:
|
||||
self.assertIsNotNone(getattr(mediafile, key))
|
||||
delattr(mediafile, key)
|
||||
|
||||
mediafile.save()
|
||||
mediafile = MediaFile(mediafile.path)
|
||||
|
||||
# TODO Eventually the tags should have None values
|
||||
empty_tags = dict((k, v) for k, v in self.empty_tags.items()
|
||||
if k in keys)
|
||||
self.assertTags(mediafile, empty_tags)
|
||||
|
||||
def test_delete_packed_total(self):
|
||||
mediafile = self._mediafile_fixture('full')
|
||||
|
||||
delattr(mediafile, 'tracktotal')
|
||||
delattr(mediafile, 'disctotal')
|
||||
|
||||
mediafile.save()
|
||||
mediafile = MediaFile(mediafile.path)
|
||||
self.assertEqual(mediafile.track, self.full_initial_tags['track'])
|
||||
self.assertEqual(mediafile.disc, self.full_initial_tags['disc'])
|
||||
|
||||
def assertTags(self, mediafile, tags):
|
||||
errors = []
|
||||
for key, value in tags.items():
|
||||
|
|
|
|||
Loading…
Reference in a new issue