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 updateRatingToFile(rating, file): #update the rating from Emby to the file f = xbmcvfs.File(file) org_size = f.size() f.close() #create tempfile if "/" in file: filepart = file.split("/")[-1] else: filepart = file.split("\\")[-1] tempfile = "special://temp/" + filepart xbmcvfs.copy(file, tempfile) tempfile = utils.tryDecode(xbmc.translatePath(tempfile)) logMsg("setting song rating: %s for filename: %s - using tempfile: %s" % (rating, file, tempfile)) if not tempfile: return try: if tempfile.lower().endswith(".flac"): audio = FLAC(tempfile) calcrating = int(round((float(rating) / 5) * 100, 0)) audio["rating"] = str(calcrating) audio.save() elif tempfile.lower().endswith(".mp3"): audio = ID3(tempfile) calcrating = int(round((float(rating) / 5) * 255, 0)) audio.add( id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1)) audio.save() else: logMsg("Not supported fileformat: %s" % (tempfile)) #once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp #safety check: we check the file size of the temp file before proceeding with overwite of original file f = xbmcvfs.File(tempfile) checksum_size = f.size() f.close() if checksum_size >= org_size: xbmcvfs.delete(file) xbmcvfs.copy(tempfile, file) else: logMsg( "Checksum mismatch for filename: %s - using tempfile: %s - not proceeding with file overwite!" % (rating, file, tempfile)) #always delete the tempfile xbmcvfs.delete(tempfile) except Exception as e: #file in use ? logMsg("Exception in updateRatingToFile %s" % e, 0)
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 updateRatingToFile(rating, file): #update the rating from Emby to the file f = xbmcvfs.File(file) org_size = f.size() f.close() #create tempfile if "/" in file: filepart = file.split("/")[-1] else: filepart = file.split("\\")[-1] tempfile = "special://temp/"+filepart xbmcvfs.copy(file, tempfile) tempfile = xbmc.translatePath(tempfile).decode("utf-8") log.info( "setting song rating: %s for filename: %s - using tempfile: %s" %(rating,file,tempfile)) if not tempfile: return try: if tempfile.lower().endswith(".flac"): audio = FLAC(tempfile) calcrating = int(round((float(rating) / 5) * 100, 0)) audio["rating"] = str(calcrating) audio.save() elif tempfile.lower().endswith(".mp3"): audio = ID3(tempfile) calcrating = int(round((float(rating) / 5) * 255, 0)) audio.add(id3.POPM(email="Windows Media Player 9 Series", rating=calcrating, count=1)) audio.save() else: log.info( "Not supported fileformat: %s" %(tempfile)) #once we have succesfully written the flags we move the temp file to destination, otherwise not proceeding and just delete the temp #safety check: we check the file size of the temp file before proceeding with overwite of original file f = xbmcvfs.File(tempfile) checksum_size = f.size() f.close() if checksum_size >= org_size: xbmcvfs.delete(file) xbmcvfs.copy(tempfile,file) else: log.info( "Checksum mismatch for filename: %s - using tempfile: %s - not proceeding with file overwite!" %(rating,file,tempfile)) #always delete the tempfile xbmcvfs.delete(tempfile) except Exception as e: #file in use ? log.error("Exception in updateRatingToFile %s" % e)
def saveArtwork(self): if Path(self.file_name).suffix == ".flac": audiof = FLAC(self.file_path) if len(audiof.pictures) != 0: return dl_img = urllib3.PoolManager(cert_reqs='CERT_NONE', assert_hostname=False).request('GET', self.artwork_url).data img = Picture() img.type = 3 img.desc = 'artwork' img.data = dl_img audiof.add_picture(img) elif Path(self.file_name).suffix == ".mp3": audiof = ID3(self.file_path) if hasattr(audiof, "pictures") and len(audiof.pictures) != 0: return dl_img = urllib3.PoolManager(cert_reqs='CERT_NONE', assert_hostname=False).request('GET', self.artwork_url).data audiof.add(mutagen.id3.APIC(3, 'image/jpeg', 3, 'Front cover', dl_img)) audiof.save()
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)