def _write_flac_tags(self, path, track, tags=None): if "DATA" in track: track = track["DATA"] if not tags: tags = self.get_track_tags(track) audio = File(path) audio.delete() cover = tags["_albumart"] del tags["_albumart"] if cover: pic = mutagen.flac.Picture() pic.data = cover["image"] audio.clear_pictures() audio.add_picture(pic) for key, val in tags.items(): if val: audio[key] = str(val) audio.save() return True
def add_flac_cover(filename, albumart): audio = File(str(filename)) image = Picture() image.type = 3 image.mime = "image/jpeg" with open(albumart, 'rb') as f: image.data = f.read() audio.add_picture(image) audio.save()
def writeAlbumCover(songPath: str, coverPath: str, picData=None): """ 给音频文件写入封面 Parameters ---------- songPath: 音频文件路径\n coverPath: 封面图片路径\n picData: 封面图片二进制数据 """ id_card = File(songPath) # 读取封面数据 if not picData: with open(coverPath, 'rb') as f: picData = f.read() # 获取音频数据和图片数据后缀名 audioSuffix = id_card.mime[0].split('/')[-1] try: picSuffix = imghdr.what(None, picData) except: picSuffix = 'jpeg' mimeType = 'image/' + picSuffix # 开始写入封面 if audioSuffix == 'mp3': keyName = 'APIC:' keyName_list = [] # 获取可能已经存在的封面键名 for key in id_card.tags.keys(): if key.startswith('APIC'): keyName = key keyName_list.append(key) # 弹出所有旧标签才能写入新数据 for key in keyName_list: id_card.pop(key) id_card[keyName] = APIC(encoding=0, mime=mimeType, type=3, desc='', data=picData) elif audioSuffix == 'flac': # 创建Picture实例 picture = Picture() # 设置属性值 picture.mime = mimeType picture.data = picData picture.type = 0 # 清除原来的图片数据 id_card.clear_pictures() # 添加图片 id_card.add_picture(picture) elif audioSuffix == 'mp4': try: id_card['covr'][0] = picData except: id_card['covr'] = [picData] # 没有键时需要创建一个 id_card.save()
def writeAlbumCov(file): if file.endswith('c'): audio = File(file) image = Picture() image.type = 3 mime = "image/jpeg" with open("cover.jpg", 'rb') as f: image.data = f.read() audio.clear_pictures() audio.add_picture(image) audio.save() else: audio = MP4(file) with open("cover.jpg", 'rb') as f: audio['covr'] = [MP4Cover(f.read(), imageformat = MP4Cover.FORMAT_JPEG)] audio.save(file)
def add_albumart(working_dir, folder_name, title): audio = File(os.path.join(working_dir, folder_name, f'{title}.flac')) image = Picture() image.type = 3 mime = 'image/png' image.desc = 'front cover' # better than open(albumart, 'rb').read() ? with open( os.path.join(working_dir, folder_name, 'albumart', f'{title}.png'), 'rb') as f: image.data = f.read() audio.add_picture(image) audio.save()
for d in glob.glob(directory + "/*"): # skip files in root directory if not os.path.isdir(d): continue cover = None # get the cover (use the first image found in directory) for f in glob.glob(d + "/*.jp*g"): cover = f break if not cover: print("no cover found in directory [%s]" % d) sys.exit(1) # scan for flac files for flac in glob.glob(d + "/*.flac"): # create mutagen picture object pic = Picture() # open cover file and store into flac file with open(cover, "rb") as c: # read raw picture data from cover file pic.data = c.read() mfile = File(flac) # remove old and add new cover mfile.clear_pictures() mfile.add_picture(pic) mfile.save()
def split_item(item, DIGITAL_FOLDER=mp3_folder, DROPBOX_COPY=False): logging.info('BLOOOAAARRRRGHHGGGGHHHHH!!! (Please hold...)') audio = wave.open(item.path) audio.params = audio.getparams() # Load AudioSegment for encoded segments if item.digital_ext is not 'wav': audio_segment = AudioSegment.from_wav(item.path) # Loop through cues and write regions (assumes start and end markers) for i, track in enumerate(item.tracks): # Build track filename digital_track_name = '{0} - {1} - {2}'.format(item.digital_file_name, str(i + 1), track.title) digital_track_name = ''.join([c for c in digital_track_name if c.isalpha() or c.isdigit() or c in "'- ._()!@#$%^&*"]).rstrip('. ') digital_track_path = os.path.join(DIGITAL_FOLDER, digital_track_name) + '.' + item.digital_ext logging.info('Region {0} | {1} -> {2}'.format(i + 1, track.duration, digital_track_path)) # Split, export track if 'wav' not in item.digital_ext: digital_track = audio_segment[(item.cues[i] / 44.1):(item.cues[i + 1] / 44.1)] tags = {'title':track.title, 'artist':item.artist, 'albumartist':item.artist, 'album':(item.album or item.artist), 'track':(i + 1)} digital_track.export(out_f=digital_track_path, format=item.digital_ext, bitrate='192k', tags=tags) # Add cover art if item.thumb and (item.digital_ext == 'mp3'): mutagen_audio = MP3(digital_track_path, ID3=ID3) try: # Add ID3 tag if it doesn't exist mutagen_audio.add_tags() except error: pass mutagen_audio.tags.add( APIC( encoding=3, # 3 is for utf-8 mime='image/jpeg', # image/jpeg or image/png type=3, # 3 is for the cover image desc=u'Cover', data=open(item.thumb_path, 'rb').read() ) ) mutagen_audio.save() elif item.thumb and (item.digital_ext == 'flac'): mutagen_audio = File(digital_track_path) flac_image = Picture() flac_image.type = 3 mime = 'image/jpeg' flac_image.desc = 'Cover' with open(item.thumb_path, 'rb') as f: flac_image.data = f.read() mutagen_audio.add_picture(flac_image) mutagen_audio.save() else: logging.warning('No cover found for item {0}'.format(item.name)) else: digital_track = wave.open(digital_track_path, 'w') digital_track.setparams(audio.params) region_length = item.cues[i + 1] - item.cues[i] digital_track.writeframes(audio.readframes(region_length)) digital_track.close() if DROPBOX_COPY: # Copy finished digital file to Dropbox order folder shutil.copy2(digital_track_path, item.dropbox_order_folder) audio.close()
class TagTool(object): def __init__(self, filePath): if os.path.isfile(filePath) is False: return self._filepath = filePath self._ext = __extension__(filePath) self._handle = File(filePath) self.title = '' self.album = '' self.albumartist = '' self.artist = '' self.copyright = '' self.tracknumber = '' self.totaltrack = '' self.discnumber = '' self.totaldisc = '' self.genre = '' self.date = '' self.composer = '' self.isrc = '' self.lyrics = '' self.__load__() def save(self, coverPath: str = None): try: if 'mp3' in self._ext: return self.__saveMp3__(coverPath) if 'flac' in self._ext: return self.__saveFlac__(coverPath) if 'mp4' in self._ext or 'm4a' in self._ext: return self.__saveMp4__(coverPath) return False except Exception as e: return False, str(e) def addPic(self, converPath: str = None): try: self.__savePic__(converPath) self._handle.save() return True except Exception as e: return False, str(e) def addLyrics(self, lyrics: str = None): try: if 'mp3' in self._ext: self._handle.tags.add( USLT(encoding=3, lang=u'eng', desc=u'desc', text=__tryStr__(self.lyrics))) if 'flac' in self._ext: self._handle.tags['lyrics'] = __tryStr__(self.lyrics) if 'mp4' in self._ext or 'm4a' in self._ext: self._handle.tags['\xa9lyr'] = __tryStr__(self.lyrics) self._handle.save() return True except Exception as e: return False, str(e) def __load__(self): try: if 'mp3' in self._ext: return self.__getMp3__() if 'flac' in self._ext: return self.__getFlac__() if 'mp4' in self._ext or 'm4a' in self._ext: return self.__getMp4__() except: return def __saveMp3__(self, coverPath): if self._handle.tags is None: self._handle.add_tags() self._handle.tags.add(TIT2(encoding=3, text=self.title)) self._handle.tags.add(TALB(encoding=3, text=self.album)) # self._handle.tags.add(TOPE(encoding=3, text=self.albumartist)) self._handle.tags.add(TPE1(encoding=3, text=self.artist)) self._handle.tags.add(TCOP(encoding=3, text=self.copyright)) self._handle.tags.add(TRCK(encoding=3, text=str(self.tracknumber))) # self._handle.tags.add(TRCK(encoding=3, text=self.discnum)) self._handle.tags.add(TCON(encoding=3, text=self.genre)) self._handle.tags.add(TDRC(encoding=3, text=self.date)) self._handle.tags.add(TCOM(encoding=3, text=self.composer)) self._handle.tags.add(TSRC(encoding=3, text=self.isrc)) self._handle.tags.add( USLT(encoding=3, lang=u'eng', desc=u'desc', text=self.lyrics)) self.__savePic__(coverPath) self._handle.save() return True def __getMp3__(self): if self._handle.tags is None: self._handle.add_tags() def __saveFlac__(self, coverPath): if self._handle.tags is None: self._handle.add_tags() self._handle.tags['title'] = self.title self._handle.tags['album'] = self.album self._handle.tags['albumartist'] = __tryList__(self.albumartist) self._handle.tags['artist'] = __tryList__(self.artist) self._handle.tags['copyright'] = __tryStr__(self.copyright) self._handle.tags['tracknumber'] = str(self.tracknumber) self._handle.tags['tracktotal'] = str(self.totaltrack) self._handle.tags['discnumber'] = str(self.discnumber) self._handle.tags['disctotal'] = str(self.totaldisc) self._handle.tags['genre'] = __tryStr__(self.genre) self._handle.tags['date'] = __tryStr__(self.date) self._handle.tags['composer'] = __tryStr__(self.composer) self._handle.tags['isrc'] = __tryStr__(self.isrc) self._handle.tags['lyrics'] = __tryStr__(self.lyrics) self.__savePic__(coverPath) self._handle.save() return True def __getFlac__(self): if self._handle.tags is None: return self.title = self.__getTagItem__('title') self.album = self.__getTagItem__('album') self.albumartist = self.__getTagItem__('albumartist') self.artist = self.__getTagItem__('artist') self.copyright = self.__getTagItem__('copyright') self.tracknumber = self.__getTagItem__('tracknumber') self.totaltrack = self.__getTagItem__('tracktotal') self.discnumber = self.__getTagItem__('discnumber') self.totaldisc = self.__getTagItem__('disctotal') self.genre = self.__getTagItem__('genre') self.date = self.__getTagItem__('date') self.composer = self.__getTagItem__('composer') self.isrc = self.__getTagItem__('isrc') self.lyrics = self.__getTagItem__('lyrics') def __saveMp4__(self, coverPath): self._handle.tags['\xa9nam'] = self.title self._handle.tags['\xa9alb'] = self.album self._handle.tags['aART'] = __tryList__(self.albumartist) self._handle.tags['\xa9ART'] = __tryList__(self.artist) self._handle.tags['cprt'] = __tryStr__(self.copyright) self._handle.tags['trkn'] = [[ __tryInt__(self.tracknumber), __tryInt__(self.totaltrack) ]] self._handle.tags['disk'] = [[ __tryInt__(self.discnumber), __tryInt__(self.totaldisc) ]] self._handle.tags['\xa9gen'] = __tryStr__(self.genre) self._handle.tags['\xa9day'] = __tryStr__(self.date) self._handle.tags['\xa9wrt'] = __tryList__(self.composer) self._handle.tags['\xa9lyr'] = __tryStr__(self.lyrics) self.__savePic__(coverPath) self._handle.save() return True def __getMp4__(self): self.title = self.__getTagItem__('\xa9nam') self.album = self.__getTagItem__('\xa9alb') self.albumartist = self.__getTagItem__('aART') self.artist = self.__getTagItem__('\xa9ART') self.copyright = self.__getTagItem__('\cprt') self.tracknumber = self.__getTagItem__('trkn') self.totaltrack = self.__getTagItem__('trkn') self.discnumber = self.__getTagItem__('disk') self.totaldisc = self.__getTagItem__('disk') self.genre = self.__getTagItem__('\xa9gen') self.date = self.__getTagItem__('\xa9day') self.composer = self.__getTagItem__('\xa9wrt') self.lyrics = self.__getTagItem__('\xa9lyr') def __getTagItem__(self, name): if name in self._handle.tags: return self._handle.tags[name] return '' def __savePic__(self, coverPath): data = __content__(coverPath) if data is None: return if 'flac' in self._ext: pic = flac.Picture() pic.data = data if '.jpg' in coverPath: pic.mime = u"image/jpeg" self._handle.clear_pictures() self._handle.add_picture(pic) if 'mp3' in self._ext: self._handle.tags.add(APIC(encoding=3, data=data)) if 'mp4' in self._ext or 'm4a' in self._ext: pic = mp4.MP4Cover(data) self._handle.tags['covr'] = [pic]
class TagTool(object): def __init__(self, filePath): if os.path.isfile(filePath) is False: return self._filepath = filePath self._ext = _getExtension(filePath) self._handle = File(filePath) self.title = '' self.album = '' self.albumartist = '' self.artist = '' self.copyright = '' self.tracknumber = '' self.totaltrack = '' self.discnumber = '' self.totaldisc = '' self.genre = '' self.date = '' self.composer = '' self.isrc = '' def save(self, coverPath=None): try: if 'mp3' in self._ext: return self._saveMp3(coverPath) if 'flac' in self._ext: return self._saveFlac(coverPath) if 'mp4' in self._ext or 'm4a' in self._ext: return self._saveMp4(coverPath) return False except: return False def _saveMp3(self, coverPath): self._handle.tags.add(TIT2(encoding=3, text=self.title)) self._handle.tags.add(TALB(encoding=3, text=self.album)) # self._handle.tags.add(TOPE(encoding=3, text=self.albumartist)) self._handle.tags.add(TPE1(encoding=3, text=self.artist)) self._handle.tags.add(TCOP(encoding=3, text=self.copyright)) self._handle.tags.add(TRCK(encoding=3, text=str(self.tracknumber))) # self._handle.tags.add(TRCK(encoding=3, text=self.discnum)) self._handle.tags.add(TCON(encoding=3, text=self.genre)) self._handle.tags.add(TDRC(encoding=3, text=self.date)) self._handle.tags.add(TCOM(encoding=3, text=self.composer)) self._handle.tags.add(TSRC(encoding=3, text=self.isrc)) self._savePic(coverPath) self._handle.save() return True def _saveFlac(self, coverPath): if self._handle.tags is None: self._handle.add_tags() self._handle.tags['title'] = self.title self._handle.tags['album'] = self.album self._handle.tags['albumartist'] = self.albumartist self._handle.tags['artist'] = self.artist self._handle.tags['copyright'] = _noneToEmptyString(self.copyright) self._handle.tags['tracknumber'] = str(self.tracknumber) self._handle.tags['tracktotal'] = str(self.totaltrack) self._handle.tags['discnumber'] = str(self.discnumber) self._handle.tags['disctotal'] = str(self.totaldisc) self._handle.tags['genre'] = _noneToEmptyString(self.genre) self._handle.tags['date'] = _noneToEmptyString(self.date) self._handle.tags['composer'] = _noneToEmptyString(self.composer) self._handle.tags['isrc'] = str(self.isrc) self._savePic(coverPath) self._handle.save() return True def _saveMp4(self, coverPath): self._handle.tags['\xa9nam'] = self.title self._handle.tags['\xa9alb'] = self.album self._handle.tags['aART'] = _getArrayStr(self.albumartist) self._handle.tags['\xa9ART'] = _getArrayStr(self.artist) self._handle.tags['cprt'] = _noneToEmptyString(self.copyright) self._handle.tags['trkn'] = [[_tryInt(self.tracknumber), _tryInt(self.totaltrack)]] self._handle.tags['disk'] = [[_tryInt(self.discnumber), _tryInt(self.totaldisc)]] self._handle.tags['\xa9gen'] = _noneToEmptyString(self.genre) self._handle.tags['\xa9day'] = _noneToEmptyString(self.date) self._handle.tags['\xa9wrt'] = _getArrayStr(self.composer) self._savePic(coverPath) self._handle.save() return True def _savePic(self, coverPath): data = _getFileData(coverPath) if data is None: return if 'flac' in self._ext: pic = flac.Picture() pic.data = data if pathHelper.getFileExtension(coverPath) == '.jpg': pic.mime = u"image/jpeg" self._handle.clear_pictures() self._handle.add_picture(pic) if 'mp3' in self._ext: self._handle.tags.add(APIC(encoding=3, data=data)) if 'mp4' in self._ext or 'm4a' in self._ext: pic = mp4.MP4Cover(data) self._handle.tags['covr'] = [pic]
def update_picture(flac_file: mutagen.File, picture: mutagen.flac.Picture): flac_file.clear_pictures() flac_file.add_picture(picture)
def process_a_file(self, input_path, output_dir): au_id = input_path.name if not au_id.isdigit(): print(f'unexpected file: {input_path}') return au_id = int(au_id) file_kind = File(input_path) if isinstance(file_kind, MP4): suffix = '.m4a' elif isinstance(file_kind, FLAC): suffix = '.flac' elif file_kind is None: raise TypeError('unknown file kind') else: raise TypeError( f'unsupport file kind {file_kind.__class__.__name__}') audio_info = self.audio_cache.get(au_id) filename = f'{spilt_artist_str(audio_info["author"])[0]} - {audio_info["title"]}{suffix}' output_path = output_dir / filename if not self.overwrite and output_path.is_file(): print(f'{filename} exists, skipped') return print(f'processing: {filename}') shutil.copyfile(input_path, output_path) album_id = audio_info['pgc_info']['pgc_menu']['menuId'] album_info = self.album_cache.get(album_id) album_cover_url = album_info['menusRespones']['coverUrl'] album_au_ids = list(map(lambda x: x['id'], album_info['songsList'])) track_id = album_au_ids.index(au_id) assert album_cover_url == album_info['songsList'][track_id][ 'cover_url'] album_cover_path = self.cover_cache.get(album_cover_url) if album_cover_path.suffix == '.jpg': image_format = AtomDataType.JPEG elif album_cover_path.suffix == '.png': image_format = AtomDataType.PNG else: raise TypeError( f'Unsupport format: {album_cover_path.suffix}, Only support jpg and png.' ) with album_cover_path.open('rb') as fp: cover_image = fp.read() audio_file = File(output_path) if isinstance(audio_file, MP4): tags = { '\xa9nam': audio_info['title'], '\xa9alb': album_info['menusRespones']['title'], '\xa9ART': format_artist_list(spilt_artist_str(audio_info['author'])), '\xa9day': str( get_year_from_timestamp( album_info['menusRespones']['pbtime'])), 'aART': format_artist_list( spilt_artist_str(album_info['menusRespones']['mbnames'])), 'trkn': [(track_id + 1, album_info['menusRespones']['songNum'])], 'disk': [(1, 1)], 'covr': [MP4Cover(cover_image, imageformat=image_format)], } elif isinstance(audio_file, FLAC): tags = { 'ALBUM': album_info['menusRespones']['title'], 'ARTIST': format_artist_list(spilt_artist_str(audio_info['author'])), 'ALBUMARTIST': format_artist_list( spilt_artist_str(album_info['menusRespones']['mbnames'])), 'DATE': str( get_year_from_timestamp( album_info['menusRespones']['pbtime'])), 'TITLE': audio_info['title'], 'DISCNUMBER': '1', 'DISCTOTAL': '1', 'TRACKTOTAL': str(album_info['menusRespones']['songNum']), 'TRACKNUMBER': str(track_id + 1), } picture = Picture() picture.data = cover_image picture.type = PictureType.COVER_FRONT audio_file.add_picture(picture) audio_file.update(tags) audio_file.save()
def split_item(item, digital_folder=digital_folder, dropbox_move=True): logging.info("BLOOOAAARRRRGHHGGGGHHHHH!!! (Please hold...)") audio = wave.open(item.path) audio.params = audio.getparams() # Load AudioSegment for encoded segments if item.digital_ext is not "wav": audio_segment = AudioSegment.from_wav(item.path) # Loop through cues and write regions (assumes start and end markers) for i, track in enumerate(item.tracks): # Build track filename digital_track_name = "{0} - {1} - {2}".format(item.digital_file_name, str(i + 1), track.title) digital_track_name = "".join( [c for c in digital_track_name if c.isalpha() or c.isdigit() or c in "'- ._()!@#$%^&*"] ).rstrip(". ") if dropbox_move: digital_track_path = os.path.join(item.dropbox_order_folder, digital_track_name) + "." + item.digital_ext else: digital_track_path = os.path.join(digital_folder, digital_track_name) + "." + item.digital_ext logging.info("Region {0} | {1} -> {2}".format(i + 1, track.duration, digital_track_path)) # Split, export track if "wav" not in item.digital_ext: digital_track = audio_segment[(item.cues[i] / 44.1) : (item.cues[i + 1] / 44.1)] tags = { "title": track.title or "Track {0}".format(i + 1), "artist": item.artist, "albumartist": item.artist, "album": (item.album or item.artist), "track": (i + 1), } digital_track.export( out_f=digital_track_path, format=item.digital_ext, bitrate=item.bitrate, tags=tags, id3v2_version="3" ) # Add cover art if item.thumb and (item.digital_ext == "mp3"): mutagen_audio = MP3(digital_track_path, ID3=ID3) try: # Add ID3 tag if it doesn't exist mutagen_audio.add_tags() except error: pass mutagen_audio.tags.add( APIC( encoding=3, # 3 is for utf-8 mime="image/jpeg", # image/jpeg or image/png type=3, # 3 is for the cover image desc=u"Cover", data=open(item.thumb_path, "rb").read(), ) ) mutagen_audio.save(v2_version=3) elif item.thumb and (item.digital_ext == "flac"): mutagen_audio = File(digital_track_path) flac_image = Picture() flac_image.type = 3 mime = "image/jpeg" flac_image.desc = "Cover" with open(item.thumb_path, "rb") as f: flac_image.data = f.read() mutagen_audio.add_picture(flac_image) mutagen_audio.save() else: logging.warning("No cover found for item {0}".format(item.name)) else: digital_track = wave.open(digital_track_path, "w") digital_track.setparams(audio.params) region_length = item.cues[i + 1] - item.cues[i] digital_track.writeframes(audio.readframes(region_length)) digital_track.close() audio.close()