async def tag(path, metadata, session=None): audio = mp3.MP3(path) audio.tags = id3.ID3() for maker in tagmaker.tag_makers: tag = maker(metadata) if tag: audio.tags.add(tag) if keys.IMAGE_LINK in metadata: url = metadata.get(keys.IMAGE_LINK) if session: mime, _ = mimetypes.guess_type(url) async with session.get(url) as response: data = await response.read() audio.tags.add( id3.APIC(encoding=id3.Encoding.UTF8, mime=mime, type=id3.PictureType.COVER_FRONT, desc='Front cover', data=data)) else: # In practice, this is unsupported by most media players # But there's no reason not to do it audio.tags.add(id3.APIC(data=url, mime='-->')) audio.save()
def write_tags(f, meta, cov): if f.endswith('.mp3'): try: audio = id3.ID3(f) except ID3NoHeaderError: audio = id3.ID3() audio['TRCK'] = id3.TRCK(encoding=3, text=str(meta['TRACK']) + "/" + str(meta['TRACKTOTAL'])) legend = { "ALBUM": id3.TALB, "ALBUMARTIST": id3.TPE2, "ARTIST": id3.TPE1, "COPYRIGHT": id3.TCOP, "TITLE": id3.TIT2, "YEAR": id3.TYER } for tag, value in meta.items(): if not tag in ['UPC', 'TRACK', 'TRACKTOTAL']: id3tag = legend[tag] audio[id3tag.__name__] = id3tag(encoding=3, text=value) with open(cov, 'rb') as cov_obj: audio.add(id3.APIC(3, 'image/jpeg', 3, '', cov_obj.read())) audio.save(f, 'v2_version=3') else: audio = FLAC(f) for tag, value in meta.items(): audio[tag] = str(value) image = Picture() image.type = 3 image.mime = "image/jpeg" with open(cov, 'rb') as cov_obj: image.data = cov_obj.read() audio.add_picture(image) audio.save()
def write_mp3_chapters(audio, chapters): z = 0 chapter_ids = [] for chapter in chapters: z += 1 chap_id = 'chap%s' % str(z).zfill(4) start = get_milliseconds(chapter['start']) stop = get_milliseconds(chapter['stop']) embeded_elements = [] for tag in chapter: if tag == 'title': embeded_elements.append(id3.TIT2(encoding=3, text=chapter[tag])) elif tag == 'description': embeded_elements.append(id3.TIT3(encoding=3, text=chapter[tag])) elif tag == 'image': image = get_mp3_coverart(chapter[tag]) image = id3.APIC(3, 'image/jpeg', 3, '', image) embeded_elements.append(image) chap = CHAP(element_id=chap_id, start=start, stop=stop, embeded_frames=embeded_elements) audio[chap_id] = chap chapter_ids.append(chap_id) ctoc = CTOC('ctoc0001', False, True, chapter_ids) audio['ctoc0001'] = ctoc
def tag_mp3(filename, title, artwork=None): """ Adds ID3 tags to a file. Args: filename (str): The name of the MP3 file that needs tagging. title (str): The text to be used as the ID3 title. artwork (str): The naem of the image file to be attached as artwork. Defaults to None. """ audio = MP3(filename) duration = audio.info.length tags = id3.ID3() tags['TLEN'] = id3.TLEN(encoding=3, text=str(int(duration * 1000))) if title: tags['TIT2'] = id3.TIT2(encoding=3, text=[title]) if artwork: mimetype, encoding = guess_type(artwork) if mimetype: with open(artwork, 'rb') as f: tags['APIC'] = id3.APIC(encoding=0, mime=mimetype, type=9, data=f.read()) tags.update_to_v23() tags.save(filename, v1=1, v2_version=3, padding=lambda info: 0)
def write_id3(mp3_file, track, cover=None): t = mp3.Open(mp3_file) if not t.tags: t.add_tags() album = track['albums'][0] t_add = t.tags.add t_add(id3.TIT2(encoding=3, text=track['title'])) t_add(id3.TPE1(encoding=3, text=track['artists'])) t_add(id3.TCOM(encoding=3, text=track[FLD_COMPOSERS])) t_add(id3.TALB(encoding=3, text=album['title'])) if 'labels' in album: t_add(id3.TPUB(encoding=3, text=', '.join(l['name'] for l in album['labels']))) if FLD_TRACKNUM in track: tnum = '{}/{}'.format(track[FLD_TRACKNUM], album['trackCount']) t_add(id3.TRCK(encoding=3, text=tnum)) if FLD_VOLUMENUM in album: t_add(id3.TPOS(encoding=3, text=str(album[FLD_VOLUMENUM]))) if 'year' in album: t_add(id3.TDRC(encoding=3, text=str(album['year']))) if args.genre: t_add(id3.TCON(encoding=3, text=album['genre'].title())) if cover: t_add(id3.APIC(encoding=3, desc='', mime=cover.mime, type=3, data=cover.data)) t.tags.update_to_v23() #id3.ID3v1SaveOptions.CREATE = 2 t.save(v1=2, v2_version=3)
def write_tags_to_mp3(path, tags): audio = MP3(path) for i, tag in [['title', 'TIT2'], ['artist', 'TPE1'], ['album', 'TALB'], ['date', 'TDRC'], ['composer', 'TCOM'], ['genre', 'TCON'], ['lyrics', 'USLT'], ['album-artist', 'TPE2'], ['disc', 'TPOS'], ['comment', 'COMM']]: if i in tags: if tag == 'USLT': tag = id3.Frames[tag](encoding=3, text=tags[i], lang='eng') audio[tag.HashKey] = tag elif tag == 'COMM': tag = id3.Frames[tag](encoding=3, text=tags[i], lang='eng') audio[tag.HashKey] = tag else: tag = id3.Frames[tag](encoding=3, text=tags[i]) audio[tag.HashKey] = tag if 'track' in tags: if 'number-of-tracks' in tags: num_tracks = tags['number-of-tracks'] else: num_tracks = 0 track_num = "%d/%d" % (int(tags['track']), int(num_tracks)) tag = id3.Frames['TRCK'](encoding=3, text=track_num) audio[tag.HashKey] = tag if 'cover' in tags: image = get_mp3_coverart(tags['cover']) image = id3.APIC(3, 'image/jpeg', 3, 'Cover', image) audio[image.HashKey] = image if 'chapters' in tags: write_mp3_chapters(audio, tags['chapters']['chapters']) audio.save()
def song_info_insert(filepath, song_name, artist_name, album_name): with open('cover.jpg', 'rb') as f: pic_data = f.read() info = { 'picData': pic_data, 'title': song_name, 'artist': artist_name, 'album': album_name } filepath += '.mp3' try: song_file = id3.ID3(filepath) song_file['APIC'] = id3.APIC( # 插入封面 encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=info['picData']) song_file['TIT2'] = id3.TIT2( # 插入歌名 encoding=3, text=info['title']) song_file['TPE1'] = id3.TPE1( # 插入歌手 encoding=3, text=info['artist']) song_file['TALB'] = id3.TALB( # 插入专辑名 encoding=3, text=info['album']) song_file.save() except Exception as error: print('无法写入歌曲信息') print(f'报错:{error}') finally: os.remove('cover.jpg')
def embed_image(): id3_dict.add( id3.APIC(encoding=3, mime='image/jpeg', type=3, desc='Front Cover', data=image))
async def _write_tag(client: api.API, file_path: pathlib.Path, song: api.Song): audio = id3.ID3(file_path) audio.add(id3.TIT2(encoding=id3.Encoding.UTF8, text=song.name)) audio.add(id3.TPE1(encoding=id3.Encoding.UTF8, text=song.artist)) audio.add(id3.TALB(encoding=id3.Encoding.UTF8, text=song.album)) if song.lyric: audio.add( id3.ULT( encoding=id3.Encoding.UTF8, lang='eng', desc=song.name, text=song.lyric, )) if song.pic_url: try: resp = await client.request('GET', song.pic_url) data = await resp.read() except (aiohttp.ClientError, asyncio.TimeoutError): pass else: audio.add( id3.APIC( encoding=id3.Encoding.UTF8, mime='image/jpeg', type=id3.PictureType.COVER_FRONT, desc='Front cover', data=data, )) try: audio.save() except mutagen.MutagenError: pass
def embed_image(): audio.tags.add( id3.APIC(encoding=3, mime='image/jpeg', type=3, desc='Front Cover', data=image.data))
def id3_art(self, mp3_file): song = mid3.ID3(mp3_file) tag = mid3.APIC(encoding=3, mime='image/jpeg', type=3, desc="Front Cover", data=self.art_data) song.add(tag) song.save()
def write_tags(f, meta, tag_cfg, cov, ext, embed_cov): if ext == ".flac": audio = FLAC(f) for k, v in meta.items(): if tag_cfg[k]: audio[k] = str(v) if embed_cov and cov: with open(cov, 'rb') as cov_obj: image = Picture() image.type = 3 image.mime = "image/jpeg" image.data = cov_obj.read() audio.add_picture(image) audio.save() elif ext == ".mp3": try: audio = id3.ID3(f) except ID3NoHeaderError: audio = id3.ID3() if tag_cfg['TRACKNUMBER'] and tag_cfg['TRACKTOTAL']: audio['TRCK'] = id3.TRCK(encoding=3, text=str(meta['TRACKNUMBER']) + "/" + str(meta['TRACKTOTAL'])) elif tag_cfg['TRACKNUMBER']: audio['TRCK'] = id3.TRCK(encoding=3, text=str(meta['TRACKNUMBER'])) if tag_cfg['DISCNUMBER']: audio['TPOS'] = id3.TPOS(encoding=3, text=str(meta['DISCNUMBER']) + "/" + str(meta['DISCTOTAL'])) legend = { "ALBUM": id3.TALB, "ALBUMARTIST": id3.TPE2, "ARTIST": id3.TPE1, "COMMENT": id3.COMM, "COMPOSER": id3.TCOM, "COPYRIGHT": id3.TCOP, "DATE": id3.TDAT, "GENRE": id3.TCON, "ISRC": id3.TSRC, "LABEL": id3.TPUB, "PERFORMER": id3.TOPE, "TITLE": id3.TIT2, # Not working. "URL": id3.WXXX, "YEAR": id3.TYER } for k, v in meta.items(): try: if tag_cfg[k]: id3tag = legend[k] audio[id3tag.__name__] = id3tag(encoding=3, text=v) except KeyError: pass if embed_cov and cov: with open(cov, 'rb') as cov_obj: audio.add(id3.APIC(3, 'image/jpeg', 3, '', cov_obj.read())) audio.save(f, 'v2_version=3')
def addImage(self, _imageType, _imagePath, _description): self.isSave = True imageData = fu.readFromBinaryFile(_imagePath) mimeType = fu.getMimeType(_imagePath)[0] self.tags.add( id3.APIC(encoding=3, mime=mimeType, type=int(_imageType), desc=uni.trUnicode(_description), data=imageData))
def write_tags(pre_abs, meta, fmt, cov_abs): if fmt == "FLAC": audio = FLAC(pre_abs) del meta['track_padded'] for k, v in meta.items(): if v: audio[k] = str(v) if cov_abs: with open(cov_abs, "rb") as f: image = Picture() image.type = 3 image.mime = "image/jpeg" image.data = f.read() audio.add_picture(image) elif fmt == "MP3": try: audio = id3.ID3(pre_abs) except ID3NoHeaderError: audio = id3.ID3() audio['TRCK'] = id3.TRCK(encoding=3, text="{}/{}".format(meta['track'], meta['tracktotal'])) legend = { "album": id3.TALB, "albumartist": id3.TPE2, "artist": id3.TPE1, #"comment": id3.COMM, "copyright": id3.TCOP, "isrc": id3.TSRC, "label": id3.TPUB, "title": id3.TIT2, "year": id3.TYER } for k, v in meta.items(): id3tag = legend.get(k) if v and id3tag: audio[id3tag.__name__] = id3tag(encoding=3, text=v) if cov_abs: with open(cov_abs, "rb") as cov_obj: audio.add(id3.APIC(3, "image/jpeg", 3, None, cov_obj.read())) else: audio = MP4(pre_abs) audio['\xa9nam'] = meta['title'] audio['\xa9alb'] = meta['album'] audio['aART'] = meta['albumartist'] audio['\xa9ART'] = meta['artist'] audio['trkn'] = [(meta['track'], meta['tracktotal'])] audio['\xa9day'] = meta['year'] audio['cprt'] = meta['copyright'] if cov_abs: with open(cov_abs, "rb") as f: audio['covr'] = [ MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG) ] audio.save(pre_abs)
def _embed_id3_img(root_dir, audio: id3.ID3): emb_image = os.path.join(root_dir, "cover.jpg") multi_emb_image = os.path.join( os.path.abspath(os.path.join(root_dir, os.pardir)), "cover.jpg") if os.path.isfile(emb_image): cover_image = emb_image else: cover_image = multi_emb_image with open(cover_image, "rb") as cover: audio.add(id3.APIC(3, "image/jpeg", 3, "", cover.read()))
def track_tagger(track_path, title, artist, album, cover_path): track = mp3.EasyMP3(track_path) track['title'] = title track['artist'] = artist track['album'] = album track.save() cover_image = open(cover_path, 'rb').read() track = id3.ID3(track_path) track.add(id3.APIC(3, 'image/jpeg', 3, u'Cover', cover_image)) track.save() remove(cover_path)
def tag(album, track, file_path, cover_path): lyrics = get_lyrics(track['lyrics_tp'], track['track_id']) meta = utils.organize_meta(album=album, track=track, lyrics=lyrics) if str(file_path).endswith('.flac'): if cover_path: f_file = FLAC(file_path) f_image = Picture() f_image.type = 3 f_image.desc = 'Front Cover' with open(cover_path, 'rb') as f: f_image.data = f.read() f_file.add_picture(f_image) f_file.save() f = FLAC(file_path) logger_bugs.debug("Writing tags to {}".format( os.path.basename(file_path))) for k, v in meta.items(): f[k] = str(v) f.save() if str(file_path).endswith('.mp3'): legend = { "ALBUM": id3.TALB, "ALBUMARTIST": id3.TPE2, "ARTIST": id3.TPE1, "TRACKNUMBER": id3.TRCK, "DISCNUMBER": id3.TPOS, "COMMENT": id3.COMM, "COMPOSER": id3.TCOM, "COPYRIGHT": id3.TCOP, "DATE": id3.TDRC, "GENRE": id3.TCON, "ISRC": id3.TSRC, "LABEL": id3.TPUB, "PERFORMER": id3.TOPE, "TITLE": id3.TIT2, "LYRICS": id3.USLT } try: audio = id3.ID3(file_path) except ID3NoHeaderError: audio = id3.ID3() logger_bugs.debug("Writing tags to {}".format( os.path.basename(file_path))) for k, v in meta.items(): try: id3tag = legend[k] audio[id3tag.__name__] = id3tag(encoding=3, text=v) except KeyError: pass if cover_path: with open(cover_path, 'rb') as cov_obj: audio.add(id3.APIC(3, 'image/jpg', 3, '', cov_obj.read())) audio.save(file_path, 'v2_version=3')
def addpic(mp3file, imgfile): type = None if imgfile.endswith('png'): type = "image/png" elif imgfile.endswith('jpg') or imgfile.endswith('jpeg'): type = "image/jpeg" else: sys.exit(1) tag = id3.ID3(mp3file, v2_version=3) with open(imgfile).read() as f: tag.add( id3.APIC(encoding=id3.Encoding.UTF16, mime=type, type=id3.PictureType.COVER_FRONT, data=f.read())) tag.save()
def compiletracl(tracl): rawfile = File("%s.mp3" % tracl['id']) rawfile['TIT2'] = id3.TIT2(encoding=3, text=tracl['title']) rawfile['TALB'] = id3.TALB(encoding=3, text=tracl['album']) rawfile['TPE1'] = id3.TPE1(encoding=3, text=tracl['artist']) rawfile['TCON'] = id3.TCON(encoding=3, text=tracl['genre']) rawfile['TYER'] = id3.TYER(encoding=3, text=tracl['year']) rawfile['TRCK'] = id3.TRCK(encoding=3, text=tracl['len']) rawfile['WOAS'] = id3.WOAS(encoding=3, text=tracl['link']) rawfile['APIC'] = id3.APIC(encoding=3, type=3, mime='image/jpeg', desc='Cover', data=downloadcover(tracl)) rawfile.save(v2_version=3)
def insert_mp3(abs_audio_f): cover = cut_suffix(abs_audio_f) + '.jpg' mime = u"image/jpeg" if not os.path.exists(cover): cover = cut_suffix(abs_audio_f) + '.png' mime = u"image/png" if not os.path.exists(cover): # print('Cover for [' + abs_audio_f + '] not found.') return audio = id3.ID3(abs_audio_f) with open(cover, 'rb') as albumart: audio['APIC'] = id3.APIC( encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=albumart.read() ) audio.save()
def tag_mp3(path_audio,path_pic,lrc,title,artist,album,disc,track,**kw): ''' ref: http://id3.org/id3v2.3.0 https://github.com/quodlibet/mutagen/blob/master/mutagen/id3/_frames.py http://help.mp3tag.de/main_tags.html http://code.activestate.com/recipes/577138-embed-lyrics-into-mp3-files-using-mutagen-uslt-tag/ ''' tags=id3.ID3() if path_pic: with open(path_pic,'rb') as f: tags['APIC']=id3.APIC(mime='image/jpeg',type=id3.PictureType.COVER_FRONT,data=f.read()) for x in lrc: tags["USLT::"+x['lang']]=id3.USLT(text=x['text'],lang=x['lang']) tags['TIT2']=id3.TIT2(text=title) tags['TPE1']=id3.TPE1(text=artist) if album!=None: tags['TALB']=id3.TALB(text=album) tags['TPOS']=id3.TPOS(text=disc) tags['TRCK']=id3.TRCK(text=str(track)) tags.save(path_audio)
def id3edit(self): """ ID3タグを編集 """ # ID3タグ書き換え encoding: UTF-16 with BOM (1) self.tags['TIT2'] = id3.TIT2(encoding=1, text=self.title) self.tags['TALB'] = id3.TALB(encoding=1, text=self.album) self.tags['TPE1'] = id3.TPE1(encoding=1, text=self.artist) self.tags['TCON'] = id3.TCON(encoding=1, text=self.genre) #self.tags['TPE2'] = TPE2(encoding=1, text=self.albumartist) self.tags.delall('COMM') self.tags['COMM'] = id3.COMM(encoding=1, lang='eng', text=self.comment) # アートワーク書き換え if not self.artwork_url == '': # アートワーク画像のURLがある場合 # 画像読み込み try: artwork_read = urlopen(self.artwork_url).read() except: raise URLOpenError("画像を取得できません") # アートワーク初期化 self.tags.delall('APIC') # 画像設定 self.tags['APIC'] = id3.APIC( encoding=1, mime='image/jpeg', type=3, desc='Cover', data=artwork_read) # 保存 self.tags.save(self.filepath) # 表示用アートワーク更新 artworks = self.tags.getall('APIC') # list artwork = None for artwork in artworks: # 抽出 pass if artwork: # アートワーク画像が存在するか self.artwork = artwork.data # type: bytes else: self.artwork = None
def save_stream(self, track, destination): if self.is_authenticated(): with open(destination, 'w+b') as stream_file: urls = self.webclient.get_stream_urls(track.get('storeId')) if len(urls) == 1: stream_file.write( self.webclient.session._rsession.get(urls[0]).content) range_pairs = [[int(s) for s in val.split('-')] for url in urls for key, val in parse_qsl(urlparse(url)[4]) if key == 'range'] for url, (start, end) in zip(urls, range_pairs): stream_file.truncate(start) stream_file.seek(0, 2) audio = self.webclient.session._rsession.get(url).content stream_file.write(audio) tag = easyid3.EasyID3() tag['title'] = track.get('title').__str__() tag['artist'] = track.get('artist').__str__() tag['album'] = track.get('album').__str__() tag['date'] = track.get('year').__str__() tag['discnumber'] = track.get('discNumber').__str__() tag['tracknumber'] = track.get('trackNumber').__str__() tag['performer'] = track.get('albumArtist').__str__() tag.save(destination) tag = mp3.MP3(destination) tag.tags.add( id3.APIC( 3, 'image/jpeg', 3, 'Front cover', urllib.urlopen( track.get('albumArtRef')[0].get('url')).read())) tag.save()
def tag(self, target, track): mp3 = MP3(os.path.join(self.workdir, target)) if not mp3.tags: mp3.add_tags() tags = mp3.tags tags.add(id3.TALB(encoding=id3.Encoding.UTF8, text=self.disc.album)) tags.add(id3.TPE1(encoding=id3.Encoding.UTF8, text=self.disc.artist)) tags.add(id3.TIT2(encoding=id3.Encoding.UTF8, text=track.title)) tags.add(id3.TRCK(encoding=id3.Encoding.UTF8, text=str(track.trackno))) tags.add(id3.TDRC(encoding=id3.Encoding.UTF8, text=str(self.disc.year))) tpos = str(self.disc.discno) if self.disc.set_size > 1: tpos = f"{self.disc.discno}/{self.disc.set_size}" tags.add(id3.TPOS(encoding=id3.Encoding.UTF8, text=tpos)) if self.disc.cover_art: tags.add( id3.APIC(encoding=id3.Encoding.UTF8, data=self.disc.cover_art)) mp3.save()
def save(self): if self.clr: for file in self.audiofiles: tmp = mid3.ID3(file) tmp.clear() tmp.add(mid3.TIT2(text="")) # title frame tmp.add(mid3.TPE1(text="")) # artist frame tmp.add(mid3.TALB(text="")) # album frame tmp.add(mid3.TPE2(text="")) # album artist frame tmp.add(mid3.TCOM(text="")) # composer frame tmp.add(mid3.TCON(text="")) # genre frame tmp.add(mid3.TDRC(text="")) # date frame tmp.add(mid3.TRCK(text="")) # tracknumber frame tmp.add(mid3.TPOS(text="")) # discnumber frame tmp.add(mid3.TBPM(text="")) # bpm frame tmp.save() if self.artwork: with open(self.artwork, 'rb') as albumart: for file in self.audiofiles: tmp = mid3.ID3(file) tmp['APIC'] = mid3.APIC( encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=albumart.read() ) tmp.save() albumart.seek(0) for file in self.audiofiles: tmp = EasyID3(file) for tag in self.__sets: if self.__sets[tag]: tmp[tag] = self.__sets[tag] tmp.save()
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) tags = self._get_tags(filename) if config.setting['clear_existing_tags']: tags.clear() if metadata.images_to_be_saved_to_tags: tags.delall('APIC') encoding = { 'utf-8': 3, 'utf-16': 1 }.get(config.setting['id3v2_encoding'], 0) if 'tracknumber' in metadata: if 'totaltracks' in metadata: text = '%s/%s' % (metadata['tracknumber'], metadata['totaltracks']) else: text = metadata['tracknumber'] tags.add(id3.TRCK(encoding=0, text=id3text(text, 0))) if 'discnumber' in metadata: if 'totaldiscs' in metadata: text = '%s/%s' % (metadata['discnumber'], metadata['totaldiscs']) else: text = metadata['discnumber'] tags.add(id3.TPOS(encoding=0, text=id3text(text, 0))) # This is necessary because mutagens HashKey for APIC frames only # includes the FrameID (APIC) and description - it's basically # impossible to save two images, even of different types, without # any description. counters = defaultdict(lambda: 0) for image in metadata.images_to_be_saved_to_tags: desc = desctag = image.comment if counters[desc] > 0: if desc: desctag = "%s (%i)" % (desc, counters[desc]) else: desctag = "(%i)" % counters[desc] counters[desc] += 1 tags.add( id3.APIC(encoding=0, mime=image.mimetype, type=image_type_as_id3_num(image.maintype), desc=id3text(desctag, 0), data=image.data)) tmcl = mutagen.id3.TMCL(encoding=encoding, people=[]) tipl = mutagen.id3.TIPL(encoding=encoding, people=[]) tags.delall('TCMP') for name, values in metadata.rawitems(): values = [id3text(v, encoding) for v in values] name = id3text(name, encoding) if name.startswith('performer:'): role = name.split(':', 1)[1] for value in values: tmcl.people.append([role, value]) elif name.startswith('comment:'): desc = name.split(':', 1)[1] if desc.lower()[:4] == 'itun': tags.delall('COMM:' + desc) tags.add( id3.COMM(encoding=0, desc=desc, lang='eng', text=[v + '\x00' for v in values])) else: tags.add( id3.COMM(encoding=encoding, desc=desc, lang='eng', text=values)) elif name.startswith('lyrics:') or name == 'lyrics': if ':' in name: desc = name.split(':', 1)[1] else: desc = '' for value in values: tags.add(id3.USLT(encoding=encoding, desc=desc, text=value)) elif name in self._rtipl_roles: for value in values: tipl.people.append([self._rtipl_roles[name], value]) elif name == 'musicbrainz_recordingid': tags.add( id3.UFID(owner='http://musicbrainz.org', data=bytes(values[0], 'ascii'))) elif name == '~rating': # Search for an existing POPM frame to get the current playcount for frame in tags.values(): if frame.FrameID == 'POPM' and frame.email == config.setting[ 'rating_user_email']: count = getattr(frame, 'count', 0) break else: count = 0 # Convert rating to range between 0 and 255 rating = int( round( float(values[0]) * 255 / (config.setting['rating_steps'] - 1))) tags.add( id3.POPM(email=config.setting['rating_user_email'], rating=rating, count=count)) elif name == 'grouping': if config.setting['itunes_compatible_grouping']: tags.add(id3.GRP1(encoding=encoding, text=values)) else: tags.add(id3.TIT1(encoding=encoding, text=values)) elif name == 'work': if config.setting['itunes_compatible_grouping']: tags.add(id3.TIT1(encoding=encoding, text=values)) tags.delall('TXXX:Work') else: tags.add(self.build_TXXX(encoding, 'Work', values)) elif name in self.__rtranslate: frameid = self.__rtranslate[name] if frameid.startswith('W'): valid_urls = all([all(urlparse(v)[:2]) for v in values]) if frameid == 'WCOP': # Only add WCOP if there is only one license URL, otherwise use TXXX:LICENSE if len(values) > 1 or not valid_urls: tags.add( self.build_TXXX( encoding, self.__rtranslate_freetext[name], values)) else: tags.add(id3.WCOP(url=values[0])) elif frameid == 'WOAR' and valid_urls: for url in values: tags.add(id3.WOAR(url=url)) elif frameid.startswith('T'): if config.setting['write_id3v23']: if frameid == 'TMOO': tags.add(self.build_TXXX(encoding, 'mood', values)) # No need to care about the TMOO tag being added again as it is # automatically deleted by Mutagen if id2v23 is selected tags.add( getattr(id3, frameid)(encoding=encoding, text=values)) if frameid == 'TSOA': tags.delall('XSOA') elif frameid == 'TSOP': tags.delall('XSOP') elif frameid == 'TSO2': tags.delall('TXXX:ALBUMARTISTSORT') elif name in self.__rtranslate_freetext: tags.add( self.build_TXXX(encoding, self.__rtranslate_freetext[name], values)) elif name.startswith('~id3:'): name = name[5:] if name.startswith('TXXX:'): tags.add(self.build_TXXX(encoding, name[5:], values)) else: frameclass = getattr(id3, name[:4], None) if frameclass: tags.add(frameclass(encoding=encoding, text=values)) # don't save private / already stored tags elif not name.startswith( "~") and name not in self.__other_supported_tags: tags.add(self.build_TXXX(encoding, name, values)) tags.add(tmcl) tags.add(tipl) self._remove_deleted_tags(metadata, tags) self._save_tags(tags, encode_filename(filename)) if self._IsMP3 and config.setting["remove_ape_from_mp3"]: try: mutagen.apev2.delete(encode_filename(filename)) except: pass
def mark(path, song, id=None): def streamify(file): with file: return file.read() def embed(item, content, type): item.encoding = 0 item.type = type item.mime = 'image/png' if content[0:4] == binascii.a2b_hex( '89504E47') else 'image/jpeg' item.data = content format = 'flac' if open( path, 'rb').read(4) == binascii.a2b_hex('664C6143') else 'mp3' audio = mp3.EasyMP3(path) if format == 'mp3' else flac.FLAC(path) meta = { 'album': song['album']['name'], 'albumId': song['album']['id'], 'albumPic': song['album']['picUrl'], 'albumPicDocId': str(song['album']['pic'] if 'pic' in song['album'] else re. search(r'/(\d+)\.\w+$', song['album']['picUrl']).group(1)), 'alias': song['alias'] if 'alias' in song else [], 'artist': [[artist['name'], artist['id']] for artist in song['artists']], 'musicId': id if id else song['id'], 'musicName': song['name'] if 'name' in song else audio['title'][0], 'mvId': song['mvid'] if 'mvid' in song else 0, 'transNames': [], 'format': format, 'bitrate': audio.info.bitrate, 'duration': int(audio.info.length * 1000), 'mp3DocId': hashlib.md5(streamify(open(path, 'rb'))).hexdigest() } cryptor = AES.new(key, AES.MODE_ECB) identifier = 'music:' + json.dumps(meta) identifier = '163 key(Don\'t modify):' + base64.b64encode( cryptor.encrypt(pad(identifier.encode('utf8'), 16))).decode('utf8') audio.delete() audio['title'] = meta['musicName'] audio['album'] = meta['album'] audio['artist'] = '/'.join([artist[0] for artist in meta['artist']]) if format == 'flac': audio['description'] = identifier else: audio.tags.RegisterTextKey('comment', 'COMM') audio['comment'] = identifier audio.save() data = requests.get(meta['albumPic'] + '?param=300y300').content if format == 'flac': audio = flac.FLAC(path) image = flac.Picture() embed(image, data, 3) audio.clear_pictures() audio.add_picture(image) elif format == 'mp3': audio = mp3.MP3(path) image = id3.APIC() embed(image, data, 6) audio.tags.add(image) audio.save()
def dump(input_path, output_path=None, skip=True): output_path = (lambda path, meta: os.path.splitext(path)[0] + '.' + meta[ 'format']) if not output_path else output_path output_path = ( lambda path, meta: path) if not callable(output_path) else output_path core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857') meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728') unpad = lambda s: s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] f = open(input_path, 'rb') # magic header header = f.read(8) assert binascii.b2a_hex(header) == b'4354454e4644414d' # key data f.seek(2, 1) key_length = f.read(4) key_length = struct.unpack('<I', bytes(key_length))[0] key_data = bytearray(f.read(key_length)) key_data = bytes(bytearray([byte ^ 0x64 for byte in key_data])) cryptor = AES.new(core_key, AES.MODE_ECB) key_data = unpad(cryptor.decrypt(key_data))[17:] key_length = len(key_data) # S-box (standard RC4 Key-scheduling algorithm) key = bytearray(key_data) S = bytearray(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % key_length]) & 0xFF S[i], S[j] = S[j], S[i] # meta data meta_length = f.read(4) meta_length = struct.unpack('<I', bytes(meta_length))[0] if meta_length: meta_data = bytearray(f.read(meta_length)) meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data])) identification = meta_data.decode('utf-8') meta_data = base64.b64decode(meta_data[22:]) cryptor = AES.new(meta_key, AES.MODE_ECB) meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] meta_data = json.loads(meta_data) else: meta_data = { 'format': 'flac' if os.fstat(f.fileno()).st_size > 1024**2 * 16 else 'mp3' } # crc32 crc32 = f.read(4) crc32 = struct.unpack('<I', bytes(crc32))[0] # album cover f.seek(5, 1) image_size = f.read(4) image_size = struct.unpack('<I', bytes(image_size))[0] image_data = f.read(image_size) if image_size else None # media data output_path = output_path(input_path, meta_data) if skip and os.path.exists(output_path): return data = f.read() f.close() # stream cipher (modified RC4 Pseudo-random generation algorithm) stream = [S[(S[i] + S[(i + S[i]) & 0xFF]) & 0xFF] for i in range(256)] stream = bytes(bytearray(stream * (len(data) // 256 + 1))[1:1 + len(data)]) data = XOR(data, stream) m = open(output_path, 'wb') m.write(data) m.close() # media tag def embed(item, content, type): item.encoding = 0 item.type = type item.mime = 'image/png' if content[0:4] == binascii.a2b_hex( '89504E47') else 'image/jpeg' item.data = content if image_data: if meta_data['format'] == 'flac': audio = flac.FLAC(output_path) image = flac.Picture() embed(image, image_data, 3) audio.clear_pictures() audio.add_picture(image) elif meta_data['format'] == 'mp3': audio = mp3.MP3(output_path) image = id3.APIC() embed(image, image_data, 6) audio.tags.add(image) audio.save() if meta_length: if meta_data['format'] == 'flac': audio = flac.FLAC(output_path) audio['description'] = identification else: audio = mp3.EasyMP3(output_path) audio.tags.RegisterTextKey('comment', 'COMM') audio['comment'] = identification audio['title'] = meta_data['musicName'] audio['album'] = meta_data['album'] audio['artist'] = '/'.join( [artist[0] for artist in meta_data['artist']]) audio.save() return output_path
def dump(input_path, output_path=None, skip=True): output_path = (lambda path, meta: os.path.splitext(path)[0] + '.' + meta[ 'format']) if not output_path else output_path core_key = binascii.a2b_hex('687A4852416D736F356B496E62617857') meta_key = binascii.a2b_hex('2331346C6A6B5F215C5D2630553C2728') unpad = lambda s: s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] f = open(input_path, 'rb') # magic header header = f.read(8) assert binascii.b2a_hex(header) == b'4354454e4644414d' # key data f.seek(2, 1) key_length = f.read(4) key_length = struct.unpack('<I', bytes(key_length))[0] key_data = bytearray(f.read(key_length)) key_data = bytes(bytearray([byte ^ 0x64 for byte in key_data])) cryptor = AES.new(core_key, AES.MODE_ECB) key_data = unpad(cryptor.decrypt(key_data))[17:] key_length = len(key_data) # S-box (standard RC4 Key-scheduling algorithm) key = bytearray(key_data) S = bytearray(range(256)) j = 0 for i in range(256): j = (j + S[i] + key[i % key_length]) % 256 S[i], S[j] = S[j], S[i] # meta data meta_length = f.read(4) meta_length = struct.unpack('<I', bytes(meta_length))[0] meta_data = bytearray(f.read(meta_length)) meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data])) meta_data = base64.b64decode(meta_data[22:]) cryptor = AES.new(meta_key, AES.MODE_ECB) meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] meta_data = json.loads(meta_data) # crc32 crc32 = f.read(4) crc32 = struct.unpack('<I', bytes(crc32))[0] # album cover f.seek(5, 1) image_size = f.read(4) image_size = struct.unpack('<I', bytes(image_size))[0] image_data = f.read(image_size) # media data output_path = output_path(input_path, meta_data) if skip and os.path.exists(output_path): return m = open(output_path, 'wb') data = bytearray(f.read()) # stream cipher (modified RC4 Pseudo-random generation algorithm) i = 0 j = 0 for k, _ in enumerate(data): i = (i + 1) % 256 j = (i + S[i]) % 256 # in RC4, is j = (j + S[i]) % 256 # S[i], S[j] = S[j], S[i] # no swapping data[k] ^= S[(S[i] + S[j]) % 256] m.write(data) m.close() f.close() # media tag if meta_data['format'] == 'flac': audio = flac.FLAC(output_path) # audio.delete() image = flac.Picture() image.encoding = 0 image.type = 3 image.mime = 'image/jpeg' image.data = image_data audio.clear_pictures() audio.add_picture(image) elif meta_data['format'] == 'mp3': audio = mp3.MP3(output_path) # audio.delete() image = id3.APIC() image.encoding = 0 image.type = 3 image.mime = 'image/jpeg' image.data = image_data audio.tags.add(image) audio.save() audio = mp3.EasyMP3(output_path) audio['title'] = meta_data['musicName'] audio['album'] = meta_data['album'] audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) audio.save() return output_path
def dumpfile(file_path): # 预定义key core_key = binascii.a2b_hex("687A4852416D736F356B496E62617857") meta_key = binascii.a2b_hex("2331346C6A6B5F215C5D2630553C2728") unpad = lambda s: s[0:-(s[-1] if type(s[-1]) == int else ord(s[-1]))] f = open(file_path, 'rb') # magic header header = f.read(8) assert binascii.b2a_hex(header) == b'4354454e4644414d' # key data f.seek(2, 1) key_length = f.read(4) key_length = struct.unpack('<I', bytes(key_length))[0] key_data = bytearray(f.read(key_length)) key_data = bytes(bytearray([byte ^ 0x64 for byte in key_data])) cryptor = AES.new(core_key, AES.MODE_ECB) key_data = unpad(cryptor.decrypt(key_data))[17:] key_length = len(key_data) # key box key_data = bytearray(key_data) key_box = bytearray(range(256)) j = 0 for i in range(256): j = (key_box[i] + j + key_data[i % key_length]) & 0xff key_box[i], key_box[j] = key_box[j], key_box[i] # meta data meta_length = f.read(4) meta_length = struct.unpack('<I', bytes(meta_length))[0] meta_data = bytearray(f.read(meta_length)) meta_data = bytes(bytearray([byte ^ 0x63 for byte in meta_data])) meta_data = base64.b64decode(meta_data[22:]) cryptor = AES.new(meta_key, AES.MODE_ECB) meta_data = unpad(cryptor.decrypt(meta_data)).decode('utf-8')[6:] meta_data = json.loads(meta_data) # crc32 crc32 = f.read(4) crc32 = struct.unpack('<I', bytes(crc32))[0] # album cover f.seek(5, 1) image_size = f.read(4) image_size = struct.unpack('<I', bytes(image_size))[0] image_data = f.read(image_size) author_name = "" # media data if len(meta_data['artist']) == 1: author_name = meta_data['artist'][0][0] else: for i in range(len(meta_data['artist'])): if i == len(meta_data['artist']) - 1: author_name += meta_data['artist'][i][0] else: author_name += meta_data['artist'][i][0] author_name += ',' file_name = author_name + ' - ' + meta_data['musicName'] + '.' + meta_data['format'] music_path = os.path.join(os.path.split(file_path)[0], file_name) m = open(music_path, 'wb') while True: chunk = bytearray(f.read(0x8000)) chunk_length = len(chunk) if not chunk: break for i in range(chunk_length): j = (i + 1) & 0xff chunk[i] ^= key_box[(key_box[j] + key_box[(key_box[j] + j) & 0xff]) & 0xff] m.write(chunk) m.close() f.close() # media tag if meta_data['format'] == 'flac': audio = flac.FLAC(music_path) # audio.delete() image = flac.Picture() image.type = 3 image.mime = 'image/jpeg' image.data = image_data audio.clear_pictures() audio.add_picture(image) elif meta_data['format'] == 'mp3': audio = mp3.MP3(music_path) # audio.delete() image = id3.APIC() image.type = 3 image.mime = 'image/jpeg' image.data = image_data audio.tags.add(image) audio.save() audio = mp3.EasyMP3(music_path) audio['title'] = meta_data['musicName'] audio['album'] = meta_data['album'] audio['artist'] = '/'.join([artist[0] for artist in meta_data['artist']]) audio.save()