class FlacStripper(MutagenStripper): """ Represent a Flac audio file """ def _create_mfile(self): self.mfile = FLAC(self.filename) def remove_all(self): """ Remove the "metadata" block from the file """ super(FlacStripper, self).remove_all() self.mfile.clear_pictures() self.mfile.save() return True def is_clean(self): """ Check if the "metadata" block is present in the file """ return super(FlacStripper, self).is_clean() and not self.mfile.pictures def get_meta(self): """ Return the content of the metadata block if present """ metadata = super(FlacStripper, self).get_meta() if self.mfile.pictures: metadata['picture:'] = 'yes' return metadata
class MetaFLAC(MetaAudio): def __init__(self, path): self.audio_path = path self.audio = FLAC(path) try: if 'albumartist' in self.audio: # use Album Artist first self.artist = self.audio['albumartist'][0] else: self.artist = self.audio['artist'][0] self.album = self.audio['album'][0] self.title = self.audio['title'][0] except Exception: raise Exception("missing FLAC tags") def has_embedded_art(self): return self.audio.pictures != [] def detach_art(self): self.audio.clear_pictures() def embed_art(self, art_path): pic = Picture() with open(art_path, "rb") as f: pic.data = f.read() pic.type = 3 # front cover pic.mime = MetaAudio.get_mime_type(art_path) pic.desc = 'front cover' self.audio.add_picture(pic) def save(self): self.audio.save()
def main(): print("start") tracks = [] root = tkinter.Tk() root.withdraw() root.update() folder = askdirectory(title = "choose the dir u want to delete on tags in",initialdir = r"C:\Users\User\Desktop", mustexist=True ) root.destroy() for root, dirs, files, in os.walk(folder): for name in files: if name.endswith((".mp3", ".flac")): print("the name= "+os.path.splitext(name)[0]) print("the type= "+os.path.splitext(name)[1]) if(name.endswith(".flac")): print("its .flac") audio=FLAC(root + "\\" + name) audio.delete() audio.clear_pictures() audio.save() if(name.endswith(".mp3")): print("its .mp3") audio=MP3(root + "\\" + name) audio.delete() audio.clear() audio.save()
def on_save(self): audio = FLAC(self.song.get("~filename", "")) ## if file has no images -> leave if (audio.pictures is None) or (len(audio.pictures) <= 0): return ## first,clear all pictures, then add the images in order try: audio.clear_pictures() except: self.printError() return False for row in self.liststore: img = row[1] try: audio.add_picture(img) except: self.printError() return False audio.save() count = 0 if (audio.pictures is None) or (len(audio.pictures) <= 0): pass else: count = str(len(audio.pictures)) self.song["pictures"] = count app.window.emit("artwork-changed", [self.song]) del self.coverlist[:] self.liststore.clear() self.start_search() return True
def test_clear_pictures(self): f = FLAC(self.NEW) c1 = len(f.pictures) c2 = len(f.metadata_blocks) f.clear_pictures() f.save() f = FLAC(self.NEW) self.failUnlessEqual(len(f.metadata_blocks), c2 - c1)
def add_flac_image_set(self,filename, images): audio = FLAC(filename) if self.replace_images: audio.clear_pictures() for img in images: self.add_flac_cover(audio, img['file'], desc=img['desc'], file_type=img['type']) print(f'{filename} images updated') audio.save()
def write_tags(song, data): try: tag = FLAC(song) tag.delete() images = Picture() images.type = 3 images.data = data["image"] tag.clear_pictures() tag.add_picture(images) tag["lyrics"] = data["lyric"] except FLACNoHeaderError: try: tag = File(song, easy=True) tag.delete() except: if isfile(song): remove(song) raise exceptions.TrackNotFound("") except NOTVALIDSONG: raise exceptions.TrackNotFound("") tag["artist"] = data["artist"] tag["title"] = data["music"] tag["date"] = data["year"] tag["album"] = data["album"] tag["tracknumber"] = data["tracknum"] tag["discnumber"] = data["discnum"] tag["genre"] = data["genre"] tag["albumartist"] = data["ar_album"] tag["author"] = data["author"] tag["composer"] = data["composer"] tag["copyright"] = data["copyright"] tag["bpm"] = data["bpm"] tag["length"] = data["duration"] tag["organization"] = data["label"] tag["isrc"] = data["isrc"] tag["lyricist"] = data["lyricist"] tag.save() try: audio = ID3(song) audio.add( APIC( encoding=3, mime="image/jpeg", type=3, desc=u"Cover", data=data["image"], )) audio.add( USLT(encoding=3, lang=u"eng", desc=u"desc", text=data["lyric"])) audio.save() except ID3NoHeaderError: pass
def cleanTags(filepath): if Path(filepath).suffix == ".flac": audiof = FLAC(filepath) audiof.clear_pictures() audiof.delete() elif Path(filepath).suffix == ".mp3": audiof = EasyID3(filepath) audiof.delete() audiof.save()
def embed_cover_art(self, audio_file, cover_file): """Embeds cover art into an audio file. Arguments: audio_file (str): The path to the audio file to embed the artwork in. cover_file (str): The path to the artwork file to embed. """ if path.isfile(audio_file) and path.isfile(cover_file): mimetype = "image/png" if cover_file.endswith("png") else "image/jpeg" artwork = open(cover_file, "rb").read() desc = u"Cover Art" # Determine which filetype we're handling if audio_file.endswith("m4a"): audio = MP4(audio_file) covr = [] if cover_file.endswith("png"): covr.append(MP4Cover(artwork, MP4Cover.FORMAT_PNG)) else: covr.append(MP4Cover(artwork, MP4Cover.FORMAT_JPEG)) audio.tags["covr"] = covr elif audio_file.endswith("mp3"): audio = MP3(audio_file, ID3=ID3) # Add ID3 tags if they don't exist try: audio.add_tags() except error: pass audio.tags.add( APIC( encoding=3, # 3 is UTF-8 mime=mimetype, type=3, # 3 is for cover artwork desc=desc, data=artwork, ) ) elif audio_file.endswith("flac"): audio = FLAC(audio_file) image = Picture() image.type = 3 # 3 is for cover artwork image.mime = mimetype image.desc = desc image.data = artwork audio.clear_pictures() # Clear existing pictures audio.add_picture(image) # Save the audio file audio.save()
def write_tags(song, data): try: tag = FLAC(song) tag.delete() images = Picture() images.type = 3 images.data = data['image'] tag.clear_pictures() tag.add_picture(images) tag['lyrics'] = data['lyric'] except FLACNoHeaderError: try: tag = File(song, easy=True) tag.delete() except: raise exceptions.TrackNotFound("") except error: raise exceptions.TrackNotFound("") tag['artist'] = data['artist'] tag['title'] = data['music'] tag['date'] = data['year'] tag['album'] = data['album'] tag['tracknumber'] = data['tracknum'] tag['discnumber'] = data['discnum'] tag['genre'] = data['genre'] tag['albumartist'] = data['ar_album'] tag['author'] = data['author'] tag['composer'] = data['composer'] tag['copyright'] = data['copyright'] tag['bpm'] = data['bpm'] tag['length'] = data['duration'] tag['organization'] = data['label'] tag['isrc'] = data['isrc'] tag['replaygain_*_gain'] = data['gain'] tag['lyricist'] = data['lyricist'] tag.save() try: audio = ID3(song) audio.add( APIC(encoding=3, mime="image/jpeg", type=3, desc=u"Cover", data=data['image'])) audio.add( USLT(encoding=3, lang=u"eng", desc=u"desc", text=data['lyric'])) audio.save() except _util.ID3NoHeaderError: pass
def remove_all(self): ''' Remove the "metadata" block from the file ''' if self.backup is True: shutil.copy2(self.filename, self.output) self.filename = self.output mfile = FLAC(self.filename) mfile.delete() mfile.clear_pictures() mfile.save()
def clear_images(self): """Delete all embedded images""" with translate_errors(): tag = FLAC(self["~filename"]) tag.clear_pictures() tag.save() # clear vcomment tags super().clear_images() self.has_images = False
def clear_images(self): """Delete all embedded images""" with translate_errors(): tag = FLAC(self["~filename"]) tag.clear_pictures() tag.save() # clear vcomment tags super(FLACFile, self).clear_images() self.has_images = False
def tag_flac(path_audio,path_pic,lrc,title,artist,album,disc,track,**kw): ''' ref: https://www.xiph.org/vorbis/doc/v-comment.html FLAC tags also call Vorbis comment. It doesn't support lyrics. So use ID3 to tag FLAC instead FLAC tags. ''' tags=FLAC(path_audio) tags.clear() tags.clear_pictures() tags.save() tag_mp3(path_audio,path_pic,lrc,title,artist,album,disc,track,**kw)
def update_flac(self, path: str, track: beatport.Track): f = FLAC(path) if UpdatableTags.title in self.config.update_tags and self.config.overwrite: f['TITLE'] = track.title if UpdatableTags.artist in self.config.update_tags and self.config.overwrite: f['ARTIST'] = 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 f.get('ALBUM') == None): f['ALBUM'] = track.album.name if UpdatableTags.label in self.config.update_tags and ( self.config.overwrite or f.get('LABEL') == None): f['LABEL'] = track.label.name if UpdatableTags.bpm in self.config.update_tags and ( self.config.overwrite or f.get('BPM') == None): f['BPM'] = str(track.bpm) if UpdatableTags.genre in self.config.update_tags and ( self.config.overwrite or f.get('GENRE') == None): f['GENRE'] = ', '.join([g.name for g in track.genres]) if UpdatableTags.date in self.config.update_tags and ( self.config.overwrite or f.get('DATE') == None): f['DATE'] = track.release_date.strftime('%Y-%m-%d') #Year - part of date if UpdatableTags.key in self.config.update_tags and ( self.config.overwrite or f.get('INITIALKEY') == None): f['INITIALKEY'] = track.id3key() if UpdatableTags.publishdate in self.config.update_tags and ( self.config.overwrite or f.get('ORIGINALDATE') == None): f['ORIGINALDATE'] = str(track.publish_date.year) #Other tags if UpdatableTags.other in self.config.update_tags: f['WWWAUDIOFILE'] = track.url() f['WWWPUBLISHER'] = track.label.url('label') #Redownlaod cover if self.config.replace_art: try: url = track.art(self.config.art_resolution) r = requests.get(url) image = Picture() image.type = 3 image.mime = 'image/jpeg' image.desc = 'Cover' image.data = r.content f.clear_pictures() f.add_picture(image) except Exception: logging.warning('Error downloading cover for file: ' + path) f.save()
class _FLACWrapper(_AbstractWrapper): VALID_TAG_KEYS = ( 'artwork', 'artist', 'album', 'title', 'genre', ) def __init__(self, filename): _AbstractWrapper.__init__(self) self.audio = FLAC(filename) def __getattr__(self, attr): if attr in self.VALID_TAG_KEYS: if attr == 'artwork': if self.audio.pictures: picture = self.audio.pictures[0] return Artwork(picture.mime, picture.data) else: return None else: try: return self.audio[attr][0] except KeyError: return None raise TagError(self, attr) def __setattr__(self, attr, value): if attr in self.VALID_TAG_KEYS: if isinstance(value, Artwork): picture = Picture() picture.type = 3 picture.mime = value.mime picture.data = value.data self.audio.clear_pictures() self.audio.add_picture(picture) elif isinstance(value, str): self.audio[attr] = [value] else: raise TagValueError(value) else: object.__setattr__(self, attr, value) def __repr__(self): return repr(self.audio) def save(self): self.audio.save()
def clear_images(self): """Delete all embedded images""" try: tag = FLAC(self["~filename"]) except EnvironmentError: return tag.clear_pictures() tag.save() # clear vcomment tags super(FLACFile, self).clear_images() self.has_images = False
def _image_flac(self): if self.image and cfg.embed_cover: audio = FLAC(self.path) img = Picture() img.type = 3 img.data = requests.get(self.image).content if cfg.overwrite_cover: audio.clear_pictures() audio.add_picture(img) self.cover_updated = True else: if self.cover_embedded is False: audio.clear_pictures() audio.add_picture(img) self.cover_updated = True audio.save()
def test_invalid_overflow_recover_and_save_back(self): # save a picture which is too large for flac, but still write it # with a wrong block size f = FLAC(self.filename) f.clear_pictures() pic = Picture() pic.data = b"\x00" * (2**24 - 32) pic._invalid_overflow_size = 42 f.add_picture(pic) f.save() # make sure we can read it and save it again f = FLAC(self.filename) self.assertTrue(f.pictures) self.assertEqual(len(f.pictures[0].data), 2**24 - 32) f.save()
def test_invalid_overflow_recover_and_save_back(self): # save a picture which is too large for flac, but still write it # with a wrong block size f = FLAC(self.filename) f.clear_pictures() pic = Picture() pic.data = b"\x00" * (2 ** 24 - 32) pic._invalid_overflow_size = 42 f.add_picture(pic) f.save() # make sure we can read it and save it again f = FLAC(self.filename) self.assertTrue(f.pictures) self.assertEqual(len(f.pictures[0].data), 2 ** 24 - 32) f.save()
def setImage(self, song): audio = FLAC(song.get("~filename", "")) ## if file has no images -> leave if (audio.pictures is None) or (len(audio.pictures) <= 0): return ## if first image is frontcover -> leave img = audio.pictures[0] if img.type == 3: return ## ok, we have to lookup the data... images = list() frontcover = None for img in audio.pictures: if img.type == 3: frontcover = img else: images.append(img) ## if file has no frontcover -> leave if (frontcover is None): print( _("No frontcover found in {!s}.").format( song.get("~filename", ""))) return ## first,clear all pictures, then add the frontcover try: audio.clear_pictures() audio.add_picture(frontcover) except: self.printError() return False ## now add all other images for img in images: try: audio.add_picture(img) except: self.printError() return False audio.save() app.window.emit("artwork-changed", [song]) return
def removeImage(self, song): audio = FLAC(song.get("~filename", "")) store = False ## if file has no images -> leave if (audio.pictures is None) or (len(audio.pictures) <= 0): return images = list() for img in audio.pictures: if img.type == self.type \ and img.desc == self.desc: store = True else: images.append(img) if store: ## first,clear all pictures, then add the frontcover try: audio.clear_pictures() except: self.printError() return False ## now add all other images for img in images: try: audio.add_picture(img) except: self.printError() return False audio.save() ## and now count the images count = "0" ## if file has no images -> set to 0 if (audio.pictures is None) or (len(audio.pictures) <= 0): pass else: count = str(len(audio.pictures)) if not "pictures" in song: song["pictures"] = count if song["pictures"] <> count: song["pictures"] = count app.window.emit("artwork-changed", [song]) return
class _FLACWrapper(_AbstractWrapper): VALID_TAG_KEYS = ('artwork', 'artist', 'album', 'title', 'genre', ) def __init__(self, filename): _AbstractWrapper.__init__(self) self.audio = FLAC(filename) def __getattr__(self, attr): if attr in self.VALID_TAG_KEYS: if attr == 'artwork': if self.audio.pictures: picture = self.audio.pictures[0] return Artwork(picture.mime, picture.data) else: return None else: try: return self.audio[attr][0] except KeyError: return None raise TagError(self, attr) def __setattr__(self, attr, value): if attr in self.VALID_TAG_KEYS: if isinstance(value, Artwork): picture = Picture() picture.type = 3 picture.mime = value.mime picture.data = value.data self.audio.clear_pictures() self.audio.add_picture(picture) elif isinstance(value, str): self.audio[attr] = [value] else: raise TagValueError(value) else: object.__setattr__(self, attr, value) def __repr__(self): return repr(self.audio) def save(self): self.audio.save()
def clearCoverArt(self): for fileShortName in os.listdir(self.path): fileName = os.path.join(self.path,fileShortName) if os.path.isdir(fileName): continue try: metadata = FLAC(fileName) except FLACNoHeaderError as (strerror): self.log.info("strerror=%s" % ( strerror)) continue except error as E: self.log.info("strerror=%s" % ( E)) continue metadata.clear_pictures() metadata.save() del(metadata)
def setImage(self, song): audio = FLAC(song.get("~filename", "")) ## if file has no images -> leave if (audio.pictures is None) or (len(audio.pictures) <= 0): return ## if first image is frontcover -> leave img = audio.pictures[0] if img.type == 3: return ## ok, we have to lookup the data... images = list() frontcover = None for img in audio.pictures: if img.type == 3: frontcover = img else: images.append(img) ## if file has no frontcover -> leave if (frontcover is None): print(_("No frontcover found in {!s}.").format(song.get("~filename", ""))) return ## first,clear all pictures, then add the frontcover try: audio.clear_pictures() audio.add_picture(frontcover) except: self.printError() return False ## now add all other images for img in images: try: audio.add_picture(img) except: self.printError() return False audio.save() app.window.emit("artwork-changed", [song]) return
def set_tag_info_flac(f_path, tag_info, cover_data=None): if tag_info.get('date'): tag_info['date'] = tag_info['date'] + 'Z' if tag_info.get('tracknumber'): tag_info['tracknumber'], tag_info['tracktotal'] = tag_info['tracknumber'].split('/') if tag_info.get('discnumber'): tag_info['discnumber'], tag_info['disctotal'] = tag_info['discnumber'].split('/') audio = FLAC(f_path) audio.delete() for key in tag_info.keys(): audio[key] = tag_info[key] if cover_data: pic = mutagen.flac.Picture() pic.mime = 'image/jpeg' pic.type = 3 pic.data = cover_data audio.clear_pictures() audio.add_picture(pic) audio.save()
def _tag_flac(self, file): """ Tag Flac file only called from `track.tag()` """ tagger = Tagger(self, '.flac') tag = FLAC(file) tag.delete() for tag_obj in tagger.tag_map: tag[tag_obj.key] = str(tag_obj.value) # image if cc.tag_cover and self.album.picture_url is not None: cover_data = self.get_cover_data() if cover_data: img = Picture() img.type = 3 img.data = cover_data tag.clear_pictures() tag.add_picture(img) else: log.warning(f'No Cover for {self}') tag.save()
def reset_flac_tags(full_path): f = FLAC(full_path) t = f.tags # we need to save the 'vendor' string because calling mutagen's delete() removes it too for block in list(f.metadata_blocks): if isinstance(block, VCFLACDict): vendor = block.vendor f.clear_pictures() f.delete() for item in 'artist', 'album', 'tracknumber', 'tracktotal', 'title', 'date': if item in t: f[item] = t[item] for block in list(f.metadata_blocks): if isinstance(block, VCFLACDict): block.vendor = vendor f.save(deleteid3=True)
def tag(file_path: Path, track: Track) -> None: """ Tag the music file at the given file path using the specified [Track][deethon.types.Track] instance. Args: file_path (Path): The music file to be tagged track: The [Track][deethon.types.Track] instance to be used for tagging. """ ext = file_path.suffix if ext == ".mp3": tags = ID3() tags.clear() tags.add(Frames["TALB"](encoding=3, text=track.album.title)) tags.add(Frames["TBPM"](encoding=3, text=str(track.bpm))) tags.add(Frames["TCON"](encoding=3, text=track.album.genres)) tags.add(Frames["TCOP"](encoding=3, text=track.copyright)) tags.add(Frames["TDAT"](encoding=3, text=track.release_date.strftime("%d%m"))) tags.add(Frames["TIT2"](encoding=3, text=track.title)) tags.add(Frames["TPE1"](encoding=3, text=track.artist)) tags.add(Frames["TPE2"](encoding=3, text=track.album.artist)) tags.add(Frames["TPOS"](encoding=3, text=str(track.disk_number))) tags.add(Frames["TPUB"](encoding=3, text=track.album.label)) tags.add(Frames["TRCK"]( encoding=3, text=f"{track.number}/{track.album.total_tracks}")) tags.add(Frames["TSRC"](encoding=3, text=track.isrc)) tags.add(Frames["TYER"](encoding=3, text=str(track.release_date.year))) tags.add(Frames["TXXX"](encoding=3, desc="replaygain_track_gain", text=str(track.replaygain_track_gain))) if track.lyrics: tags.add(Frames["USLT"](encoding=3, text=track.lyrics)) tags.add(Frames["APIC"](encoding=3, mime="image/jpeg", type=3, desc="Cover", data=track.album.cover_xl)) tags.save(file_path, v2_version=3) else: tags = FLAC(file_path) tags.clear() tags["album"] = track.album.title tags["albumartist"] = track.album.artist tags["artist"] = track.artist tags["bpm"] = str(track.bpm) tags["copyright"] = track.copyright tags["date"] = track.release_date.strftime("%Y-%m-%d") tags["genre"] = track.album.genres tags["isrc"] = track.isrc if track.lyrics: tags["lyrics"] = track.lyrics tags["replaygain_track_gain"] = str(track.replaygain_track_gain) tags["title"] = track.title tags["tracknumber"] = str(track.number) tags["year"] = str(track.release_date.year) cover = Picture() cover.type = 3 cover.data = track.album.cover_xl cover.width = 1000 cover.height = 1000 tags.clear_pictures() tags.add_picture(cover) tags.save(deleteid3=True)
print ["Sorry, i need piece of covert art labeled: ", picpath] p_data = open(picpath).read() # pic = Picture( # 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=p_data # ) # apic = 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=p_data # ) pic = Picture() pic.load(open(picpath)) flaccount = 0 flext = re.compile(".*\.flac") for f in files: if re.search(flext, f) != None: flaccount = flaccount + 1 ftag = FLAC(f) ftag.clear_pictures() ftag.add_picture(pic) ftag.save exit(0)
artists_str = artists_str[1:] artists.append(artists_str) audio['artist'] = artists audio['album'] = track['al']['name'] image = Picture() image.type = 3 image.desc = 'front cover' image.mime = 'image/jpeg' image.width = 640 image.height = 640 image.data = open(cover_file_path, 'rb').read() audio.save() audio.clear_pictures() audio.add_picture(image) log.debug(audio.tags) audio.save() except FLACNoHeaderError: log.error('Not a validate FLAC file!') playlist_tracks.append(track) track_error[track['id']] = 1 continue except Exception as e: log.error('Error while adding metadata: ' + str(e)) playlist_tracks.append(track) track_error[track['id']] = 1 continue # delete cover file
def clear_pictures(filename): audio = FLAC(filename) audio.clear_pictures() audio.save() print(' Cleared pictures.')
'ffmpeg', '-i', tag_path[i], '-ac', '2', '-acodec', 'flac', 'tag.flac' ] try: subprocess.check_output(cli_args) except: print("convert tag flac error") # read tag info tag_info = FLAC('tag.flac') key_list = tag_info.keys() # write tag info audio_flac = FLAC(flac_path[i]) audio_flac.clear() audio_flac.clear_pictures() for key in key_list: audio_flac[key] = tag_info[key] # write cover image info if os.path.exists('./cover.jpg'): img = fimg() img.type = 3 img.mime = 'image/jpg' img.desc = 'front cover' img.colors = 0 img.data = open('cover.jpg', mode='rb').read() audio_flac.add_picture(img) # save music info audio_flac.save()
class FileInfo(object): """Read and write FLAC metadata. Variables: - path: The FLAC file. - parse_ok: True if the file was parsed successfully. If False, most other variables will be None. - parse_exception: The exception raised during parsing, or None. - streaminfo: The file's StreamInfo. - cuesheet: The file's CueSheet. - tags: The file's Tags. This class supports only one picture per type. """ def __init__(self, path): self.path = str(path) self.parse() @property def summary(self): """Return a Summary for this FileInfo.""" return Summary(self) def parse(self): """Read the FLAC file and update the variables.""" try: self._flac = FLAC(self.path) info = self._flac.info self.streaminfo = StreamInfo( info.channels, info.bits_per_sample, info.sample_rate, info.total_samples ) if self._flac.cuesheet is not None: self.cuesheet = CueSheet(self._flac.cuesheet) else: self.cuesheet = None self.tags = Tags(self._flac.tags) self.parse_ok = True self.parse_exception = None except Exception as e: self.parse_ok = False self.parse_exception = e self.streaminfo = None self.cuesheet = None self.tags = None def update(self): """Save the current metadata and re-parse the FLAC file.""" self._flac.save() self.parse() def pictures(self): """Return a tuple of Pictures, or None.""" if self.parse_ok: return tuple(self._picture_m2f(p) for p in self._flac.pictures) else: return None def get_picture(self, type_): """Return the Picture of the given type, or None.""" result = None if self.parse_ok: matches = [p for p in self._flac.pictures if p.type == type_] if matches: result = self._picture_m2f(matches[0]) return result def set_picture(self, picture): """Set or replace the Picture of its type. Returns True if anything changed. """ changed = False old = self.get_picture(picture.type) if old != picture: self.remove_picture(picture.type) self._flac.add_picture(self._picture_f2m(picture)) changed = True return changed def remove_picture(self, type_): """Remove the picture of the given type. Returns True if anything changed. """ changed = False pics = self._flac.pictures keep = [p for p in pics if p.type != type_] if len(pics) != len(keep): self._flac.clear_pictures() for picture in keep: self._flac.add_picture(picture) changed = True return changed @staticmethod def _picture_m2f(mutagen_picture): """Create a Flackup Picture from a Mutagen Picture.""" return Picture( mutagen_picture.type, mutagen_picture.mime, mutagen_picture.width, mutagen_picture.height, mutagen_picture.depth, mutagen_picture.data ) @staticmethod def _picture_f2m(flackup_picture): """Create a Mutagen Picture from a Flackup Picture.""" picture = MutagenPicture() picture.type = flackup_picture.type picture.mime = flackup_picture.mime picture.width = flackup_picture.width picture.height = flackup_picture.height picture.depth = flackup_picture.depth picture.data = flackup_picture.data return picture
class Track(object): def __init__(self, fileType, pathList, fileName, audioTagPath): # ID3 tags self.title = '' self.artists = [] self.albumTitle = '' self.albumArtist = '' self.year = '' # YYYY self.date = '' # YYYY-MM-DD self.performers = [] self.composedPerformer = [] self.composers = '' self.genres = [] self.producers = [] self.label = '' self.trackNumber = 0 self.totalTrack = 0 self.discNumber = 0 self.totalDisc = 0 self.bpm = '' self.lang = '' self.compilation = '' # Computed self.audioTagPath = audioTagPath self.audioTag = {} self.feat = [] self.remix = [] self.hasCover = False self.cover = {} self.coverType = '' self.coverDesc = '' # Filesystem path and name as lists (separator is ` - `) self.pathList = pathList self.fileType = fileType self.fileName = fileName # Filename as a string # %releaseArtists% - %year% - %albumTitle% - %discNumber%%trackNumber% - %artists% - %title% self.fileNameList = [] self.folderNameList = [] # %year% - %albumTitle% # Self fill if fileType == 'MP3': self.audioTag = ID3(audioTagPath) self._fillFromMP3() elif fileType == 'FLAC': self.audioTag = FLAC(audioTagPath) self._fillFromFLAC() self._computeInternals() # Read the mp3 track ID3 tags and extract all interresting values into a Track object def _fillFromMP3(self): if 'TIT2' in self.audioTag and self.audioTag['TIT2'].text[0] != '': self.title = self.audioTag['TIT2'].text[0].rstrip() if 'TPE1' in self.audioTag: self.artists = self.audioTag['TPE1'].text[0].split('; ') if 'TPE2' in self.audioTag: self.albumArtist = self.audioTag['TPE2'].text[0].rstrip() if 'TALB' in self.audioTag: self.albumTitle = self.audioTag['TALB'].text[0].rstrip() if 'TDRC' in self.audioTag and self.audioTag['TDRC'].text[0].get_text( ) != '': self.year = self.audioTag['TDRC'].text[0].get_text()[:4].rstrip() if 'TPUB' in self.audioTag and self.audioTag['TPUB'].text[0] != '': self.producers = self.audioTag['TPUB'].text[0].rstrip().split('; ') if 'TCOP' in self.audioTag and self.audioTag['TCOP'].text[0] != '': self.label = self.audioTag['TCOP'].text[0].rstrip() if 'TCOM' in self.audioTag and self.audioTag['TCOM'].text[0] != '': self.composers = self.audioTag['TCOM'].text[0].rstrip().split('; ') if 'TOPE' in self.audioTag and self.audioTag['TOPE'].text[0] != '': self.performers = self.audioTag['TOPE'].text[0].rstrip().split( '; ') if 'TLAN' in self.audioTag: self.lang = self.audioTag['TLAN'].text[0].rstrip().split('; ') if 'TRCK' in self.audioTag and self.audioTag['TRCK'].text[0] != '': if '/' in self.audioTag['TRCK'].text[0]: tags = self.audioTag['TRCK'].text[0].rstrip().split('/') self.trackNumber = tags[0] self.totalTrack = tags[1] else: self.trackNumber = self.audioTag['TRCK'].text[0].rstrip() if 'TPOS' in self.audioTag and self.audioTag['TPOS'].text[0] != '': tags = self.audioTag['TPOS'].text[0].rstrip().split('/') self.discNumber = tags[0] if len(tags) > 1: self.totalDisc = tags[1] else: self.totalDisc = -1 if 'TBPM' in self.audioTag and self.audioTag['TBPM'].text[0] != '': self.bpm = self.audioTag['TBPM'].text[0].rstrip() if 'TCMP' in self.audioTag and self.audioTag['TCMP'].text[0] != '': self.compilation = self.audioTag['TCMP'].text[0].rstrip() if 'TDOR' in self.audioTag and self.audioTag['TDOR'].text[0] != '': self.date = str(self.audioTag['TDOR'].text[0]) # Read the flac track Vorbis tags and extract all interresting values into a Track object def _fillFromFLAC(self): if 'TITLE' in self.audioTag: self.title = self.audioTag['TITLE'][0] if 'DATE' in self.audioTag: self.year = self.audioTag['DATE'][0] if 'TRACKNUMBER' in self.audioTag: self.trackNumber = self.audioTag['TRACKNUMBER'][0] if 'PRODUCER' in self.audioTag: self.producers = self.audioTag['PRODUCER'][0].split('; ') if 'LABEL' in self.audioTag: self.label = self.audioTag['LABEL'][0] if 'DISCNUMBER' in self.audioTag: self.discNumber = self.audioTag['DISCNUMBER'][0] if 'DISCTOTAL' in self.audioTag: self.totalDisc = self.audioTag['DISCTOTAL'][0] if 'TRACKTOTAL' in self.audioTag: self.totalTrack = self.audioTag['TRACKTOTAL'][0] if 'COMPOSER' in self.audioTag: self.composers = self.audioTag['COMPOSER'][0].split('; ') if 'PERFORMER' in self.audioTag: self.performers = self.audioTag['PERFORMER'][0].split('; ') if 'GENRE' in self.audioTag: self.genres = self.audioTag['GENRE'][0].split('; ') if 'ARTIST' in self.audioTag: self.artists = self.audioTag['ARTIST'][0].split('; ') if 'ALBUM' in self.audioTag: self.albumTitle = self.audioTag['ALBUM'][0] if 'ALBUMARTIST' in self.audioTag: self.albumArtist = self.audioTag['ALBUMARTIST'][0] if 'BPM' in self.audioTag: self.bpm = self.audioTag['BPM'][0] if 'LANGUAGE' in self.audioTag: self.lang = self.audioTag['LANGUAGE'][0].split('; ') if 'COMPILATION' in self.audioTag: self.compilation = self.audioTag['COMPILATION'][0] if 'RELEASEDATE' in self.audioTag: self.date = self.audioTag['RELEASEDATE'][0] # Compute all class internals that can not be extracted from ID3 tags def _computeInternals(self): self._computeFileNameList() self._computeFolderNameList() self._computeFeaturing() self._computeRemixer() self._containsCover() # Splits the filename into its components # (%releaseArtists% - %year% - %albumTitle% - %discNumber%%trackNumber% - %artists% - %title%) def _computeFileNameList(self): # We split the filename into its differents parts, as mentioned in this method description self.fileNameList = self.fileName.split(' - ') forbiddenPattern = ['Single', 'Intro', 'ÉPILOGUE', '25', 'Interlude'] # Here we handle all specific cases (when ' - ' is not a separator) if len(self.fileNameList ) > 6 and self.fileNameList[3] in forbiddenPattern: # When album is a single, we must re-join the album name and the 'Single' suffix self.fileNameList[2:4] = [' - '.join(self.fileNameList[2:4]) ] # Re-join with a ' - ' separator # Splits the folderame into its components (%year% - %albumTitle%) def _computeFolderNameList(self): # We also split the folder name to make a double check for Year and Album name self.folderNameList = self.pathList[len(self.pathList) - 1].split(' - ') forbiddenPattern = ['Single', 'Intro', 'ÉPILOGUE', '25', 'Interlude'] if len(self.folderNameList ) == 3 and self.folderNameList[2] in forbiddenPattern: # When album is a single, we must re-join the album name and the 'Single' suffix self.folderNameList[1:3] = [' - '.join(self.folderNameList[1:3]) ] # Re-join with a ' - ' separator # Extract the featured artist(s) name(s) from the track fileName def _computeFeaturing(self): if self.fileName.find('(feat.') != -1: startIndex = self.fileName.rfind('(feat.', 0, len(self.fileName)) self.feat = self.fileName[startIndex + 7:self.fileName. find(')', startIndex)].split(', ') # +7 is to remove the `(feat. ` string from feat artist if len(self.feat) > 0 and self.feat[0] != '': self.composedPerformer = [*self.feat, *self.artists] return self.composedPerformer = self.artists # No featuring so performer should be equal to artist # Extract the track remix artist name from the track fileName def _computeRemixer(self): if self.fileNameList[len(self.fileNameList) - 1].find(' Remix)') != -1: self.remix = self.fileName[ # +1 is to remove the opening parenthesis self.fileName.rfind('(', 0, len(self.fileName)) + 1:self.fileName.rfind(' Remix)')].split(', ') # Test the cover existence in the file def _containsCover(self): # Extract image from file if self.fileType == 'MP3': if len(self.audioTag.getall('APIC')) > 0: mp3Cover = self.audioTag.getall('APIC')[0] self.cover = mp3Cover.data self.coverType = mp3Cover.mime self.coverDesc = mp3Cover.desc elif self.fileType == 'FLAC': if len(self.audioTag.pictures) > 0: self.cover = self.audioTag.pictures[0].data self.coverType = self.audioTag.pictures[0].mime self.coverDesc = self.audioTag.pictures[0].desc else: self.cover = self.audioTag.pictures # Test cover existence if len(self.cover) != 0: self.hasCover = True else: self.hasCover = False # Inspects the track object to find if any of its tags has multiple fields def testTagsUnicity(self): if self.fileType == 'MP3': if 'TIT2' in self.audioTag and len(self.audioTag['TIT2'].text) > 1: return False if 'TPE1' in self.audioTag and len(self.audioTag['TPE1'].text) > 1: return False if 'TPE2' in self.audioTag and len(self.audioTag['TPE2'].text) > 1: return False if 'TALB' in self.audioTag and len(self.audioTag['TALB'].text) > 1: return False if 'TDRC' in self.audioTag and len(self.audioTag['TDRC'].text) > 1: return False if 'TPUB' in self.audioTag and len(self.audioTag['TPUB'].text) > 1: return False if 'TCOP' in self.audioTag and len(self.audioTag['TCOP'].text) > 1: return False if 'TCOM' in self.audioTag and len(self.audioTag['TCOM'].text) > 1: return False if 'TOPE' in self.audioTag and len(self.audioTag['TOPE'].text) > 1: return False if 'TLAN' in self.audioTag and len(self.audioTag['TLAN'].text) > 1: return False if 'TRCK' in self.audioTag and len(self.audioTag['TRCK'].text) > 1: return False if 'TPOS' in self.audioTag and len(self.audioTag['TPOS'].text) > 1: return False if 'TBPM' in self.audioTag and len(self.audioTag['TBPM'].text) > 1: return False if 'TCMP' in self.audioTag and len(self.audioTag['TCMP'].text) > 1: return False if 'TDOR' in self.audioTag and len(self.audioTag['TDOR'].text) > 1: return False elif self.fileType == 'FLAC': if 'TITLE' in self.audioTag and len(self.audioTag['TITLE']) > 1: return False if 'DATE' in self.audioTag and len(self.audioTag['DATE']) > 1: return False if 'TRACKNUMBER' in self.audioTag and len( self.audioTag['TRACKNUMBER']) > 1: return False if 'PRODUCER' in self.audioTag and len( self.audioTag['PRODUCER']) > 1: return False if 'LABEL' in self.audioTag and len(self.audioTag['LABEL']) > 1: return False if 'DISCNUMBER' in self.audioTag and len( self.audioTag['DISCNUMBER']) > 1: return False if 'DISCTOTAL' in self.audioTag and len( self.audioTag['DISCTOTAL']) > 1: return False if 'TRACKTOTAL' in self.audioTag and len( self.audioTag['TRACKTOTAL']) > 1: return False if 'COMPOSER' in self.audioTag and len( self.audioTag['COMPOSER']) > 1: return False if 'PERFORMER' in self.audioTag and len( self.audioTag['PERFORMER']) > 1: return False if 'GENRE' in self.audioTag and len(self.audioTag['GENRE']) > 1: return False if 'ARTIST' in self.audioTag and len(self.audioTag['ARTIST']) > 1: return False if 'ALBUM' in self.audioTag and len(self.audioTag['ALBUM']) > 1: return False if 'ALBUMARTIST' in self.audioTag and len( self.audioTag['ALBUMARTIST']) > 1: return False if 'BPM' in self.audioTag and len(self.audioTag['BPM']) > 1: return False if 'LANGUAGE' in self.audioTag and len( self.audioTag['LANGUAGE']) > 1: return False if 'COMPILATION' in self.audioTag and len( self.audioTag['COMPILATION']) > 1: return False if 'RELEASEDATE' in self.audioTag and len( self.audioTag['RELEASEDATE']) > 1: return False return True # Clear all previously existing tags def clearInternalTags(self, album): # We could use audioTag.delete() but we just want to clear the tags supported by convention if self.fileType == 'MP3': self.audioTag.add(TIT2(text='')) self.audioTag.add(TPE1(text='')) self.audioTag.add(TPE2(text='')) self.audioTag.add(TALB(text='')) self.audioTag.add(TDRC(text='')) self.audioTag.add(TPUB(text='')) self.audioTag.add(TCOP(text='')) self.audioTag.add(TCOM(text='')) self.audioTag.add(TOPE(text='')) self.audioTag.add(TLAN(text='')) self.audioTag.add(TRCK(text='')) self.audioTag.add(TPOS(text='')) self.audioTag.add(TBPM(text='')) self.audioTag.add(TCMP(text='')) self.audioTag.add(TDOR(text='')) elif self.fileType == 'FLAC': self.audioTag['TITLE'] = '' self.audioTag['DATE'] = '' self.audioTag['ALBUM'] = '' self.audioTag['ARTIST'] = '' self.audioTag['ALBUMARTIST'] = '' self.audioTag['PERFORMER'] = '' self.audioTag['TRACKNUMBER'] = '' self.audioTag['DISCNUMBER'] = '' self.audioTag['TRACKTOTAL'] = '' self.audioTag['TOTALTRACK'] = '' self.audioTag['TOTALTRACKS'] = '' self.audioTag['DISCTOTAL'] = '' self.audioTag['TOTALDISC'] = '' self.audioTag['TOTALDISCS'] = '' self.audioTag['COMPILATION'] = '' self.audioTag['RELEASEDATE'] = '' self.audioTag.clear_pictures() self.audioTag.save(self.audioTagPath) # Compute all class internals that can not be extracted from ID3 tags def setInternalTags(self, album): # Compilation tag is '0' for regular release, '1' for various artist and '2' for mixes compilation = '0' default = '<fill me>' # Since record company must contain this string, we then admit its a compilation if ' Records' in album.albumArtist: compilation = '1' if self.fileType == 'FLAC': if len(self.fileNameList) == 6: # Avoid range exception self._buildArtistsList() self._buildPerformersList() self._addCoverToFile(album) # Append tag by tag o the track if self.fileNameList[5] is not None: self._setInternalTag('TITLE', self.fileNameList[5][:-5], default) if album.year is not None: self._setInternalTag('DATE', str(album.year), '1900') else: self._setInternalTag('DATE', '1900') if self.artists is not None: self._setInternalTag('ARTIST', '; '.join(self.artists), default) else: self._setInternalTag('ARTIST', default) if album.albumArtist is not None: self._setInternalTag('ALBUMARTIST', album.albumArtist, default) else: self._setInternalTag('ALBUMARTIST', default) if self.performers is not None: self._setInternalTag('PERFORMER', '; '.join(self.performers), default) else: self._setInternalTag('PERFORMER', default) if len(self.fileNameList ) == 6 and self.fileNameList[3] is not None: self._setInternalTag('TRACKNUMBER', str(self.fileNameList[3][1:]).lstrip('0'), '0') else: self._setInternalTag('TRACKNUMBER', '0') if album.totalTrack is not None: self._setInternalTag('TRACKTOTAL', str(album.totalTrack), '0') else: self._setInternalTag('TRACKTOTAL', '0') if len(self.folderNameList ) == 2 and self.folderNameList[1] is not None: self._setInternalTag('ALBUM', self.folderNameList[1], default) else: self._setInternalTag('ALBUM', default) if album.totalDisc is not None: self._setInternalTag('DISCTOTAL', str(album.totalDisc), '0') else: self._setInternalTag('DISCTOTAL', '0') if len(self.fileNameList ) == 6 and self.fileNameList[3] is not None: self._setInternalTag('DISCNUMBER', str(self.fileNameList[3][0]), '0') else: self._setInternalTag('DISCNUMBER', '0') # No need for test value as compilation is built locally (only for regular(0)/compilation(1), not live(2)/mix(3)) self._setInternalTag('COMPILATION', compilation, '-1') # Create fields with default value to fasten manual tagging self._setInternalTag('COMPOSER', default) self._setInternalTag('LANGUAGE', default) self._setInternalTag('PRODUCER', default) self._setInternalTag( 'LABEL', default ) # May be overwritten in _fillTagsFromPreviouslyExistingTag() # Release date if len(album.folderNameList[0]) > 4: self._setInternalTag('RELEASEDATE', album.folderNameList[0], '1900-01-01') else: self._setInternalTag('RELEASEDATE', '{}-01-01'.format(album.year), '1900-01-01') # If other tags were previously filled, try to integrate them according to the tagging convention self._fillTagsFromPreviouslyExistingTag() elif self.fileType == 'MP3': if len(self.fileNameList) == 6: # Avoid range exception self._buildArtistsList() self._buildPerformersList() self._addCoverToFile(album) # Append tag by tag on the track if self.fileNameList[5] is not None: # Track title self.audioTag.add(TIT2(text=self.fileNameList[5] [:-4])) # -4 for '.mp3' string if self.artists is not None: # Artist self.audioTag.add(TPE1(text='; '.join(self.artists))) if album.albumArtist is not None: # Album artist self.audioTag.add(TPE2(text=album.albumArtist)) if len( self.folderNameList ) == 2 and self.folderNameList[1] is not None: # Album title self.audioTag.add(TALB(text=self.folderNameList[1])) if album.year is not None: # Year self.audioTag.add(TDRC(text=str(album.year))) if self.performers is not None: # Performer (original artist) self.audioTag.add(TOPE(text='; '.join(self.performers))) if len(self.fileNameList) == 6 and self.fileNameList[ 3] is not None and album.totalTrack is not None: # track N°/track total self.audioTag.add( TRCK(text=str(self.fileNameList[3][1:]).lstrip('0') + '/' + str(album.totalTrack))) if len(self.fileNameList) == 6 and self.fileNameList[ 3] is not None and album.totalDisc is not None: # disc N°/disc total self.audioTag.add( TPOS(text=str(self.fileNameList[3][0]) + '/' + str(album.totalDisc))) self.audioTag.add(TCMP(text=compilation)) # Compilation self.audioTag.add(TPUB(text=default)) # Producer self.audioTag.add(TCOP(text=default)) # Label self.audioTag.add(TCOM(text=default)) # Composer self.audioTag.add(TLAN(text=default)) # Language # Release date if len(album.folderNameList[0]) > 4: self.audioTag.add(TDOR(text=album.folderNameList[0])) else: self.audioTag.add(TDOR(text='{}-01-01'.format(album.year))) # Now save all the new tags into the audio file self.audioTag.save(self.audioTagPath) # Check if the tag is already filled before adding one def _setInternalTag(self, tag, value, default=''): if tag in self.audioTag and self.audioTag[tag] is not value: self.audioTag[tag] = value else: self.audioTag[tag] = default # This method will fill : # - Label tag if publisher tag was previously filled (according to this convention, the label is stored in publisher (TPUB) for mp3 files) def _fillTagsFromPreviouslyExistingTag(self): if self.fileType == 'FLAC': if 'PUBLISHER' in self.audioTag and self.audioTag['PUBLISHER'] != [ '' ]: self._setInternalTag('LABEL', self.audioTag['PUBLISHER'][0], '<fill me>') self.audioTag['PUBLISHER'] = '' # Clear publisher tag # Build artist array from artist string and support remix artist if any def _buildArtistsList(self): outputList = [] if len(self.remix) == 0: # Not a remixed track artists = self.fileNameList[4].split(', ') for artist in artists: outputList.append(artist) else: outputList = list(set(outputList + self.remix)) outputList.sort() self.artists = outputList # Build performers array from artist string and support remix artist if any def _buildPerformersList(self): outputList = [] if len(self.remix) == 0: # Not a remixed track performers = self.fileNameList[4].split(', ') for performer in performers: outputList.append(performer) else: outputList = list(set(outputList + self.remix)) if len(self.feat) > 0: # Append featuring artists if any outputList = list(set(outputList + self.feat)) outputList.sort() self.performers = outputList # Append a cover to the track only if it is 1k by 1k and if there is not any cover def _addCoverToFile(self, album): # Build the file path by concatenating folder in the file path path = '' for folder in self.pathList: path += '{}/'.format(folder) path += album.coverName if self.fileType == 'FLAC': if not self.hasCover or (self.audioTag.pictures[0].height != 1000 and self.audioTag.pictures[0].width != 1000): if self.hasCover: self.audioTag.clear_pictures() with open(path, 'rb') as img: data = img.read() # Open physical image im = PIL.Image.open(path) width, height = im.size # Create picture and set its internals picture = Picture() picture.data = data picture.type = 3 # COVER_FRONT picture.desc = path.rsplit( '/', 1)[-1] # Add picture name as a description picture.mime = mimetypes.guess_type(path)[0] picture.width = width picture.height = height picture.depth = mode_to_bpp[im.mode] # Save into file's audio tag self.audioTag.add_picture(picture) self.audioTag.save() else: # Remove any previous cover self.audioTag.delall('APIC') # Read and save cover into file imgData = open(path, 'rb').read() mime = mimetypes.guess_type(path)[0] self.audioTag.add(APIC(3, mime, 3, album.coverName, imgData)) self.audioTag.save(v2_version=3)
def flac_tag(flac_dirname, flac_filename, artist, album, track, tracks, title, year, genre, bpms, compilation): # Delete existing tags id3 = FLAC(flac_filename) id3.clear_pictures() id3.delete() # Artist, Composer id3["ARTIST"] = artist id3["ALBUM_ARTIST"] = artist id3["ALBUMARTIST"] = artist id3["COMPOSER"] = artist # Artistsort id3["SORT_ARTIST"] = artist id3["SORT_COMPOSER"] = artist id3["SORT_ALBUM_ARTIST"] = artist id3["ARTISTSORT"] = artist id3["ALBUMARTISTSORT"] = artist id3["COMPOSERSORT"] = artist id3["soar"] = artist id3["soaa"] = artist id3["soco"] = artist # Album id3["ALBUM"] = album # Albumsort id3["SORT_ALBUM"] = album id3["ALBUMSORT"] = album # Track id3["TRACKNUMBER"] = tracks id3["TRACK"] = tracks id3["DISCNUMBER"] = '1/1' # Title id3["TITLE"] = title # Year id3["YEAR_OF_RELEASE"] = year id3["DATE"] = year # Genre id3["GENRE"] = genre # BPMs id3["BPM"] = bpms id3["tmpo"] = bpms # Compilation if (compilation): id3["COMPILATION"] = '1' else: id3["COMPILATION"] = '0' # Cover id3.clear_pictures() try: image = Picture() image.data = open(str(flac_dirname + '/Cover.jpg'), 'rb').read() image.type = PictureType.COVER_FRONT image.mime = "image/jpeg" id3.add_picture(image) except: print("Warning. No Cover.jpg in directory " + flac_dirname + ".") # Save tags to file id3.save(filename=flac_filename, deleteid3=True)
def set_release_metadata(artist_name, album_name, record_id): translation = {'/': '-'} table = str.maketrans(translation) record = get_local_record_list(artist_name, album_name.translate(table)) record_dir = record['record_dir'] try: release = musicbrainzngs.get_release_by_id(record_id, includes=[ 'recordings', ]) release = release['release'] except: release = musicbrainzngs.get_release_by_id(record_id) try: album = release['title'] except KeyError: album = 'not defined' try: date = release['date'] except KeyError: date = 'not defined' try: country = release['country'] except KeyError: country = 'not defined' try: mediumtotal = release['medium-count'] except KeyError: mediumtotal = 0 tracknumber = 1 for i in range(1, mediumtotal + 1): if mediumtotal > 1: base_dir = record_dir + f'/CD{i}/' base_dir_art = record_dir + '/' else: base_dir = record_dir + '/' base_dir_art = record_dir + '/' try: pic = Picture() with open(f'{base_dir_art}fanart.jpg', "rb") as f: pic.data = f.read() pic.mime = u"image/jpeg" pic.width = 1000 pic.height = 1000 pic.depth = 16 except: logger.warning('No Fan Art Available!') songs = os.listdir(base_dir) for song in songs: fullpath = base_dir + song extension = pathlib.Path(fullpath).suffix if extension == '.flac': metadata = FLAC(fullpath) for item in metadata.items(): if item[0] == 'tracknumber': tracknumber = int(item[1].pop()) records = filter(lambda x: int(x['position']) == i, release['medium-list']) for recording in records: tracktotal = recording['track-count'] for track in recording['track-list']: if int(track['number']) == tracknumber: tracktitle = track['recording']['title'].translate( table) trackid = track['recording']['id'] track_musicbrainz = musicbrainzngs.get_recording_by_id( trackid, includes=[ 'artists', ]) artist = track_musicbrainz['recording'][ 'artist-credit-phrase'] metadata.delete() metadata.clear_pictures() if pic: metadata.add_picture(pic) metadata["Album"] = album metadata["Albumartist"] = artist_name metadata["Artist"] = artist_name metadata["Country"] = country metadata["Date"] = date metadata["Discnumber"] = str(i) metadata["Title"] = tracktitle metadata["Tracktotal"] = str(tracktotal) metadata["Tracknumber"] = str(tracknumber) metadata.save() logger.info(f'old name: {song}') if mediumtotal != 1: logger.info( f'new name: {artist} - {album.translate(table)} - CD{i} - {tracknumber:02} - {tracktitle}.flac' ) os.rename( fullpath, f'{base_dir}{artist} - {album.translate(table)} - CD{i} - {tracknumber:02} - {tracktitle}.flac' ) else: logger.info( f'new name: {artist} - {album.translate(table)} - {tracknumber:02} - {tracktitle}.flac' ) os.rename( fullpath, f'{base_dir}{artist} - {album.translate(table)} - {tracknumber:02} - {tracktitle}.flac' )