def _load(self, filename): log.debug("Loading file %r", filename) self.__casemap = {} file = self._File(encode_filename(filename)) metadata = Metadata() if file.tags: for origname, values in file.tags.items(): name_lower = origname.lower() if (values.kind == mutagen.apev2.BINARY and name_lower.startswith("cover art")): if b'\0' in values.value: descr, data = values.value.split(b'\0', 1) try: coverartimage = TagCoverArtImage( file=filename, tag=name_lower, data=data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.images.append(coverartimage) # skip EXTERNAL and BINARY values if values.kind != mutagen.apev2.TEXT: continue for value in values: name = name_lower if name == "year": name = "date" value = sanitize_date(value) elif name == "track": name = "tracknumber" track = value.split("/") if len(track) > 1: metadata["totaltracks"] = track[1] value = track[0] elif name == "disc": name = "discnumber" disc = value.split("/") if len(disc) > 1: metadata["totaldiscs"] = disc[1] value = disc[0] elif name == 'performer' or name == 'comment': name = name + ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name in self.__rtranslate: name = self.__rtranslate[name] self.__casemap[name] = origname metadata.add(name, value) self._info(metadata, file) return metadata
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == 'performer' or name == 'comment': # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name.startswith('rating'): try: name, email = name.split(':', 1) except ValueError: email = '' if email != self.config.setting['rating_user_email']: continue name = '~rating' value = unicode( int( round( (float(value) * (self.config.setting['rating_steps'] - 1))))) elif name == "fingerprint" and value.startswith( "MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal" and "totaltracks" not in file.tags: name = "totaltracks" elif name == "metadata_block_picture": image = mutagen.flac.Picture( base64.standard_b64decode(value)) metadata.add_image(image.mime, image.data) continue metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: metadata.add_image(image.mime, image.data) # Read the unofficial COVERART tags, for backward compatibillity only if not "metadata_block_picture" in file.tags: try: for index, data in enumerate(file["COVERART"]): metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data)) except KeyError: pass self._info(metadata, file) return metadata
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) metadata = Metadata() if file.tags: for origname, values in file.tags.items(): if origname.lower().startswith("cover art") and values.kind == mutagen.apev2.BINARY: if '\0' in values.value: descr, data = values.value.split('\0', 1) try: coverartimage = TagCoverArtImage( file=filename, tag=origname, data=data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) # skip EXTERNAL and BINARY values if values.kind != mutagen.apev2.TEXT: continue for value in values: name = origname if name == "Year": name = "date" value = sanitize_date(value) elif name == "Track": name = "tracknumber" track = value.split("/") if len(track) > 1: metadata["totaltracks"] = track[1] value = track[0] elif name == "Disc": name = "discnumber" disc = value.split("/") if len(disc) > 1: metadata["totaldiscs"] = disc[1] value = disc[0] elif name == 'Performer' or name == 'Comment': name = name.lower() + ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name in self.__translate: name = self.__translate[name] else: name = name.lower() metadata.add(name, value) self._info(metadata, file) return metadata
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == 'performer' or name == 'comment': # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name.startswith('rating'): try: name, email = name.split(':', 1) except ValueError: email = '' if email != self.config.setting['rating_user_email']: continue name = '~rating' value = unicode(int(round((float(value) * (self.config.setting['rating_steps'] - 1))))) elif name == "fingerprint" and value.startswith("MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal": if "totaltracks" in file.tags: continue name = "totaltracks" elif name == "disctotal": if "totaldiscs" in file.tags: continue name = "totaldiscs" elif name == "metadata_block_picture": image = mutagen.flac.Picture(base64.standard_b64decode(value)) metadata.add_image(image.mime, image.data) continue metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: metadata.add_image(image.mime, image.data) # Read the unofficial COVERART tags, for backward compatibillity only if not "metadata_block_picture" in file.tags: try: for index, data in enumerate(file["COVERART"]): metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data)) except KeyError: pass self._info(metadata, file) return metadata
def test_correct(self): self.assertEqual(util.sanitize_date("2006--"), "2006") self.assertEqual(util.sanitize_date("2006--02"), "2006") self.assertEqual(util.sanitize_date("2006 "), "2006") self.assertEqual(util.sanitize_date("2006 02"), "") self.assertEqual(util.sanitize_date("2006.02"), "") self.assertEqual(util.sanitize_date("2006-02"), "2006-02")
def test_correct(self): self.failUnlessEqual(util.sanitize_date("2006--"), "2006") self.failUnlessEqual(util.sanitize_date("2006--02"), "2006") self.failUnlessEqual(util.sanitize_date("2006 "), "2006") self.failUnlessEqual(util.sanitize_date("2006 02"), "") self.failUnlessEqual(util.sanitize_date("2006.02"), "") self.failUnlessEqual(util.sanitize_date("2006-02"), "2006-02")
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) metadata = Metadata() if file.tags: for origname, values in file.tags.items(): if origname.lower().startswith( "cover art") and values.kind == mutagen.apev2.BINARY: if '\0' in values.value: descr, data = values.value.split('\0', 1) mime = mimetype.get_from_data(data, descr, 'image/jpeg') metadata.add_image(mime, data) # skip EXTERNAL and BINARY values if values.kind != mutagen.apev2.TEXT: continue for value in values: name = origname if name == "Year": name = "date" value = sanitize_date(value) elif name == "Track": name = "tracknumber" track = value.split("/") if len(track) > 1: metadata["totaltracks"] = track[1] value = track[0] elif name == "Disc": name = "discnumber" disc = value.split("/") if len(disc) > 1: metadata["totaldiscs"] = disc[1] value = disc[0] elif name == 'Performer' or name == 'Comment': name = name.lower() + ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name in self.__translate: name = self.__translate[name] else: name = name.lower() metadata.add(name, value) self._info(metadata, file) return metadata
def _save(self, filename, metadata, settings): """Save metadata to the file.""" self.log.debug("Saving file %r", filename) file = self._File(encode_filename(filename)) if file.tags is None: file.add_tags() if settings["clear_existing_tags"]: file.tags.clear() if self._File == mutagen.flac.FLAC and ( settings["clear_existing_tags"] or (settings['save_images_to_tags'] and metadata.images)): file.clear_pictures() tags = {} for name, value in metadata.items(): if name == '~rating': # Save rating according to http://code.google.com/p/quodlibet/wiki/Specs_VorbisComments if settings['rating_user_email']: name = 'rating:%s' % settings['rating_user_email'] else: name = 'rating' value = unicode(float(value) / (settings['rating_steps'] - 1)) # don't save private tags elif name.startswith("~"): continue if name.startswith('lyrics:'): name = 'lyrics' elif name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name.startswith('performer:') or name.startswith('comment:'): # transform "performer:Piano=Joe Barr" to "performer=Joe Barr (Piano)" name, desc = name.split(':', 1) if desc: value += ' (%s)' % desc elif name == "musicip_fingerprint": name = "fingerprint" value = "MusicMagic Fingerprint%s" % value tags.setdefault(name.upper().encode('utf-8'), []).append(value) if "totaltracks" in metadata: tags.setdefault(u"TRACKTOTAL", []).append(metadata["totaltracks"]) if "totaldiscs" in metadata: tags.setdefault(u"DISCTOTAL", []).append(metadata["totaldiscs"]) if settings['save_images_to_tags']: for mime, data in metadata.images: image = mutagen.flac.Picture() image.type = 3 # Cover image image.data = data image.mime = mime if self._File == mutagen.flac.FLAC: file.add_picture(image) else: tags.setdefault(u"METADATA_BLOCK_PICTURE", []).append( base64.standard_b64encode(image.write())) file.tags.update(tags) kwargs = {} if self._File == mutagen.flac.FLAC and settings["remove_id3_from_flac"]: kwargs["deleteid3"] = True try: file.save(**kwargs) except TypeError: file.save()
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) is_flac = self._File == mutagen.flac.FLAC file = self._File(encode_filename(filename)) if file.tags is None: file.add_tags() if config.setting["clear_existing_tags"]: channel_mask = file.tags.get('waveformatextensible_channel_mask', None) file.tags.clear() if channel_mask: file.tags['waveformatextensible_channel_mask'] = channel_mask images_to_save = list(metadata.images.to_be_saved_to_tags()) if is_flac and (config.setting["clear_existing_tags"] or images_to_save): file.clear_pictures() tags = {} for name, value in metadata.items(): if name == '~rating': # Save rating according to http://code.google.com/p/quodlibet/wiki/Specs_VorbisComments user_email = sanitize_key(config.setting['rating_user_email']) if user_email: name = 'rating:%s' % user_email else: name = 'rating' value = str( float(value) / (config.setting['rating_steps'] - 1)) # don't save private tags elif name.startswith("~") or not self.supports_tag(name): continue elif name.startswith('lyrics:'): name = 'lyrics' elif name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name.startswith('performer:') or name.startswith('comment:'): # transform "performer:Piano=Joe Barr" to "performer=Joe Barr (Piano)" name, desc = name.split(':', 1) if desc: value += ' (%s)' % desc elif name == "musicip_fingerprint": name = "fingerprint" value = "MusicMagic Fingerprint%s" % value elif name in self.__rtranslate: name = self.__rtranslate[name] tags.setdefault(name.upper(), []).append(value) if "totaltracks" in metadata: tags.setdefault("TRACKTOTAL", []).append(metadata["totaltracks"]) if "totaldiscs" in metadata: tags.setdefault("DISCTOTAL", []).append(metadata["totaldiscs"]) for image in images_to_save: picture = mutagen.flac.Picture() picture.data = image.data picture.mime = image.mimetype picture.desc = image.comment picture.width = image.width picture.height = image.height picture.type = image_type_as_id3_num(image.maintype) if is_flac: # See https://xiph.org/flac/format.html#metadata_block_picture expected_block_size = (8 * 4 + len(picture.data) + len(picture.mime) + len(picture.desc.encode('UTF-8'))) if expected_block_size > FLAC_MAX_BLOCK_SIZE: log.error( 'Failed saving image to %r: Image size of %d bytes exceeds maximum FLAC block size of %d bytes', filename, expected_block_size, FLAC_MAX_BLOCK_SIZE) continue file.add_picture(picture) else: tags.setdefault("METADATA_BLOCK_PICTURE", []).append( base64.b64encode(picture.write()).decode('ascii')) file.tags.update(tags) self._remove_deleted_tags(metadata, file.tags) if is_flac: flac_sort_pics_after_tags(file.metadata_blocks) kwargs = {} if is_flac and config.setting["remove_id3_from_flac"]: kwargs["deleteid3"] = True try: file.save(**kwargs) except TypeError: file.save()
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename), ID3=compatid3.CompatID3) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith("T"): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == "COMM": for text in frame.text: if text: metadata.add("%s:%s" % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add("performer:%s" % role, name) elif frameid == "TIPL": # If file is ID3v2.3, TIPL tag could contain TMCL # so we will test for TMCL values and add to TIPL if not TMCL for role, name in frame.people: if role in self._tipl_roles and name: metadata.add(self._tipl_roles[role], name) else: metadata.add("performer:%s" % role, name) elif frameid == "TXXX": name = frame.desc if name in self.__translate_freetext: name = self.__translate_freetext[name] elif (name in self.__rtranslate) != (name in self.__rtranslate_freetext): # If the desc of a TXXX frame conflicts with the name of a # Picard tag, load it into ~id3:TXXX:desc rather than desc. # # This basically performs an XOR, making sure that 'name' # is in __rtranslate or __rtranslate_freetext, but not # both. (Being in both implies we support reading it both # ways.) Currently, the only tag in both is license. name = "~id3:TXXX:" + name for text in frame.text: metadata.add(name, unicode(text)) elif frameid == "USLT": name = "lyrics" if frame.desc: name += ":%s" % frame.desc metadata.add(name, unicode(frame.text)) elif frameid == "UFID" and frame.owner == "http://musicbrainz.org": metadata["musicbrainz_recordingid"] = frame.data.decode("ascii", "ignore") elif frameid == "TRCK": value = frame.text[0].split("/") if len(value) > 1: metadata["tracknumber"], metadata["totaltracks"] = value[:2] else: metadata["tracknumber"] = value[0] elif frameid == "TPOS": value = frame.text[0].split("/") if len(value) > 1: metadata["discnumber"], metadata["totaldiscs"] = value[:2] else: metadata["discnumber"] = value[0] elif frameid == "APIC": extras = {"desc": frame.desc, "type": image_type_from_id3_num(frame.type)} metadata.add_image(frame.mime, frame.data, extras=extras) elif frameid == "POPM": # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == config.setting["rating_user_email"]: rating = unicode(int(round(frame.rating / 255.0 * (config.setting["rating_steps"] - 1)))) metadata.add("~rating", rating) if "date" in metadata: sanitized = sanitize_date(metadata.getall("date")[0]) if sanitized: metadata["date"] = sanitized self._info(metadata, file) return metadata
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == "performer" or name == "comment": # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ":" if value.endswith(")"): start = len(value) - 2 count = 1 while count > 0 and start > 0: if value[start] == ")": count += 1 elif value[start] == "(": count -= 1 start -= 1 if start > 0: name += value[start + 2 : -1] value = value[:start] elif name.startswith("rating"): try: name, email = name.split(":", 1) except ValueError: email = "" if email != config.setting["rating_user_email"]: continue name = "~rating" value = unicode(int(round((float(value) * (config.setting["rating_steps"] - 1))))) elif name == "fingerprint" and value.startswith("MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal": if "totaltracks" in file.tags: continue name = "totaltracks" elif name == "disctotal": if "totaldiscs" in file.tags: continue name = "totaldiscs" elif name == "metadata_block_picture": image = mutagen.flac.Picture(base64.standard_b64decode(value)) imagetype = ID3_REVERSE_IMAGE_TYPE_MAP.get(image.type, "other") metadata.add_image(image.mime, image.data, description=image.desc, type_=imagetype) continue metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: imagetype = ID3_REVERSE_IMAGE_TYPE_MAP.get(image.type, "other") metadata.add_image(image.mime, image.data, description=image.desc, type_=imagetype) # Read the unofficial COVERART tags, for backward compatibillity only if not "metadata_block_picture" in file.tags: try: for index, data in enumerate(file["COVERART"]): metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data)) except KeyError: pass self._info(metadata, file) return metadata
def _load(self, filename): log.debug("Loading file %r", filename) file = self._get_file(encode_filename(filename)) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith('T') or frameid == 'GRP1': for text in frame.text: if text: metadata.add(name, string_(text)) elif frameid == 'COMM': for text in frame.text: if text: metadata.add('%s:%s' % (name, frame.desc), string_(text)) else: metadata.add(name, string_(frame)) elif frameid == 'TIT1': itunes_compatible = config.setting[ 'itunes_compatible_grouping'] name = 'work' if itunes_compatible else 'grouping' for text in frame.text: if text: metadata.add(name, string_(text)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add('performer:%s' % role, name) elif frameid == "TIPL": # If file is ID3v2.3, TIPL tag could contain TMCL # so we will test for TMCL values and add to TIPL if not TMCL for role, name in frame.people: if role in self._tipl_roles and name: metadata.add(self._tipl_roles[role], name) else: metadata.add('performer:%s' % role, name) elif frameid == 'TXXX': name = frame.desc if name in self.__translate_freetext: name = self.__translate_freetext[name] elif ((name in self.__rtranslate) != (name in self.__rtranslate_freetext)): # If the desc of a TXXX frame conflicts with the name of a # Picard tag, load it into ~id3:TXXX:desc rather than desc. # # This basically performs an XOR, making sure that 'name' # is in __rtranslate or __rtranslate_freetext, but not # both. (Being in both implies we support reading it both # ways.) Currently, the only tag in both is license. name = '~id3:TXXX:' + name for text in frame.text: metadata.add(name, string_(text)) elif frameid == 'USLT': name = 'lyrics' if frame.desc: name += ':%s' % frame.desc metadata.add(name, string_(frame.text)) elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org': metadata['musicbrainz_recordingid'] = frame.data.decode( 'ascii', 'ignore') elif frameid in self.__tag_re_parse.keys(): m = self.__tag_re_parse[frameid].search(frame.text[0]) if m: for name, value in m.groupdict().items(): if value is not None: metadata[name] = value else: log.error("Invalid %s value '%s' dropped in %r", frameid, frame.text[0], filename) elif frameid == 'APIC': try: coverartimage = TagCoverArtImage( file=filename, tag=frameid, types=types_from_id3(frame.type), comment=frame.desc, support_types=True, data=frame.data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) elif frameid == 'POPM': # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == config.setting['rating_user_email']: rating = string_( int( round(frame.rating / 255.0 * (config.setting['rating_steps'] - 1)))) metadata.add('~rating', rating) if 'date' in metadata: sanitized = sanitize_date(metadata.getall('date')[0]) if sanitized: metadata['date'] = sanitized self._info(metadata, file) return metadata
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename), ID3=compatid3.CompatID3) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith('T'): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == 'COMM': for text in frame.text: if text: metadata.add('%s:%s' % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add('performer:%s' % role, name) elif frameid == "TIPL": # If file is ID3v2.3, TIPL tag could contain TMCL # so we will test for TMCL values and add to TIPL if not TMCL for role, name in frame.people: if role in self._tipl_roles and name: metadata.add(self._tipl_roles[role], name) else: metadata.add('performer:%s' % role, name) elif frameid == 'TXXX': name = frame.desc if name in self.__translate_freetext: name = self.__translate_freetext[name] elif ((name in self.__rtranslate) != (name in self.__rtranslate_freetext)): # If the desc of a TXXX frame conflicts with the name of a # Picard tag, load it into ~id3:TXXX:desc rather than desc. # # This basically performs an XOR, making sure that 'name' # is in __rtranslate or __rtranslate_freetext, but not # both. (Being in both implies we support reading it both # ways.) Currently, the only tag in both is license. name = '~id3:TXXX:' + name for text in frame.text: metadata.add(name, unicode(text)) elif frameid == 'USLT': name = 'lyrics' if frame.desc: name += ':%s' % frame.desc metadata.add(name, unicode(frame.text)) elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org': metadata['musicbrainz_recordingid'] = frame.data.decode( 'ascii', 'ignore') elif frameid == 'TRCK': value = frame.text[0].split('/') if len(value) > 1: metadata['tracknumber'], metadata[ 'totaltracks'] = value[:2] else: metadata['tracknumber'] = value[0] elif frameid == 'TPOS': value = frame.text[0].split('/') if len(value) > 1: metadata['discnumber'], metadata['totaldiscs'] = value[:2] else: metadata['discnumber'] = value[0] elif frameid == 'APIC': extras = { 'desc': frame.desc, 'type': image_type_from_id3_num(frame.type) } metadata.add_image(frame.mime, frame.data, extras=extras) elif frameid == 'POPM': # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == config.setting['rating_user_email']: rating = unicode( int( round(frame.rating / 255.0 * (config.setting['rating_steps'] - 1)))) metadata.add('~rating', rating) if 'date' in metadata: sanitized = sanitize_date(metadata.getall('date')[0]) if sanitized: metadata['date'] = sanitized self._info(metadata, file) return metadata
def _load(self, filename): log.debug("Loading file %r", filename) file = self._get_file(encode_filename(filename)) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith('T'): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == 'COMM': for text in frame.text: if text: metadata.add('%s:%s' % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add('performer:%s' % role, name) elif frameid == "TIPL": # If file is ID3v2.3, TIPL tag could contain TMCL # so we will test for TMCL values and add to TIPL if not TMCL for role, name in frame.people: if role in self._tipl_roles and name: metadata.add(self._tipl_roles[role], name) else: metadata.add('performer:%s' % role, name) elif frameid == 'TXXX': name = frame.desc if name in self.__translate_freetext: name = self.__translate_freetext[name] elif ((name in self.__rtranslate) != (name in self.__rtranslate_freetext)): # If the desc of a TXXX frame conflicts with the name of a # Picard tag, load it into ~id3:TXXX:desc rather than desc. # # This basically performs an XOR, making sure that 'name' # is in __rtranslate or __rtranslate_freetext, but not # both. (Being in both implies we support reading it both # ways.) Currently, the only tag in both is license. name = '~id3:TXXX:' + name for text in frame.text: metadata.add(name, unicode(text)) elif frameid == 'USLT': name = 'lyrics' if frame.desc: name += ':%s' % frame.desc metadata.add(name, unicode(frame.text)) elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org': metadata['musicbrainz_recordingid'] = frame.data.decode('ascii', 'ignore') elif frameid in self.__tag_re_parse.keys(): m = self.__tag_re_parse[frameid].search(frame.text[0]) if m: for name, value in m.groupdict().iteritems(): if value is not None: metadata[name] = value else: log.error("Invalid %s value '%s' dropped in %r", frameid, frame.text[0], filename) elif frameid == 'APIC': try: coverartimage = TagCoverArtImage( file=filename, tag=frameid, types=types_from_id3(frame.type), comment=frame.desc, support_types=True, data=frame.data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) elif frameid == 'POPM': # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == config.setting['rating_user_email']: rating = unicode(int(round(frame.rating / 255.0 * (config.setting['rating_steps'] - 1)))) metadata.add('~rating', rating) if 'date' in metadata: sanitized = sanitize_date(metadata.getall('date')[0]) if sanitized: metadata['date'] = sanitized self._info(metadata, file) return metadata
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) is_flac = self._File == mutagen.flac.FLAC file = self._File(encode_filename(filename)) if file.tags is None: file.add_tags() if config.setting["clear_existing_tags"]: file.tags.clear() if (is_flac and (config.setting["clear_existing_tags"] or metadata.images_to_be_saved_to_tags)): file.clear_pictures() tags = {} for name, value in metadata.items(): if name == '~rating': # Save rating according to http://code.google.com/p/quodlibet/wiki/Specs_VorbisComments if config.setting['rating_user_email']: name = 'rating:%s' % config.setting['rating_user_email'] else: name = 'rating' value = string_( float(value) / (config.setting['rating_steps'] - 1)) # don't save private tags elif name.startswith("~"): continue elif name.startswith('lyrics:'): name = 'lyrics' elif name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name.startswith('performer:') or name.startswith('comment:'): # transform "performer:Piano=Joe Barr" to "performer=Joe Barr (Piano)" name, desc = name.split(':', 1) if desc: value += ' (%s)' % desc elif name == "musicip_fingerprint": name = "fingerprint" value = "MusicMagic Fingerprint%s" % value elif name in self.__rtranslate: name = self.__rtranslate[name] tags.setdefault(name.upper(), []).append(value) if "totaltracks" in metadata: tags.setdefault("TRACKTOTAL", []).append(metadata["totaltracks"]) if "totaldiscs" in metadata: tags.setdefault("DISCTOTAL", []).append(metadata["totaldiscs"]) for image in metadata.images_to_be_saved_to_tags: picture = mutagen.flac.Picture() picture.data = image.data picture.mime = image.mimetype picture.desc = image.comment picture.type = image_type_as_id3_num(image.maintype) if self._File == mutagen.flac.FLAC: file.add_picture(picture) else: tags.setdefault("METADATA_BLOCK_PICTURE", []).append( base64.b64encode(picture.write()).decode('ascii')) file.tags.update(tags) self._remove_deleted_tags(metadata, file.tags) kwargs = {} if is_flac and config.setting["remove_id3_from_flac"]: kwargs["deleteid3"] = True try: file.save(**kwargs) except TypeError: file.save()
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == 'performer' or name == 'comment': # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ':' if value.endswith(')'): start = len(value) - 2 count = 1 while count > 0 and start > 0: if value[start] == ')': count += 1 elif value[start] == '(': count -= 1 start -= 1 if start > 0: name += value[start + 2:-1] value = value[:start] elif name.startswith('rating'): try: name, email = name.split(':', 1) except ValueError: email = '' if email != config.setting['rating_user_email']: continue name = '~rating' value = unicode(int(round((float(value) * (config.setting['rating_steps'] - 1))))) elif name == "fingerprint" and value.startswith("MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal": if "totaltracks" in file.tags: continue name = "totaltracks" elif name == "disctotal": if "totaldiscs" in file.tags: continue name = "totaldiscs" elif name == "metadata_block_picture": image = mutagen.flac.Picture(base64.standard_b64decode(value)) try: coverartimage = TagCoverArtImage( file=filename, tag=name, types=types_from_id3(image.type), comment=image.desc, support_types=True, data=image.data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) continue elif name in self.__translate: name = self.__translate[name] metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: try: coverartimage = TagCoverArtImage( file=filename, tag='FLAC/PICTURE', types=types_from_id3(image.type), comment=image.desc, support_types=True, data=image.data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) # Read the unofficial COVERART tags, for backward compatibillity only if not "metadata_block_picture" in file.tags: try: for data in file["COVERART"]: try: coverartimage = TagCoverArtImage( file=filename, tag='COVERART', data=base64.standard_b64decode(data) ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) except KeyError: pass self._info(metadata, file) return metadata
def test_incorrect(self): self.failIfEqual(util.sanitize_date("2006--02"), "2006-02") self.failIfEqual(util.sanitize_date("2006.03.02"), "2006-03-02")
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename), ID3=compatid3.CompatID3) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith('T'): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == 'COMM': for text in frame.text: if text: metadata.add('%s:%s' % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add('performer:%s' % role, name) elif frameid == "TIPL": for role, name in frame.people: if role in self.__tipl_roles and name: metadata.add(self.__tipl_roles[role], name) elif frameid == 'TXXX' and frame.desc in self.__translate_freetext: name = self.__translate_freetext[frame.desc] for text in frame.text: metadata.add(name, unicode(text)) elif frameid == 'USLT': name = 'lyrics' if frame.desc: name += frame.desc metadata.add(name, unicode(frame.text)) elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org': metadata['musicbrainz_trackid'] = unicode(frame.data) elif frameid == 'TRCK': value = frame.text[0].split('/') if len(value) > 1: metadata['tracknumber'], metadata['totaltracks'] = value[:2] else: metadata['tracknumber'] = value[0] elif frameid == 'TPOS': value = frame.text[0].split('/') if len(value) > 1: metadata['discnumber'], metadata['totaldiscs'] = value[:2] else: metadata['discnumber'] = value[0] elif frameid == 'APIC': metadata.add_image(frame.mime, frame.data) elif frameid == 'POPM': # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == self.config.setting['rating_user_email']: rating = unicode(int(round(frame.rating / 255.0 * (self.config.setting['rating_steps'] - 1)))) metadata.add('~rating', rating) if 'date' in metadata: metadata['date'] = sanitize_date(metadata.getall('date')[0]) self._info(metadata, file) return metadata
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename), ID3=compatid3.CompatID3) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith('T'): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == 'COMM': for text in frame.text: if text: metadata.add('%s:%s' % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add('performer:%s' % role, name) elif frameid == "TIPL": for role, name in frame.people: if role in self.__tipl_roles and name: metadata.add(self.__tipl_roles[role], name) elif frameid == 'TXXX' and frame.desc in self.__translate_freetext: name = self.__translate_freetext[frame.desc] for text in frame.text: metadata.add(name, unicode(text)) elif frameid == 'USLT': name = 'lyrics' if frame.desc: name += frame.desc metadata.add(name, unicode(frame.text)) elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org': metadata['musicbrainz_trackid'] = unicode(frame.data) elif frameid == 'TRCK': value = frame.text[0].split('/') if len(value) > 1: metadata['tracknumber'], metadata[ 'totaltracks'] = value[:2] else: metadata['tracknumber'] = value[0] elif frameid == 'TPOS': value = frame.text[0].split('/') if len(value) > 1: metadata['discnumber'], metadata['totaldiscs'] = value[:2] else: metadata['discnumber'] = value[0] elif frameid == 'APIC': metadata.add_image(frame.mime, frame.data) elif frameid == 'POPM': # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == self.config.setting['rating_user_email']: rating = unicode( int( round(frame.rating / 255.0 * (self.config.setting['rating_steps'] - 1)))) metadata.add('~rating', rating) if 'date' in metadata: metadata['date'] = sanitize_date(metadata.getall('date')[0]) self._info(metadata, file) return metadata
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) file = self._File(encode_filename(filename)) if file.tags is None: file.add_tags() if config.setting["clear_existing_tags"]: file.tags.clear() if self._File == mutagen.flac.FLAC and ( config.setting["clear_existing_tags"] or (config.setting["save_images_to_tags"] and metadata.images) ): file.clear_pictures() tags = {} for name, value in metadata.items(): if name == "~rating": # Save rating according to http://code.google.com/p/quodlibet/wiki/Specs_VorbisComments if config.setting["rating_user_email"]: name = "rating:%s" % config.setting["rating_user_email"] else: name = "rating" value = unicode(float(value) / (config.setting["rating_steps"] - 1)) # don't save private tags elif name.startswith("~"): continue if name.startswith("lyrics:"): name = "lyrics" elif name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name.startswith("performer:") or name.startswith("comment:"): # transform "performer:Piano=Joe Barr" to "performer=Joe Barr (Piano)" name, desc = name.split(":", 1) if desc: value += " (%s)" % desc elif name == "musicip_fingerprint": name = "fingerprint" value = "MusicMagic Fingerprint%s" % value tags.setdefault(name.upper().encode("utf-8"), []).append(value) if "totaltracks" in metadata: tags.setdefault(u"TRACKTOTAL", []).append(metadata["totaltracks"]) if "totaldiscs" in metadata: tags.setdefault(u"DISCTOTAL", []).append(metadata["totaldiscs"]) if config.setting["save_images_to_tags"]: for image in metadata.images: if config.setting["save_only_front_images_to_tags"] and image["type"] != "front": continue picture = mutagen.flac.Picture() picture.data = image["data"] picture.mime = image["mime"] picture.desc = image["description"] picture.type = ID3_IMAGE_TYPE_MAP.get(image["type"], 0) if self._File == mutagen.flac.FLAC: file.add_picture(picture) else: tags.setdefault(u"METADATA_BLOCK_PICTURE", []).append(base64.standard_b64encode(picture.write())) file.tags.update(tags) kwargs = {} if self._File == mutagen.flac.FLAC and config.setting["remove_id3_from_flac"]: kwargs["deleteid3"] = True try: file.save(**kwargs) except TypeError: file.save()
def test_incorrect(self): self.assertNotEqual(util.sanitize_date("2006--02"), "2006-02") self.assertNotEqual(util.sanitize_date("2006.03.02"), "2006-03-02")
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == 'performer' or name == 'comment': # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ':' if value.endswith(')'): start = len(value) - 2 count = 1 while count > 0 and start > 0: if value[start] == ')': count += 1 elif value[start] == '(': count -= 1 start -= 1 if start > 0: name += value[start + 2:-1] value = value[:start] elif name.startswith('rating'): try: name, email = name.split(':', 1) except ValueError: email = '' if email != config.setting['rating_user_email']: continue name = '~rating' value = string_( int( round((float(value) * (config.setting['rating_steps'] - 1))))) elif name == "fingerprint" and value.startswith( "MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal": if "totaltracks" in file.tags: continue name = "totaltracks" elif name == "disctotal": if "totaldiscs" in file.tags: continue name = "totaldiscs" elif name == "metadata_block_picture": image = mutagen.flac.Picture( base64.standard_b64decode(value)) try: coverartimage = TagCoverArtImage( file=filename, tag=name, types=types_from_id3(image.type), comment=image.desc, support_types=True, data=image.data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) continue elif name in self.__translate: name = self.__translate[name] metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: try: coverartimage = TagCoverArtImage( file=filename, tag='FLAC/PICTURE', types=types_from_id3(image.type), comment=image.desc, support_types=True, data=image.data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) # Read the unofficial COVERART tags, for backward compatibillity only if "metadata_block_picture" not in file.tags: try: for data in file["COVERART"]: try: coverartimage = TagCoverArtImage( file=filename, tag='COVERART', data=base64.standard_b64decode(data)) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) except KeyError: pass self._info(metadata, file) return metadata
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) is_flac = self._File == mutagen.flac.FLAC file = self._File(encode_filename(filename)) if file.tags is None: file.add_tags() if config.setting["clear_existing_tags"]: channel_mask = file.tags.get('waveformatextensible_channel_mask', None) file.tags.clear() if channel_mask: file.tags['waveformatextensible_channel_mask'] = channel_mask if (is_flac and (config.setting["clear_existing_tags"] or metadata.images_to_be_saved_to_tags)): file.clear_pictures() tags = {} for name, value in metadata.items(): if name == '~rating': # Save rating according to http://code.google.com/p/quodlibet/wiki/Specs_VorbisComments if config.setting['rating_user_email']: name = 'rating:%s' % config.setting['rating_user_email'] else: name = 'rating' value = str(float(value) / (config.setting['rating_steps'] - 1)) # don't save private tags elif name.startswith("~") or not self.supports_tag(name): continue elif name.startswith('lyrics:'): name = 'lyrics' elif name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name.startswith('performer:') or name.startswith('comment:'): # transform "performer:Piano=Joe Barr" to "performer=Joe Barr (Piano)" name, desc = name.split(':', 1) if desc: value += ' (%s)' % desc elif name == "musicip_fingerprint": name = "fingerprint" value = "MusicMagic Fingerprint%s" % value elif name in self.__rtranslate: name = self.__rtranslate[name] tags.setdefault(name.upper(), []).append(value) if "totaltracks" in metadata: tags.setdefault("TRACKTOTAL", []).append(metadata["totaltracks"]) if "totaldiscs" in metadata: tags.setdefault("DISCTOTAL", []).append(metadata["totaldiscs"]) for image in metadata.images_to_be_saved_to_tags: picture = mutagen.flac.Picture() picture.data = image.data picture.mime = image.mimetype picture.desc = image.comment picture.type = image_type_as_id3_num(image.maintype) if self._File == mutagen.flac.FLAC: file.add_picture(picture) else: tags.setdefault("METADATA_BLOCK_PICTURE", []).append( base64.b64encode(picture.write()).decode('ascii')) file.tags.update(tags) self._remove_deleted_tags(metadata, file.tags) kwargs = {} if is_flac and config.setting["remove_id3_from_flac"]: kwargs["deleteid3"] = True try: file.save(**kwargs) except TypeError: file.save()
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename), ID3=compatid3.CompatID3) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith('T'): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == 'COMM': for text in frame.text: if text: metadata.add('%s:%s' % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add('performer:%s' % role, name) elif frameid == "TIPL": # If file is ID3v2.3, TIPL tag could contain TMCL # so we will test for TMCL values and add to TIPL if not TMCL for role, name in frame.people: if role in self._tipl_roles and name: metadata.add(self._tipl_roles[role], name) else: metadata.add('performer:%s' % role, name) elif frameid == 'TXXX': name = frame.desc if name in self.__translate_freetext: name = self.__translate_freetext[name] elif ((name in self.__rtranslate) != (name in self.__rtranslate_freetext)): # If the desc of a TXXX frame conflicts with the name of a # Picard tag, load it into ~id3:TXXX:desc rather than desc. # # This basically performs an XOR, making sure that 'name' # is in __rtranslate or __rtranslate_freetext, but not # both. (Being in both implies we support reading it both # ways.) Currently, the only tag in both is license. name = '~id3:TXXX:' + name for text in frame.text: metadata.add(name, unicode(text)) elif frameid == 'USLT': name = 'lyrics' if frame.desc: name += ':%s' % frame.desc metadata.add(name, unicode(frame.text)) elif frameid == 'UFID' and frame.owner == 'http://musicbrainz.org': metadata['musicbrainz_recordingid'] = frame.data.decode('ascii', 'ignore') elif frameid == 'TRCK': value = frame.text[0].split('/') if len(value) > 1: metadata['tracknumber'], metadata['totaltracks'] = value[:2] else: metadata['tracknumber'] = value[0] elif frameid == 'TPOS': value = frame.text[0].split('/') if len(value) > 1: metadata['discnumber'], metadata['totaldiscs'] = value[:2] else: metadata['discnumber'] = value[0] elif frameid == 'APIC': extras = { 'desc': frame.desc, 'type': image_type_from_id3_num(frame.type) } metadata.add_image(frame.mime, frame.data, extras=extras) elif frameid == 'POPM': # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == config.setting['rating_user_email']: rating = unicode(int(round(frame.rating / 255.0 * (config.setting['rating_steps'] - 1)))) metadata.add('~rating', rating) if 'date' in metadata: sanitized = sanitize_date(metadata.getall('date')[0]) if sanitized: metadata['date'] = sanitized self._info(metadata, file) return metadata
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename), ID3=compatid3.CompatID3) tags = file.tags or {} # upgrade custom 2.3 frames to 2.4 for old, new in self.__upgrade.items(): if old in tags and new not in tags: f = tags.pop(old) tags.add(getattr(id3, new)(encoding=f.encoding, text=f.text)) metadata = Metadata() for frame in tags.values(): frameid = frame.FrameID if frameid in self.__translate: name = self.__translate[frameid] if frameid.startswith("T"): for text in frame.text: if text: metadata.add(name, unicode(text)) elif frameid == "COMM": for text in frame.text: if text: metadata.add("%s:%s" % (name, frame.desc), unicode(text)) else: metadata.add(name, unicode(frame)) elif frameid == "TMCL": for role, name in frame.people: if role or name: metadata.add("performer:%s" % role, name) elif frameid == "TIPL": for role, name in frame.people: if role in self.__tipl_roles and name: metadata.add(self.__tipl_roles[role], name) elif frameid == "TXXX" and frame.desc in self.__translate_freetext: name = self.__translate_freetext[frame.desc] for text in frame.text: metadata.add(name, unicode(text)) elif frameid == "USLT": name = "lyrics" if frame.desc: name += frame.desc metadata.add(name, unicode(frame.text)) elif frameid == "UFID" and frame.owner == "http://musicbrainz.org": metadata["musicbrainz_trackid"] = unicode(frame.data) elif frameid == "TRCK": value = frame.text[0].split("/") if len(value) > 1: metadata["tracknumber"], metadata["totaltracks"] = value[:2] else: metadata["tracknumber"] = value[0] elif frameid == "TPOS": value = frame.text[0].split("/") if len(value) > 1: metadata["discnumber"], metadata["totaldiscs"] = value[:2] else: metadata["discnumber"] = value[0] elif frameid == "APIC": metadata.add_image(frame.mime, frame.data) elif frameid == "POPM": # Rating in ID3 ranges from 0 to 255, normalize this to the range 0 to 5 if frame.email == self.config.setting["rating_user_email"]: rating = unicode(int(round(frame.rating / 255.0 * (self.config.setting["rating_steps"] - 1)))) metadata.add("~rating", rating) if "date" in metadata: metadata["date"] = sanitize_date(metadata.getall("date")[0]) self._info(metadata, file) return metadata