def to_disc_metadata(self): from audiotools import MetaData return MetaData(album_name=self.get(u"TITLE", None), performer_name=self.get(u"PERFORMER", None), artist_name=self.get(u"SONGWRITER", None), composer_name=self.get(u"COMPOSER", None), comment=self.get(u"MESSAGE", None))
def delete_metadata(self): """deletes the track's MetaData this removes or unsets tags as necessary in order to remove all data raises IOError if unable to write the file""" from audiotools import MetaData self.set_metadata(MetaData())
def to_track_metadata(self): from audiotools import MetaData return MetaData( track_name=decode_string(self.get("TITLE", None)), performer_name=decode_string(self.get("PERFORMER", None)), artist_name=decode_string(self.get("SONGWRITER", None)), composer_name=decode_string(self.get("COMPOSER", None)), comment=decode_string(self.get("MESSAGE", None)), ISRC=decode_string(self.get("ISRC", None)))
def metadata(self): def get_track_metadata(track_node, album_metadata, track_number): try: #FIXME - not sure if name or sort-name should take precendence artist_name = get_xml_text_node( get_xml_nodes(track_node, u'artist')[0], u'name') except IndexError: artist_name = album_metadata.artist_name track_metadata = MetaData(track_name=get_xml_text_node( track_node, u'title'), artist_name=artist_name, track_number=track_number) track_metadata.merge(album_metadata) return track_metadata try: release = self.dom.getElementsByTagName(u'release')[0] except IndexError: return AlbumMetaData([]) album_name = get_xml_text_node(release, u'title') try: #FIXME - not sure if name or sort-name should take precendence artist_name = get_xml_text_node( get_xml_nodes(release, u'artist')[0], u'name') except IndexError: artist_name = u'' try: tracks = get_xml_nodes( get_xml_nodes(release, u'track-list')[0], u'track') except IndexError: tracks = [] album_metadata = MetaData(album_name=album_name, artist_name=artist_name, track_total=len(tracks)) try: release_events = get_xml_nodes(release, u'release-event-list')[0] event = get_xml_nodes(release_events, u'event')[-1] album_metadata.year = event.getAttribute('date')[0:4] album_metadata.catalog = event.getAttribute('catalog-number') except IndexError: pass return AlbumMetaData([ get_track_metadata(track_node=node, album_metadata=album_metadata, track_number=i + 1) for (i, node) in enumerate(tracks) ])
def delete_metadata(self): """deletes the track's MetaData raises IOError if unable to write the file""" if ((self.get_replay_gain() is not None) or (self.get_cuesheet() is not None)): # non-textual metadata is present and needs preserving self.set_metadata(MetaData()) else: # no non-textual metadata, so wipe out the entire block from os import access, R_OK, W_OK from audiotools.bitstream import BitstreamReader from audiotools import transfer_data if not access(self.filename, R_OK | W_OK): raise IOError(self.filename) with open(self.filename, "rb") as f: f.seek(-32, 2) (preamble, version, tag_size, item_count, read_only, item_encoding, is_header, no_footer, has_header) = BitstreamReader(f, True).parse( ApeTag.HEADER_FORMAT) if (preamble == b'APETAGEX') and (version == 2000): from audiotools import TemporaryFile from os.path import getsize # there's existing metadata to delete # so rewrite file without trailing metadata tag if has_header: old_tag_size = 32 + tag_size else: old_tag_size = tag_size # copy everything but the last "old_tag_size" bytes # from existing file to rewritten file new_apev2 = TemporaryFile(self.filename) old_apev2 = open(self.filename, "rb") limited_transfer_data( old_apev2.read, new_apev2.write, getsize(self.filename) - old_tag_size) old_apev2.close() new_apev2.close()
def delete_metadata(self): """deletes the track's MetaData this removes or unsets tags as necessary in order to remove all data raises IOError if unable to write the file""" from audiotools import MetaData # the vorbis comment packet is required, # so simply zero out its contents self.set_metadata(MetaData())
def from_cuesheet(cls, cuesheet, total_frames, sample_rate, metadata=None): if (metadata is None): metadata = MetaData() return cls.from_files([ DummyAudioFile(length=(pcm_frames * 75) / sample_rate, metadata=metadata, track_number=i + 1) for (i, pcm_frames) in enumerate(cuesheet.pcm_lengths(total_frames)) ])
def inject_metadata(self, format, version): """ audiotools.MetaData """ meta = MetaData() """ prepare metadata object """ # track-level metadata meta.track_name = self.name meta.track_number = self.tracknumber meta.media = 'DIGITAL' meta.isrc = self.isrc """ Needs fixing... for extra_artist in self.extra_artists.all(): print extra_artist meta.performer_name = meta.composer_name = meta.conductor_name = """ # release-level metadata if self.release: meta.album_name = self.release.name meta.catalog = self.release.catalognumber meta.track_total = len(self.release.media_release.all()) if self.release.releasedate: try: meta.year = str(self.release.releasedate.year) meta.date = str(self.release.releasedate) except Exception, e: print e try: cover_image = self.release.cover_image if self.release.cover_image else self.release.main_image if meta.supports_images() and cover_image: for i in meta.images(): meta.delete_image(i) opt = dict(size=(200, 200), crop=True, bw=False, quality=80) image = get_thumbnailer(cover_image).get_thumbnail(opt) meta.add_image(get_raw_image(image.path, 0)) except Exception, e: print e
def incect_metadata(self, path, media): log = logging.getLogger('util.process.Process.incect_metadata') log.debug('incect metadata to: %s' % (path)) log.debug('source: %s' % (media)) """ audiotools.MetaData """ meta = MetaData() """ prepare metadata object """ # track-level metadata meta.track_name = media.name meta.track_number = media.tracknumber meta.media = 'DIGITAL' meta.isrc = media.isrc meta.genre = 2 # release-level metadata if media.release: meta.album_name = media.release.name meta.catalog = media.release.catalognumber meta.track_total = len(media.release.media_release.all()) if media.release.releasedate: try: meta.year = str(media.release.releasedate.year) meta.date = str(media.release.releasedate) except Exception, e: print e try: cover_image = media.release.cover_image if media.release.cover_image else media.release.main_image if meta.supports_images() and cover_image: for i in meta.images(): meta.delete_image(i) opt = dict(size=(200, 200), crop=True, bw=False, quality=80) image = get_thumbnailer(cover_image).get_thumbnail(opt) meta.add_image(get_raw_image(image.path, 0)) except Exception, e: print e
def get_track_metadata(track_node, album_metadata, track_number): try: #FIXME - not sure if name or sort-name should take precendence artist_name = get_xml_text_node( get_xml_nodes(track_node, u'artist')[0], u'name') except IndexError: artist_name = album_metadata.artist_name track_metadata = MetaData(track_name=get_xml_text_node( track_node, u'title'), artist_name=artist_name, track_number=track_number) track_metadata.merge(album_metadata) return track_metadata
def get_metadata(self): """returns SheetTrack's MetaData, or None""" from audiotools import MetaData isrc = self.first_flag(TOCFlag_ISRC) cd_text = self.first_flag(CDText) if (isrc is not None) and (cd_text is not None): metadata = cd_text.to_track_metadata() metadata.ISRC = decode_string(isrc.isrc()) return metadata elif cd_text is not None: return cd_text.to_track_metadata() elif isrc is not None: return MetaData(ISRC=decode_string(isrc.isrc())) else: return None
def get_metadata(self): """returns MetaData of Sheet, or None this metadata often contains information such as catalog number or CD-TEXT values""" from audiotools import MetaData if (self.__catalog__ is not None) and (self.__cd_text__ is not None): metadata = self.__cd_text__.to_disc_metadata() metadata.catalog = self.__catalog__ return metadata elif self.__catalog__ is not None: return MetaData(catalog=self.__catalog__) elif self.__cd_text__ is not None: return self.__cd_text__.to_disc_metadata() else: return None
def set_cuesheet(self, cuesheet): import os.path import cue if (cuesheet is None): return metadata = self.get_metadata() if (metadata is None): metadata = WavePackAPEv2.converted(MetaData()) metadata['Cuesheet'] = WavePackAPEv2.ITEM.string( 'Cuesheet', cue.Cuesheet.file(cuesheet, os.path.basename(self.filename)).decode( 'ascii', 'replace')) self.set_metadata(metadata)
def xmcd_metadata(freedb_file): """given a dict of KEY->value unicode strings, yields a MetaData object per track""" import re TTITLE = re.compile(r'TTITLE(\d+)') dtitle = freedb_file.get("DTITLE", "") if (" / " in dtitle): (album_artist, album_name) = dtitle.split(" / ", 1) else: album_artist = None album_name = dtitle year = freedb_file.get("DYEAR", None) ttitles = [(int(m.group(1)), value) for (m, value) in [(TTITLE.match(key), value) for (key, value) in freedb_file.items()] if m is not None] if (len(ttitles) > 0): track_total = max([tracknum for (tracknum, ttitle) in ttitles]) + 1 else: track_total = 0 for (tracknum, ttitle) in sorted(ttitles, key=lambda t: t[0]): if (" / " in ttitle): (track_artist, track_name) = ttitle.split(" / ", 1) else: track_artist = album_artist track_name = ttitle from audiotools import MetaData yield MetaData( track_name=track_name.decode('utf-8', 'replace'), track_number=tracknum + 1, track_total=track_total, album_name=album_name.decode('utf-8', 'replace'), artist_name=(track_artist.decode('utf-8', 'replace') if track_artist is not None else None), year=(year.decode('utf-8', 'replace') if year is not None else None))
def get_metadata(self): """returns SheetTrack's MetaData, or None""" from operator import or_ from functools import reduce if (reduce(or_, [(attr is not None) for attr in [ self.__isrc__, self.__title__, self.__performer__, self.__songwriter__ ]], False)): from audiotools import MetaData return MetaData(ISRC=self.__isrc__, track_name=self.__title__, performer_name=self.__performer__, artist_name=self.__songwriter__) else: return None
def get_metadata(self): """returns MetaData of Sheet, or None this metadata often contains information such as catalog number or CD-TEXT values""" from operator import or_ from functools import reduce if (reduce(or_, [(attr is not None) for attr in [ self.__catalog__, self.__title__, self.__performer__, self.__songwriter__ ]], False)): from audiotools import MetaData return MetaData(catalog=self.__catalog__, album_name=self.__title__, performer_name=self.__performer__, artist_name=self.__songwriter__) else: return None
def set_cuesheet(self, cuesheet): """Imports cuesheet data from a Cuesheet-compatible object. This are objects with catalog(), ISRCs(), indexes(), and pcm_lengths() methods. Raises IOError if an error occurs setting the cuesheet.""" import os.path import cue if (cuesheet is None): return metadata = self.get_metadata() if (metadata is None): metadata = WavPackAPEv2.converted(MetaData()) metadata['Cuesheet'] = WavPackAPEv2.ITEM.string( 'Cuesheet', cue.Cuesheet.file(cuesheet, os.path.basename(self.filename)).decode( 'ascii', 'replace')) self.set_metadata(metadata)
def metadata(self): dtitle = self.get('DTITLE', u'') if (u' / ' in dtitle): (album_artist, album_name) = dtitle.split(u' / ', 1) else: (album_artist, album_name) = (dtitle, dtitle) dyear = self.get('DYEAR', u'') tracks = [] for key in self.keys(): if (key.startswith('TTITLE')): tracknum = self.key_digits(key) if (tracknum == -1): continue ttitle = self[key] if (u' / ' in ttitle): (track_artist, track_name) = ttitle.split(u' / ', 1) else: track_name = ttitle track_artist = album_artist tracks.append( MetaData(track_name=track_name, track_number=tracknum + 1, album_name=album_name, artist_name=track_artist, year=dyear)) track_total = max([t.track_number for t in tracks]) for t in tracks: t.track_total = track_total tracks.sort(lambda t1, t2: cmp(t1.track_number, t2.track_number)) return AlbumMetaData(tracks)
def parse_release(release, disc_id): """given a <release> Element node and DiscID object yields a populated MetaData object per track may raise KeyError if the given DiscID is not found in the <release>""" # <release> may contain <title> try: album_name = text(get_node(release, u"title")) except KeyError: album_name = None # <release> may contain <artist-credit> try: album_artist = artist(get_node(release, u"artist-credit")) except KeyError: album_artist = None # <release> may contain <label-info-list> try: # <label-info-list> contains 0 or more <label-info>s for label_info in get_nodes(get_node(release, u"label-info-list"), u"label-info"): # <label-info> may contain <catalog-number> try: catalog = text(get_node(label_info, u"catalog-number")) except KeyError: catalog = None # <label-info> may contain <label> # and <label> may contain <name> try: publisher = text(get_node(label_info, u"label", u"name")) except KeyError: publisher = None # we'll use the first result found break else: # <label-info-list> with no <label-info> tags catalog = None publisher = None except KeyError: catalog = None publisher = None # <release> may contain <date> try: year = text(get_node(release, u"date"))[0:4] except: year = None # find exact disc in <medium-list> tag # depending on disc_id value try: medium_list = get_node(release, u"medium-list") except KeyError: # no media found for disc ID raise KeyError(disc_id) for medium in get_nodes(medium_list, u"medium"): try: if (disc_id.__unicode__() in [disc.getAttribute(u"id") for disc in get_nodes(get_node(medium, u"disc-list"), u"disc")]): # found requested disc_id in <medium>'s list of <disc>s # so use that medium node to find additional info break except KeyError: # no <disc-list> tag found in <medium> continue else: # our disc_id wasn't found in any of the <release>'s <medium>s raise KeyError(disc_id) # if multiple discs in <medium-list>, # populate album number and album total if ((medium_list.hasAttribute(u"count") and (int(medium_list.getAttribute(u"count")) > 1))): album_total = int(medium_list.getAttribute(u"count")) try: album_number = int(text(get_node(medium, u"position"))) except KeyError: album_number = None else: album_total = album_number = None # <medium> must contain <track-list> tracks = get_nodes(get_node(medium, u"track-list"), u"track") track_total = len(tracks) # and <track-list> contains 0 or more <track>s for (i, track) in enumerate(tracks, 1): # if <track> contains title use that for track_name try: track_name = text(get_node(track, u"title")) except KeyError: track_name = None # if <track> contains <artist-credit> use that for track_artist try: track_artist = artist(get_node(release, u"artist-credit")) except KeyError: track_artist = None # if <track> contains a <recording> # use that for track_name and track artist try: recording = get_node(track, u"recording") # <recording> may contain a <title> if track_name is None: try: track_name = text(get_node(recording, u"title")) except KeyError: track_name = None # <recording> may contain <artist-credit> if track_artist is None: try: track_artist = artist(get_node(recording, u"artist-credit")) except KeyError: track_artist = album_artist except KeyError: # no <recording> in <track> if track_artist is None: track_artist = album_artist # <track> may contain a <position> try: track_number = int(text(get_node(track, u"position"))) except KeyError: track_number = i # yield complete MetaData object from audiotools import MetaData yield MetaData(track_name=track_name, track_number=track_number, track_total=track_total, album_name=album_name, artist_name=track_artist, performer_name=None, composer_name=None, conductor_name=None, ISRC=None, catalog=catalog, copyright=None, publisher=publisher, year=year, album_number=album_number, album_total=album_total, comment=None)