PICARD-546,287: Add support for tag removal

This commit is contained in:
Sambhav Kothari
2016-12-16 21:29:36 +05:30
parent 572743fb6d
commit eddee11fa3
8 changed files with 168 additions and 8 deletions

View File

@@ -141,11 +141,13 @@ class File(QtCore.QObject, Item):
values = self.orig_metadata.getall(tag)
if values:
saved_metadata[tag] = values
deleted_tags = self.metadata.deleted_tags
self.metadata.copy(metadata)
self.metadata.deleted_tags = deleted_tags
for tag, values in saved_metadata.iteritems():
self.metadata.set(tag, values)
self.metadata["acoustid_id"] = acoustid
if acoustid:
self.metadata["acoustid_id"] = acoustid
def has_error(self):
return self.state == File.ERROR

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
from __future__ import absolute_import
import re
import mutagen.apev2
import mutagen.monkeysaudio
import mutagen.musepack
@@ -163,9 +164,44 @@ class APEv2File(File):
tags['Cover Art (Front)'] = mutagen.apev2.APEValue(cover_filename + '\0' + image.data, mutagen.apev2.BINARY)
break # can't save more than one item with the same name
# (mp3tags does this, but it's against the specs)
for tag in metadata.deleted_tags:
real_name = str(self._get_tag_name(tag))
if real_name in ('Lyrics','Comment','Performer'):
tag_type = "\(%s\)" % tag.split(':',1)[1]
for item in tags.get(real_name):
if re.search(tag_type,item):
tags.get(real_name).remove(item)
elif tag in ('totaltracks', 'totaldiscs'):
tagstr = real_name.lower() + 'number'
try:
tags[real_name] = metadata[tagstr]
except:
pass
else:
del tags[real_name]
tags.save(encode_filename(filename))
def _get_tag_name(self, name):
if name.startswith('lyrics:'):
return 'Lyrics'
elif name == 'date':
return 'Year'
elif name == ('tracknumber','totaltracks'):
return 'Track'
elif name == ('discnumber', 'totaldiscs'):
return 'Disc'
elif name.startswith('performer:') or name.startswith('comment:'):
return name.split(':',1)[0].title()
elif name in self.__rtranslate:
return self.__rtranslate[name]
else:
return name.title()
class MusepackFile(APEv2File):
"""Musepack file."""

View File

@@ -209,7 +209,30 @@ class ASFFile(File):
continue
name = self.__TRANS[name]
file.tags[name] = map(unicode, values)
for tag in metadata.deleted_tags:
real_name = self._get_tag_name(tag)
if real_name and real_name in file.tags:
if tag == 'totaldiscs':
try:
file.tags[real_name] = map(unicode,metadata['discnumber'])
except:
pass
else:
del file.tags[real_name]
file.save()
def supports_tag(self, name):
return name in self.__TRANS
def _get_tag_name(self, name):
if name.startswith('lyrics'):
return 'lyrics'
elif name == 'totaldiscs':
return self.__TRANS['discnumber']
else:
return self.__TRANS[name]

View File

@@ -397,6 +397,19 @@ class ID3File(File):
if tipl.people:
tags.add(tipl)
self._build_inverse_dic()
for tag in metadata.deleted_tags:
real_name = self._get_tag_name(tag)
log.debug(real_name)
log.debug(tag)
if real_name == 'POPM':
for key, frame in tags.items():
if frame.FrameID == 'POPM' and frame.email == config.setting['rating_user_email']:
del tags[key]
elif real_name in tags:
del tags[real_name]
self._save_tags(tags, encode_filename(filename))
if self._IsMP3 and config.setting["remove_ape_from_mp3"]:
@@ -404,6 +417,18 @@ class ID3File(File):
mutagen.apev2.delete(encode_filename(filename))
except:
pass
def _build_inverse_dic(self):
self.__itranslate = {}
for key, value in self.__translate.items():
self.__itranslate[value] = key
for key, value in self.__translate_freetext.items():
self.__itranslate[value] = key
def _get_tag_name(self,name):
if name in self.__itranslate:
return self.__itranslate[name]
elif name == '~rating':
return 'POPM'
def _get_file(self, filename):
raise NotImplementedError()

View File

@@ -210,6 +210,11 @@ class MP4File(File):
if covr:
file.tags["covr"] = covr
for tag in metadata.deleted_tags:
real_name = self._get_tag_name(tag)
if real_name and real_name in file.tags:
del file.tags[real_name]
file.save()
def supports_tag(self, name):
@@ -218,6 +223,26 @@ class MP4File(File):
or name in self.__other_supported_tags\
or name.startswith('lyrics:')
def _get_tag_name(self, name):
if name.startswith('lyrics:'):
return 'lyrics'
if name in self.__r_text_tags:
return self.__r_text_tags[name]
elif name in self.__r_bool_tags:
return self.__r_bool_tags[name]
elif name in self.__r_int_tags:
return self.__r_int_tags[name]
elif name in self.__r_freeform_tags:
return self.__r_freeform_tags[name]
elif name == "musicip_fingerprint":
return "----:com.apple.iTunes:fingerprint"
elif name == "tracknumber":
return "trkn"
elif name == "discnumber":
return "disk"
else:
return None
def _info(self, metadata, file):
super(MP4File, self)._info(metadata, file)
if hasattr(file.info, 'codec_description') and file.info.codec_description:

View File

@@ -18,6 +18,7 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import base64
import re
import mutagen.flac
import mutagen.ogg
import mutagen.oggflac
@@ -209,6 +210,17 @@ class VCommentFile(File):
base64.standard_b64encode(picture.write()))
file.tags.update(tags)
for tag in metadata.deleted_tags:
real_name = self._get_tag_name(tag)
if real_name and real_name in file.tags:
if real_name == 'performer' or real_name == 'comment':
tag_type = "\(%s\)" % tag.split(':',1)[1]
for item in file.tags.get(real_name):
if re.search(tag_type,item):
file.tags.get(real_name).remove(item)
else:
del file.tags[real_name]
kwargs = {}
if is_flac and config.setting["remove_id3_from_flac"]:
kwargs["deleteid3"] = True
@@ -217,6 +229,25 @@ class VCommentFile(File):
except TypeError:
file.save()
def _get_tag_name(self, name):
if name == '~rating':
if config.setting['rating_user_email']:
return 'rating:%s' % config.setting['rating_user_email']
else:
return 'rating'
elif name.startswith("~"):
return None
elif name.startswith('lyrics:'):
return 'lyrics'
elif name.startswith('performer:') or name.startswith('comment:'):
return name.split(':', 1)[0]
elif name == 'musicip_fingerprint':
return 'fingerprint'
elif name in self.__rtranslate:
return self.__rtranslate[name]
else:
return name
class FLACFile(VCommentFile):

View File

@@ -46,6 +46,7 @@ class Metadata(dict):
def __init__(self):
super(Metadata, self).__init__()
self.images = []
self.deleted_tags = set()
self.length = 0
def append_image(self, coverartimage):
@@ -222,11 +223,13 @@ class Metadata(dict):
self.images = other.images[:]
if other.length:
self.length = other.length
self.deleted_tags.update(other.deleted_tags)
def clear(self):
dict.clear(self)
self.images = []
self.length = 0
self.deleted_tags = set()
def getall(self, name):
return dict.get(self, name, [])
@@ -243,15 +246,17 @@ class Metadata(dict):
def set(self, name, values):
dict.__setitem__(self, name, values)
if name in self.deleted_tags:
self.deleted_tags.remove(name)
def __setitem__(self, name, values):
if not isinstance(values, list):
values = [values]
values = filter(None, map(unicode, values))
if len(values):
dict.__setitem__(self, name, values)
self.set(name, values)
else:
self.pop(name, None)
self.delete(name)
def add(self, name, value):
if value or value == 0:
@@ -261,6 +266,12 @@ class Metadata(dict):
if value not in self.getall(name):
self.add(name, value)
def delete(self, name):
if name in self:
self.pop(name, None)
self.deleted_tags.add(name)
def iteritems(self):
for name, values in dict.iteritems(self):
for value in values:

View File

@@ -111,16 +111,15 @@ class TagDiff(object):
else:
return orig != new
def add(self, tag, orig_values, new_values, removable):
def add(self, tag, orig_values, new_values, removable=False):
if orig_values:
self.orig.add(tag, orig_values)
if new_values:
self.new.add(tag, new_values)
if orig_values and not new_values:
if (orig_values and not new_values) or removed:
self.status[tag] |= TagStatus.Removed
removable = False
elif new_values and not orig_values:
self.status[tag] |= TagStatus.Added
removable = True
@@ -412,7 +411,8 @@ class MetadataBox(QtGui.QTableWidget):
new_values = list(orig_values or [""])
existing_tags.add(name)
tag_diff.add(name, orig_values, new_values, clear_existing_tags)
removed = name in new_metadata.deleted_tags
tag_diff.add(name, orig_values, new_values, True, removed)
tag_diff.add("~length",
str(orig_metadata.length), str(new_metadata.length), False)
@@ -491,6 +491,13 @@ class MetadataBox(QtGui.QTableWidget):
new_item.setFlags(orig_flags if length else new_flags)
self.set_item_value(new_item, self.tag_diff.new, name)
font = new_item.font()
if result.tag_status(name) == TagStatus.Removed:
font.setStrikeOut(True)
else:
font.setStrikeOut(False)
new_item.setFont(font)
color = self.colors.get(result.tag_status(name),
self.colors[TagStatus.NoChange])
orig_item.setForeground(color)