def _setTagsForMp3File(self, audioFileTags): ''' Sets the Mp3 file's tags to that of the AudioFileTags object given. ''' # Use the EasyId3 interface for setting the standard Mp3 tags mutagenInterface = EasyID3(self.audioFilepath) mutagenInterface['title'] = audioFileTags.title mutagenInterface['artist'] = audioFileTags.artist mutagenInterface['album'] = audioFileTags.album mutagenInterface['albumartist'] = audioFileTags.albumArtist mutagenInterface['genre'] = audioFileTags.genre mutagenInterface.save() # Use the ID3 interface for setting the nonstandard Mp3 tags mutagenInterface = ID3(self.audioFilepath, v2_version=3) mutagenInterface['TXXX:DATE_ALL_PLAYS'] = TXXX( 3, desc='DATE_ALL_PLAYS', text=audioFileTags.dateAllPlays) mutagenInterface['TXXX:DATE_LAST_PLAYED'] = TXXX( 3, desc='DATE_LAST_PLAYED', text=audioFileTags.dateLastPlayed) mutagenInterface['TXXX:PLAY_COUNT'] = TXXX( 3, desc='PLAY_COUNT', text=audioFileTags.playCount) mutagenInterface['TXXX:VOTES'] = TXXX(3, desc='VOTES', text=audioFileTags.votes) mutagenInterface['TXXX:RATING'] = TXXX(3, desc='RATING', text=audioFileTags.rating) mutagenInterface.save(v2_version=3)
def test_TXXX(self): from mutagen.id3 import TXXX self.assert_(isinstance(TXXX(desc='d', text='text'), TXXX)) frame = TXXX(encoding=0, desc="d", text=[]) self.assertEqual(frame.HashKey, "TXXX:d") frame._pprint()
def test_hash(self): frame = TXXX(encoding=0, desc="d", text=[]) self.assertEqual(frame.HashKey, "TXXX:d") frame._pprint() self.assertEquals(TXXX(text="a").HashKey, TXXX(text="b").HashKey) self.assertNotEquals(TXXX(desc="a").HashKey, TXXX(desc="b").HashKey)
def tagFoundButUnratedFile(srcCompleteFileName, toolName, toolOptions, foundNoRating, foundWithRating, foundWithUpperCaseRating): """ This method adds FMPS_RATING to all files given. It adds a default rating of 0.4 if no FMPS_RATING is found. In addition it computes POPM (e.g Windows Media Player) and RATING (e.g. xbmc) tags to files """ os.chdir(os.path.dirname(srcCompleteFileName)) f = taglib.File(srcCompleteFileName) mutID3 = ID3(srcCompleteFileName) logging.debug("working dir: " + os.getcwd()) rating = '0.4' if 'FMPS_RATING' in f.tags: logging.debug("Rating with wrong case set for " + srcCompleteFileName) rating = f.tags['FMPS_RATING'][0] logging.debug(str(f.tags['FMPS_RATING']) + str(f.tags)) new_entry = { 'srcCompleteFileName': srcCompleteFileName, 'TAGS': f.tags } foundWithUpperCaseRating.append(new_entry) # pytaglib can only write tags in uppercase so these 2 lines below do not work del f.tags['FMPS_RATING'] mutID3.delall('TXXX:FMPS_RATING') mutID3.add(TXXX(encoding=3, desc='FMPS_Rating', text=rating)) # add xbmcratings see http://kodi.wiki/view/Adding_music_to_the_library#Ratings_in_ID3_tags elif 'FMPS_Rating' in f.tags: logging.debug("Rating set for " + srcCompleteFileName) logging.debug(str(f.tags['FMPS_Rating']) + str(f.tags)) foundWithRating.append(new_entry) rating = f.tags['FMPS_Rating'][0] else: logging.debug("No Rating set for " + srcCompleteFileName) new_entry = { 'srcCompleteFileName': srcCompleteFileName, 'TAGS': f.tags } foundNoRating.append(new_entry) mutID3.add(TXXX(encoding=3, desc='FMPS_Rating', text=u'0.4')) xbmc_rating = math.trunc(float(rating) * 5) mutID3.add(TXXX(encoding=3, desc='RATING', text=str(xbmc_rating))) popm_rating = math.trunc(float(rating) * 255) mutID3.add(POPM(rating=popm_rating)) MP3CARidx = srcCompleteFileName.find('MP3CAR') szCarDir = srcCompleteFileName[MP3CARidx - 3:MP3CARidx] mutID3.add(TXXX(encoding=3, desc='SZ_CarDir', text=szCarDir)) #f.tags['SZ_CarDir']=szCarDir mutID3.save()
def write2tag(tag, lyric): ''' :param tag: object created by 'ID3(file)' ''' arr = parse_synced_lyric(lyric) if len(arr) > 0: #synced lyric """ 'SYLT' is not displayed. if len(tag.getall('SYLT'))>0: tag.delall('SYLT') tag.add( SYLT(encoding=3,lang=u'eng',desc=u'desc', format=2, #time format=mill seconds type=1, #type=lyric text=arr #[(text of lyric,start_time)] ) ) """ if len(tag.getall('TXXX:LIRICS')) > 0: tag.delall('TXXX:LIRICS') tag.add(TXXX(encoding=3, desc='LYRICS', text=[lyric])) else: #save tag to unsynced lyric if len(tag.getall('USLT')) > 0: tag.delall('USLT') tag.add(USLT(encoding=3, lang='eng', desc='desc', text=lyric)) try: tag.save() except Exception as e: msg = "error at saving mp3.:" + str(e) print(msg) logging.error(msg)
def ok_pressed(): try: tags = ID3(_dir + "/" + __dir) except: print("Adding ID3 header;") tags = ID3() tags['TRCK'] = TRCK(encoding=3, text=edit_entry_list[TRACK_ID].get()) tags['TIT2'] = TIT2(encoding=3, text=edit_entry_list[TITLE_ID].get()) tags['TPE1'] = TPE1(encoding=3, text=edit_entry_list[ARTIST_ID].get()) tags['TALB'] = TALB(encoding=3, text=edit_entry_list[ALBUM_ID].get()) tags['TDRC'] = TDRC(encoding=3, text=edit_entry_list[YEAR_ID].get()) tags['TCOM'] = TCOM(encoding=3, text=edit_entry_list[COMPOSER_ID].get()) tags['TEXT'] = TEXT(encoding=3, text=edit_entry_list[LYRICIST_ID].get()) tags['TXXX:PERFORMER'] = TXXX(encoding=3, desc='PERFORMER', text=edit_entry_list[PERFORMER_ID].get()) try: tags.save(_dir + "/" + __dir) except: print("denied") new_val = list(tree.item(right_row)['values']) for in_id in edit_id: if new_val[in_id] != edit_entry_list[in_id].get(): new_val[in_id] = edit_entry_list[in_id].get() tree.item(right_row, values=new_val) win.destroy()
def setID3Tag(self, tag, tagVal): if self.tagsID3 is None: self.findID3Tags() if self.tagsID3 is None: if self.debug: print("Could not set ID3 tag because tags are None") return if tag == "TXXX": try: self.tagsID3.add(TXXX(encoding=3, text=tagVal)) except: raise ValueError( "Could not set ID3 tag [{0}] to [{1}] for [{2}]".format( tag, tagVal, self.mp3)) else: try: self.tagsID3.getall(tag)[0].text[0] = tagVal except: raise ValueError( "Could not set ID3 tag [{0}] to [{1}] for [{2}]".format( tag, tagVal, self.mp3)) if self.test is True: print("Not saving because test flag is True") else: try: self.tagsID3.save() except: raise ValueError("Could not save ID3 tags to {0}".format( self.mp3))
def add_mp3_tags(fileobj, tags, cover=None, lyrics=None, image_mimetype='image/png'): handle = MP3(fileobj=fileobj) if 'artist' in tags: handle['TPE1'] = TPE1(text=tags['artist']) if 'title' in tags: handle['TIT2'] = TIT2(text=tags['title']) if 'album' in tags: handle['TALB'] = TALB(text=tags['album']) if 'albumartist' in tags: handle['TPE2'] = TPE2(text=tags['albumartist']) if 'genre' in tags: handle['TCON'] = TCON(genres=[tags['genre']]) if 'tracknumber' in tags: handle['TRCK'] = TRCK(text=tags['tracknumber']) if 'year' in tags: handle['TYER'] = TYER(text=tags['year']) if 'date' in tags: handle['TDAT'] = TDAT(text=tags['date']) if 'bpm' in tags: handle['TBPM'] = TBPM(text=tags['bpm']) if 'isrc' in tags: handle['TSRC'] = TSRC(text=tags['isrc']) if 'explicit' in tags: handle['TXXX'] = TXXX(text=tags['explicit']) if lyrics: handle['USLT'] = USLT(text=lyrics) if cover: handle['APIC'] = APIC(data=cover, mime=image_mimetype) handle.save(fileobj) fileobj.seek(0)
def testMutagen(logging, srcCompleteFileName): audio = MP3(srcCompleteFileName, ID3=EasyID3) logging.debug(audio.pprint()) # MPEG 1 layer 3, 160000 bps, 44100 Hz, 270.63 seconds (audio/mp3) # album=Odyssey # artist=Yngwie J. Malmsteen's Rising Force # date=1988 # genre=Hard Rock # length=270628 # media=DIG # title=Faster Than The Speed Of Light # tracknumber=10/12 audio2 = ID3(srcCompleteFileName) # {'TALB': TALB(encoding=3, text=['Odyssey']), # 'TMED': TMED(encoding=0, text=['DIG']), # 'TXXX:SZ_CARDIR': TXXX(encoding=3, desc='SZ_CARDIR', text=['001']), # 'TDRC': TDRC(encoding=3, text=['1988']), # 'TLEN': TLEN(encoding=0, text=['270628']), # 'TCON': TCON(encoding=3, text=['Hard Rock']), # 'TXXX:FMPS_RATING': TXXX(encoding=3, desc='FMPS_RATING', text=['0.4']), # 'TIT2': TIT2(encoding=3, text=['Faster Than The Speed Of Light']), # 'TPE1': TPE1(encoding=3, text=["Yngwie J. Malmsteen's Rising Force"]), # 'TRCK': TRCK(encoding=3, text=['10/12']) } #audio.add(TIT2(encoding=3, text=u"An example")) audio2.add(TXXX(encoding=3, desc='FMPS_Rating', text=u'0.4')) audio2.save() logging.info(audio2)
def tag(self, flac_filename, mp3_filename): flac = FLAC(flac_filename) id3 = ID3() involved_people = [] for tag, value in flac.iteritems(): if tag in self.tag_map: id3.add(self.tag_map[tag](encoding=3, text=value)) elif tag in self.text_tag_map: id3.add( TXXX(encoding=3, desc=self.text_tag_map[tag], text=value)) elif tag == 'tracknumber': value[0] += self._total(flac, ['tracktotal', 'totaltracks']) id3.add(TRCK(encoding=3, text=value)) elif tag == 'discnumber': value[0] += self._total(flac, ['disctotal', 'totaldiscs']) id3.add(TPOS(encoding=3, text=value)) elif tag == 'musicbrainz_trackid': id3.add(UFID(u'http://musicbrainz.org', value[0])) elif tag in ('producer', 'engineer', 'arranger'): involved_people.extend((unicode(tag), v) for v in value) elif tag == 'mixer': involved_people.extend((u'mix', v) for v in value) elif tag == 'performer': id3.add(TMCL(encoding=3, people=self._performers(value))) elif tag not in [ 'tracktotal', 'totaltracks', 'disctotal', 'totaldiscs', 'replaygain_album_gain', 'replaygain_album_peak', 'replaygain_track_gain', 'replaygain_track_peak', # Don't know what to do with reference loudness - ignore it 'replaygain_reference_loudness', # No mapping for mp3 - https://picard.musicbrainz.org/docs/mappings/ 'originalyear', # Drop CDDB disc id 'discid' ]: raise UnknownTag("%s=%s" % (tag, value)) if involved_people: id3.add(TIPL(encoding=3, people=involved_people)) self._replaygain(flac, id3, 'album') self._replaygain(flac, id3, 'track') for pic in flac.pictures: tag = APIC(encoding=3, mime=pic.mime, type=pic.type, desc=pic.desc, data=pic.data) id3.add(tag) id3.save(mp3_filename)
def _copy_replaygain_tag(self, ape, id3, tag_name, converter): if callable(converter): try: value = converter(str(ape[tag_name])) except ValueError: raise else: value = str(ape[tag_name]) id3.add(TXXX(encoding=Id3Encoding.UTF8, desc=tag_name, text=value))
def writemd5(self): if self.fname and self.fsum: try: mp3 = ID3(self.fname) mp3.add(TXXX(encoding=3, desc=u'MD5', text=[self.fsum])) mp3.save() except mutagen.id3.ID3NoHeaderError: print "No Header Error: %s" % self.fname pass except IOError: print "Couldn't write header." pass
def syncMP3Ratings(mutID3, newFMPSRating): """ This method resyncs FMPS_RATING to all files given. It resyncs POPM (e.g Windows Media Player) and RATING (e.g. xbmc) tags to files it is given that FMPS_RATING is set """ changedTag = False newPopmRating = math.trunc(newFMPSRating * 255) try: curPOPMRating = mutID3.getall('POPM')[0].rating if curPOPMRating != newPopmRating: mutID3.delall('POPM') mutID3.add(POPM(rating=newPopmRating)) changedTag = True else: logging.debug("POPM tag found and already synced: ") except (KeyError, IndexError) as e: logging.debug('POPM rating did not exist: adding ... it') mutID3.add(POPM(rating=newPopmRating)) changedTag = True # handle RATING newRATING = math.trunc(newFMPSRating * 5) try: curRATINGStr = mutID3.getall('TXXX:RATING')[0].text[0] curRATING = float(curRATINGStr) if curRATING != newRATING: mutID3.add(TXXX(encoding=3, desc='RATING', text=str(newRATING))) changedTag = True else: logging.debug("RATING found and already synced: ") except (KeyError, IndexError) as e: logging.debug('RATING rating did not exist: adding ... it') mutID3.add(TXXX(encoding=3, desc='RATING', text=str(newRATING))) changedTag = True if changedTag: mutID3.save()
def copy_replaygain_tag(self, apev2, id3, name, converter=None): self.log.debug("processing '%s' tag" % name) if name not in apev2: self.log.info("no APEv2 '%s' tag found, skipping tag" % name) return False if not self.force and ("TXXX:%s" % name) in id3: self.log.info("ID3 '%s' tag already exists, skpping tag" % name) return False value = str(apev2[name]) if callable(converter): self.log.debug("converting APEv2 '%s' tag from '%s'" % (name, value)) try: value = converter(value) except ValueError: self.log.warning("invalid value for APEv2 '%s' tag" % name) return False self.log.debug("converted APEv2 '%s' tag to '%s'" % (name, value)) id3.add(TXXX(encoding=1, desc=name, text=value)) self.log.info("added ID3 '%s' tag with value '%s'" % (name, value)) return True
def setRatingForFiles(filesToProcessDict, newFMPSRating): for curFile in filesToProcessDict: logging.info("set rating for " + curFile['srcCompleteFileName'] + " to " + str(newFMPSRating)) mutID3 = ID3(curFile['srcCompleteFileName']) changedTag = False curFMPSRating = mutID3.get(u'TXXX:FMPS_Rating') if curFMPSRating == None: # No existing tag TXXX for FMPS has been found, so create one... logging.debug("no FMPS_RATING found: " + os.path.basename(curFile['srcCompleteFileName'])) mutID3.add( TXXX(encoding=3, desc=u"FMPS_Rating", text=[str(newFMPSRating)])) changedTag = True else: newFMPSRating = float(curFMPSRating[0]) syncMP3Ratings(mutID3, newFMPSRating) if changedTag: mutID3.save()
def metadata_mp3_mutagen(self, path, media): from mutagen.mp3 import MP3 from mutagen.id3 import ID3, TRCK, TIT2, TPE1, TALB, TCON, TXXX, UFID, TSRC, TPUB, TMED, TRCK, TDRC, APIC try: tags = ID3(path) except Exception: """ kindf of hackish - mutagen does complain if no id3 headers - so just create some """ audio = MP3(path) audio["TIT2"] = TIT2(encoding=3, text=["Empty Title"]) audio.save() tags = ID3(path) # reset tags tags.delete() # user data if INCLUDE_USER and self.user: tags.add( TXXX(encoding=3, desc='open broadcast user', text=u'%s' % self.user.email)) # track-level metadata tags.add(TIT2(encoding=3, text=u'%s' % media.name)) tags.add( UFID(encoding=3, owner='https://openbroadcast.org', data=u'%s' % media.uuid)) tags.add( TXXX(encoding=3, desc='open broadcast API', text=u'https://%s%s' % (self.current_site.domain, media.get_api_url()))) # remove genre tags.add(TCON(encoding=3, text=u'')) tags.add(TMED(encoding=3, text=u'Digital Media')) if media.tracknumber: tags.add(TRCK(encoding=3, text=u'%s' % media.tracknumber)) if media.isrc: tags.add(TSRC(encoding=3, text=u'%s' % media.isrc)) if uuid_by_object(media, 'musicbrainz'): tags.add( UFID(encoding=3, owner='http://musicbrainz.org', data=u'%s' % uuid_by_object(media, 'musicbrainz'))) # release-level metadata if media.release: tags.add(TALB(encoding=3, text=u'%s' % media.release.name)) if media.release.catalognumber: tags.add( TXXX(encoding=3, desc='CATALOGNUMBER', text=u'%s' % media.release.catalognumber)) if media.release.releasedate: tags.add( TDRC(encoding=3, text=u'%s' % media.release.releasedate.year)) if media.release.release_country: tags.add( TXXX(encoding=3, desc='MusicBrainz Album Release Country', text=u'%s' % media.release.release_country.iso2_code)) if media.release.totaltracks and media.tracknumber: tags.add( TRCK(encoding=3, text=u'%s/%s' % (media.tracknumber, media.release.totaltracks))) if media.release.releasedate: tags.add( TDRC(encoding=3, text=u'%s' % media.release.releasedate.year)) if uuid_by_object(media.release, 'musicbrainz'): tags.add( TXXX(encoding=3, desc='MusicBrainz Album Id', text=u'%s' % uuid_by_object(media.release, 'musicbrainz'))) if media.release and media.release.main_image and os.path.exists( media.release.main_image.path): opt = dict(size=(300, 300), crop=True, bw=False, quality=80) try: image = get_thumbnailer( media.release.main_image).get_thumbnail(opt) tags.add( APIC(encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=open(image.path).read())) except: pass # artist-level metadata if media.artist: tags.add(TPE1(encoding=3, text=u'%s' % media.artist.name)) if uuid_by_object(media.artist, 'musicbrainz'): tags.add( TXXX(encoding=3, desc='MusicBrainz Artist Id', text=u'%s' % uuid_by_object(media.artist, 'musicbrainz'))) # label-level metadata if media.release and media.release.label: tags.add(TPUB(encoding=3, text=u'%s' % media.release.label.name)) tags.save(v1=0) return
def _save_db_to_id3v2(self, pathSong, dbrating, dbcount): """ Save rating and playcount from Rhythmbox db to standard ID3v2 tags POPM stand for Popularimeter, we use Banshee ratings standard (which is also an ID3v2 standard, meaning a value between 0 and 255). (should eventually be deprecated) (see http://www.id3.org/id3v2.4.0-frames section 4.16 ) TXXX:FMPS_Rating and TXXX:FMPS_Playcount are from the FMPS freedesktop specs (see http://www.freedesktop.org/wiki/Specifications/free-media-player-specs) """ audio = ID3(pathSong) # Instead of having two I/O operations each time, # we can get only one I/O operation when rating AND playcount haven't changed # We use needsave boolean to do that needsave = False if self.ratingsenabled: if dbrating > 0: # First we store it in POPM format ########### POPM (will be deprecated eventually) ####### popmrating = audio.get('POPM:Banshee') if popmrating == None: # No existing tag POPM has been found, so create one... audio.add(POPM(email=u'Banshee', rating=int(51 * dbrating))) needsave = True else: # An existing tag POPM has been found, let's check if the rating has changed if self._convert_ID3v2_rating_to_rhythmbdb_rating( popmrating.rating) != dbrating: # If it has, erase the value of the file an replace it with the db value (converted) audio.delall('POPM:Banshee') audio.add( POPM(email=u'Banshee', rating=int(51 * dbrating))) needsave = True #################################################### ############# TXXX ################################# fmpsrating = audio.get(u'TXXX:FMPS_Rating') if fmpsrating == None: # No existing tag TXXX for FMPS has been found, so create one... audio.add( TXXX(encoding=3, desc=u"FMPS_Rating", text=[unicode(0.2 * dbrating)])) needsave = True else: # An existing tag TXXX for FMPS has been found, let's check if the rating has changed if self._convert_fmps_rating_to_rhythmbdb_rating( fmpsrating.text[0]) != dbrating: # If it has, erase the value of the file and replace it with the db value (converted) audio.delall(u'TXXX:FMPS_Rating') audio.add( TXXX(encoding=3, desc=u"FMPS_Rating", text=[unicode(0.2 * dbrating)])) needsave = True ####################################################### if self.playcountsenabled: if dbcount > 0: ######### TXXX ############ fmpsplaycount = audio.get(u'TXXX:FMPS_Playcount') if fmpsplaycount == None: # No existing tag TXXX for FMPS has been found, so create one... audio.add( TXXX(encoding=3, desc=u"FMPS_Playcount", text=[unicode(1.0 * dbcount)])) needsave = True else: # An existing tag TXXX for FMPS has been found, let's check if the playcount has changed if float(fmpsplaycount.text[0]) != dbcount: # If it has, erase the value of the file and replace it with the db value (converted) audio.delall(u'TXXX:FMPS_Playcount') audio.add( TXXX(encoding=3, desc=u"FMPS_Playcount", text=[unicode(1.0 * dbcount)])) needsave = True ############################ if needsave: # save to file only if needed audio.save() self.num_saved += 1 else: self.num_already_done += 1
def test_multi_TXXX(self): from mutagen.id3 import TXXX self.assertEquals(TXXX(encoding=0, text="a").HashKey, TXXX(encoding=0, text="b").HashKey) self.assertNotEquals(TXXX(encoding=0, desc="a").HashKey, TXXX(encoding=0, desc="b").HashKey)
# --------------- # Alter metadata. # --------------- if not arguments.test: track, tracks = 0, len(collection) # type: int, int for file in collection: if file.album: path = arguments.parent / arguments.repository.capitalize( ) / file.dst if path.exists(): audio_file = File(path) tag = audio_file.tags track += 1 if arguments.extension == "flac": tag["album"] = file.album tag["tracknumber"] = str(track) tag["tracktotal"] = str(tracks) with suppress(MutagenError): audio_file.save() elif arguments.extension == "mp3": tag.add(TALB(text=file.album)) tag.add(TRCK(text=str(track))) tag.add( TXXX(description="TOTALTRACKS", text=str(tracks))) with suppress(MutagenError): audio_file.save() sys.exit(count)
def __init_id3_tags(id3, major=3): """ Attributes: id3 ID3 Tag object major ID3 major version, e.g.: 3 for ID3v2.3 """ from mutagen.id3 import TRCK, TPOS, TXXX, TPUB, TALB, UFID, TPE2, \ TSO2, TMED, TIT2, TPE1, TSRC, IPLS, TORY, TDAT, TYER id3.add(TRCK(encoding=major, text="1/10")) id3.add(TPOS(encoding=major, text="1/1")) id3.add( TXXX(encoding=major, desc="MusicBrainz Release Group Id", text="e00305af-1c72-469b-9a7c-6dc665ca9adc")) id3.add(TXXX(encoding=major, desc="originalyear", text="2011")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Type", text="album")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Id", text="e7050302-74e6-42e4-aba0-09efd5d431d8")) id3.add(TPUB(encoding=major, text="J&R Adventures")) id3.add(TXXX(encoding=major, desc="CATALOGNUMBER", text="PRAR931391")) id3.add(TALB(encoding=major, text="Don\'t Explain")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Status", text="official")) id3.add(TXXX(encoding=major, desc="SCRIPT", text="Latn")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Release Country", text="US")) id3.add(TXXX(encoding=major, desc="BARCODE", text="804879313915")) id3.add( TXXX(encoding=major, desc="MusicBrainz Album Artist Id", text=[ "3fe817fc-966e-4ece-b00a-76be43e7e73c", "984f8239-8fe1-4683-9c54-10ffb14439e9" ])) id3.add(TPE2(encoding=major, text="Beth Hart & Joe Bonamassa")) id3.add(TSO2(encoding=major, text="Hart, Beth & Bonamassa, Joe")) id3.add(TXXX(encoding=major, desc="ASIN", text="B005NPEUB2")) id3.add(TMED(encoding=major, text="CD")) id3.add( UFID(encoding=major, owner="http://musicbrainz.org", data=b"f151cb94-c909-46a8-ad99-fb77391abfb8")) id3.add(TIT2(encoding=major, text="Sinner's Prayer")) id3.add( TXXX(encoding=major, desc="MusicBrainz Artist Id", text=[ "3fe817fc-966e-4ece-b00a-76be43e7e73c", "984f8239-8fe1-4683-9c54-10ffb14439e9" ])) id3.add(TPE1(encoding=major, text=["Beth Hart & Joe Bonamassa"])) id3.add( TXXX(encoding=major, desc="Artists", text=["Beth Hart", "Joe Bonamassa"])) id3.add(TSRC(encoding=major, text=["NLB931100460", "USMH51100098"])) id3.add( TXXX(encoding=major, desc="MusicBrainz Release Track Id", text="d062f484-253c-374b-85f7-89aab45551c7")) id3.add( IPLS(encoding=major, people=[["engineer", "James McCullagh"], ["engineer", "Jared Kvitka"], ["arranger", "Jeff Bova"], ["producer", "Roy Weisman"], ["piano", "Beth Hart"], ["guitar", "Blondie Chaplin"], ["guitar", "Joe Bonamassa"], ["percussion", "Anton Fig"], ["drums", "Anton Fig"], ["keyboard", "Arlan Schierbaum"], ["bass guitar", "Carmine Rojas"], ["orchestra", "The Bovaland Orchestra"], ["vocals", "Beth Hart"], ["vocals", "Joe Bonamassa"]])), id3.add(TORY(encoding=major, text="2011")) id3.add(TYER(encoding=major, text="2011")) id3.add(TDAT(encoding=major, text="2709"))
def test_TXXX(self): from mutagen.id3 import TXXX self.assert_(isinstance(TXXX(encoding=0, desc='d',text='text'), TXXX))
lambda amsong: TALB(text=amsong.album_name), "isrc": lambda amsong: TSRC(text=amsong.isrc), "record_label": lambda amsong: TPUB(text=amsong.album.record_label) if amsong.album.record_label else None, "copyright": lambda amsong: TCOP(text=amsong.album.copyright), "genre": lambda amsong: TCON(text=amsong.genres[0]), "album_artist": lambda amsong: TPE2(text=amsong.album.artist_name), "song_artist": lambda amsong: TPE1(text=amsong.artist_name), "itunes_advisory": lambda amsong: TXXX(desc="ITUNESADVISORY", text="1") if amsong.is_explicit else None, "release_date": lambda amsong: TDRC(text=amsong.release_date), "artwork": lambda amsong: APIC(mime='image/jpeg', desc='cover', data=amsong.get_artwork(prefer_album=True)), "disc_position": lambda amsong: TPOS(text=amsong.disc_number) if '/' in str(amsong.disc_number) else None, "track_position": lambda amsong: TRCK(text= f"{amsong.track_number}/{amsong.album.track_count}") } ERROR_MSG = "--> For '{song}' failed tagging: {tags}"
def update_id3(self, path: str, track: beatport.Track): #AIFF Check aiff = None if path.endswith('.aiff') or path.endswith('.aif'): aiff = AIFF(path) f = aiff.tags else: f = ID3() f.load(path, v2_version=3, translate=True) #Update tags if UpdatableTags.title in self.config.update_tags and self.config.overwrite: f.setall('TIT2', [TIT2(text=track.title)]) if UpdatableTags.artist in self.config.update_tags and self.config.overwrite: f.setall('TPE1', [ TPE1(text=self.config.artist_separator.join( [a.name for a in track.artists])) ]) if UpdatableTags.album in self.config.update_tags and ( self.config.overwrite or len(f.getall('TALB')) == 0): f.setall('TALB', [TALB(text=track.album.name)]) if UpdatableTags.label in self.config.update_tags and ( self.config.overwrite or len(f.getall('TPUB')) == 0): f.setall('TPUB', [TPUB(text=track.label.name)]) if UpdatableTags.bpm in self.config.update_tags and ( self.config.overwrite or len(f.getall('TBPM')) == 0): f.setall('TBPM', [TBPM(text=str(track.bpm))]) if UpdatableTags.genre in self.config.update_tags and ( self.config.overwrite or len(f.getall('TCON')) == 0): f.setall('TCON', [TCON(text=', '.join([g.name for g in track.genres]))]) #Dates if UpdatableTags.date in self.config.update_tags: #ID3 v2.3 if self.config.id3v23 and (self.config.overwrite or (len(f.getall('TYER')) == 0 and len(f.getall('TDAT')) == 0)): date = track.release_date.strftime('%d%m') f.setall('TDRC', []) f.setall('TDAT', [TDAT(text=date)]) f.setall('TYER', [TYER(text=str(track.release_date.year))]) #ID3 v2.4 if not self.config.id3v23 and (self.config.overwrite or len(f.getall('TDRC')) == 0): date = track.release_date.strftime('%Y-%m-%d') f.setall('TDAT', []) f.setall('TYER', []) f.setall('TDRC', [TDRC(text=date)]) if UpdatableTags.key in self.config.update_tags and ( self.config.overwrite or len(f.getall('TKEY')) == 0): f.setall('TKEY', [TKEY(text=track.id3key())]) if UpdatableTags.publishdate in self.config.update_tags and ( self.config.overwrite or len(f.getall('TDRL')) == 0): # f.setall('TORY', [TORY(text=str(track.publish_date.year))]) if not self.config.id3v23: date = track.publish_date.strftime('%Y-%m-%d') f.setall('TDRL', [TDRL(text=date)]) #Other keys if UpdatableTags.other in self.config.update_tags: f.add(TXXX(desc='WWWAUDIOFILE', text=track.url())) f.add(TXXX(desc='WWWPUBLISHER', text=track.label.url('label'))) #Redownlaod cover if self.config.replace_art: try: url = track.art(self.config.art_resolution) r = requests.get(url) data = APIC(encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=r.content) f.delall('APIC') f['APIC:cover.jpg'] = data except Exception: logging.warning('Error downloading cover for file: ' + path) if aiff == None: if self.config.id3v23: f.save(path, v2_version=3, v1=0) else: f.save(path, v2_version=4, v1=0) else: aiff.save()
def TaggerWriteData(files, discogs): # label label = discogs['json'].get('labels')[0]['name'] # country country = discogs['json'].get('country') if country is None: country = '' # date date = discogs['json'].get('released') if date is not None: date = [date.replace('-', '/').replace('/00', '/01')] # genres genres = UtilsArrayToString(discogs['json'].get('genres')) # styles styles = UtilsArrayToString(discogs['json'].get('styles')) for file in files: try: file_extension = file.rsplit('.', 1)[1] if file_extension == 'flac': f = FLAC(file) f['organization'] = label f['composer'] = genres f['genre'] = styles if date is not None: f['date'] = date f['country'] = country f['custom'] = ENV_TAGGING_DONE + ' ' + f['custom'][0] f.save() print(f['tracknumber'][0] + ' done') if file_extension == 'mp3': f = EasyID3(file) f['organization'] = label f['composer'] = genres f['genre'] = styles if date is not None: f['date'] = date f.save() f2 = ID3(file) f2.add(TXXX( desc=u'country', text=[country], )) f2.add( TXXX(desc=u'Custom', text=[ str(ENV_TAGGING_DONE + ' ' + str(f2.get('TXXX:Custom'))) ])) f2.save() print(f['tracknumber'][0] + ' done') except: print(style.red(ENV_ERROR_TAGGING)) continue
def CopyTagsToTranscodedFileMp3(losslessFile, lossyFile): # Because the input flac file is decoded to wav, all metadata is lost. We have to extract this metadata from # the flac file and put it directly into the generated mp3 file. from mutagen.flac import FLAC from mutagen.id3 import ID3 flacFile = FLAC(losslessFile) flacFileTags = flacFile.tags mp3File = ID3(lossyFile) mp3File.delete() for key,value in flacFileTags.items(): if key == 'title': from mutagen.id3 import TIT2 mp3File.add(TIT2(encoding=3, text=value)) elif key == 'album': from mutagen.id3 import TALB mp3File.add(TALB(encoding=3, text=value)) elif key == 'artist': from mutagen.id3 import TPE1 mp3File.add(TPE1(encoding=3, text=value)) elif key == 'tracknumber': from mutagen.id3 import TRCK mp3File.add(TRCK(encoding=3, text=value)) elif key == 'date': from mutagen.id3 import TDRC mp3File.add(TDRC(encoding=3, text=value)) elif key == 'genre': from mutagen.id3 import TCON mp3File.add(TCON(encoding=3, text=value)) elif key == 'discnumber': from mutagen.id3 import TPOS mp3File.add(TPOS(encoding=3, text=value)) elif key == 'composer': from mutagen.id3 import TCOM mp3File.add(TCOM(encoding=3, text=value)) elif key == 'conductor': from mutagen.id3 import TPE3 mp3File.add(TPE3(encoding=3, text=value)) elif key == 'ensemble': from mutagen.id3 import TPE2 mp3File.add(TPE2(encoding=3, text=value)) elif key == 'comment': from mutagen.id3 import COMM mp3File.add(COMM(encoding=3, text=value)) elif key == 'publisher': from mutagen.id3 import TPUB mp3File.add(TPUB(encoding=3, text=value)) elif key == 'opus': from mutagen.id3 import TIT3 mp3File.add(TIT3(encoding=3, text=value)) elif key == 'sourcemedia': from mutagen.id3 import TMED mp3File.add(TMED(encoding=3, text=value)) elif key == 'isrc': from mutagen.id3 import TSRC mp3File.add(TSRC(encoding=3, text=value)) elif key == 'license': from mutagen.id3 import TOWN mp3File.add(TOWN(encoding=3, text=value)) elif key == 'copyright': from mutagen.id3 import WCOP mp3File.add(WCOP(encoding=3, text=value)) elif key == 'encoded-by': from mutagen.id3 import TENC mp3File.add(TENC(encoding=3, text=value)) elif (key == 'part' or key == 'partnumber'): from mutagen.id3 import TIT3 mp3File.add(TIT3(encoding=3, text=value)) elif (key == 'lyricist' or key == 'textwriter'): from mutagen.id3 import TIT3 mp3File.add(TIT3(encoding=3, text=value)) else: from mutagen.id3 import TXXX mp3File.add(TXXX(encoding=3, text=value, desc=key)) mp3File.update_to_v24() mp3File.save() return
def one_to_one_conversion_txxx(flac_frame_name, desc): return (flac_frame_name, lambda mp3, flac: mp3.text[0] == flac, lambda str: [TXXX(encoding=3, desc=desc, text=str)])
def _audio_txxx(atuple): audio, atag, _, _ = atuple param = ast.literal_eval(atag) audio.add(TXXX(param[0], param[1], param[2]))
def copyTagsToTranscodedFileMp3(losslessFile, lossyFile): # # Copy the tags from the losslessFile (.flac) to the lossyFile. # All previous tags from the lossyFile will be deleted before the # tags from the losslessFile are copied. # from mutagen.flac import FLAC from mutagen.id3 import ID3 # Read all tags from the flac file flacFile = FLAC(losslessFile) flacFileTags = flacFile.tags # Returns a dictionary containing the flac tags # Only mp3 files with ID3 headers can be openend. # So be sure to add some tags during encoding .wav. to mp3 # Mapping from Vorbis comments field recommendations to id3v2_4_0 # For more information about vorbis field recommendations: http://reactor-core.org/ogg-tagging.html # For more information about id3v2_4_0 frames: http://www.id3.org/id3v2.4.0-frames # # Single value tags: # ALBUM -> TALB # ARTIST -> TPE1 # PUBLISHER -> TPUB # COPYRIGHT -> WCOP # DISCNUMBER -> TPOS # ISRC -> TSRC # EAN/UPN # LABEL # LABELNO # LICENSE -> TOWN # OPUS -> TIT3 # SOURCEMEDIA -> TMED # TITLE -> TIT2 # TRACKNUMBER -> TRCK # VERSION # ENCODED-BY -> TENC # ENCODING # Multiple value tags: # COMPOSER -> TCOM # ARRANGER # LYRICIST -> TEXT # AUTHOR -> TEXT # CONDUCTOR -> TPE3 # PERFORMER -> # ENSEMBLE -> TPE2 # PART -> TIT1 # PARTNUMBER -> TIT1 # GENRE -> TCON # DATE -> TDRC # LOCATION # COMMENT -> COMM # Other vorbis tags are mapped to TXXX tags mp3File = ID3(lossyFile) mp3File.delete() for key, value in flacFileTags.items(): if key == 'title': # Map to TIT2 frame from mutagen.id3 import TIT2 mp3File.add(TIT2(encoding=3, text=value)) elif key == 'album': # Map to TALB frame from mutagen.id3 import TALB mp3File.add(TALB(encoding=3, text=value)) elif key == 'artist': # Map to TPE1 frame from mutagen.id3 import TPE1 mp3File.add(TPE1(encoding=3, text=value)) elif key == 'tracknumber': # Map to TRCK frame from mutagen.id3 import TRCK mp3File.add(TRCK(encoding=3, text=value)) elif key == 'date': # Map to TDRC frame from mutagen.id3 import TDRC mp3File.add(TDRC(encoding=3, text=value)) elif key == 'genre': # Map to TCON frame from mutagen.id3 import TCON mp3File.add(TCON(encoding=3, text=value)) elif key == 'discnumber': # Map to TPOS frame from mutagen.id3 import TPOS mp3File.add(TPOS(encoding=3, text=value)) elif key == 'composer': # Map to TCOM frame from mutagen.id3 import TCOM mp3File.add(TCOM(encoding=3, text=value)) elif key == 'conductor': # Map to TPE3 frame from mutagen.id3 import TPE3 mp3File.add(TPE3(encoding=3, text=value)) elif key == 'ensemble': # Map to TPE2 frame from mutagen.id3 import TPE2 mp3File.add(TPE2(encoding=3, text=value)) elif key == 'comment': # Map to COMM frame from mutagen.id3 import COMM mp3File.add(COMM(encoding=3, text=value)) elif key == 'publisher': # Map to TPUB frame from mutagen.id3 import TPUB mp3File.add(TPUB(encoding=3, text=value)) elif key == 'opus': # Map to TIT3 frame from mutagen.id3 import TIT3 mp3File.add(TIT3(encoding=3, text=value)) elif key == 'sourcemedia': # Map to TMED frame from mutagen.id3 import TMED mp3File.add(TMED(encoding=3, text=value)) elif key == 'isrc': # Map to TSRC frame from mutagen.id3 import TSRC mp3File.add(TSRC(encoding=3, text=value)) elif key == 'license': # Map to TOWN frame from mutagen.id3 import TOWN mp3File.add(TOWN(encoding=3, text=value)) elif key == 'copyright': # Map to WCOP frame from mutagen.id3 import WCOP mp3File.add(WCOP(encoding=3, text=value)) elif key == 'encoded-by': # Map to TENC frame from mutagen.id3 import TENC mp3File.add(TENC(encoding=3, text=value)) elif (key == 'part' or key == 'partnumber'): # Map to TIT3 frame from mutagen.id3 import TIT3 mp3File.add(TIT3(encoding=3, text=value)) elif (key == 'lyricist' or key == 'textwriter'): # Map to TEXT frame from mutagen.id3 import TIT3 mp3File.add(TIT3(encoding=3, text=value)) else: #all other tags are mapped to TXXX frames # Map to TXXX frame from mutagen.id3 import TXXX mp3File.add(TXXX(encoding=3, text=value, desc=key)) mp3File.update_to_v24() mp3File.save() return