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(TDRC(text='')) self.audioTag.add(TPE1(text='')) self.audioTag.add(TPE2(text='')) self.audioTag.add(TOPE(text='')) self.audioTag.add(TRCK(text='')) self.audioTag.add(TALB(text='')) self.audioTag.add(TPOS(text='')) self.audioTag.add(TCMP(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)
def write_id3_tags(self, filepath: str, meta: dict): """Write metadata to the MP3 file :param filepath: name of mp3 file :param meta: dict of track metadata """ logging.debug(" Encoding process starting..") filename = filepath.rsplit('/', 1)[1][:-8] if not self.debugging: print_clean("\r({}/{}) [{}] :: Encoding: {}".format( self.track_num, self.num_tracks, "=" * 50, filename)) audio = MP3(filepath) audio.delete() audio["TIT2"] = TIT2(encoding=3, text=["title"]) audio.save(filename=None, v1=2) audio = MP3(filepath) if self.grouping and 'label' in meta: audio["TIT1"] = TIT1(encoding=3, text=meta["label"]) if self.embed_lyrics: audio["USLT"] = USLT(encoding=3, lang='eng', desc='', text=meta['lyrics']) if self.embed_art and self.album_art != None: with open(self.album_art, 'rb') as cover_img: cover_bytes = cover_img.read() audio["APIC"] = APIC(encoding=3, mime='image/jpeg', type=3, desc='Cover', data=cover_bytes) audio.save() audio = EasyMP3(filepath) audio["tracknumber"] = meta['track'] audio["title"] = meta["title"] audio["artist"] = meta['artist'] audio["album"] = meta['album'] audio["date"] = meta["date"] audio.save() logging.debug(" Encoding process finished..") logging.debug(" Renaming:\n\t{} -to-> {}".format( filepath, filepath[:-4])) try: os.rename(filepath, filepath[:-4]) except WindowsError: os.remove(filepath[:-4]) os.rename(filepath, filepath[:-4]) if not self.debugging: print_clean("\r({}/{}) [{}] :: Finished: {}".format( self.track_num, self.num_tracks, "=" * 50, filename))
def write_id3_tags(self, filename, meta): print("\nEncoding . . .") audio = MP3(filename) audio["TIT2"] = TIT2(encoding=3, text=["title"]) audio.save(filename=None, v1=2) audio = EasyID3(filename) audio["tracknumber"] = meta['track'] audio["title"] = meta['title'] audio["artist"] = meta['artist'] audio["album"] = meta['album'] audio["date"] = meta['date'] audio.save() audio.save(filename) print("Done encoding . . .")
def write_id3_tags(self, filepath: str, meta: dict): """Write metadata to the MP3 file :param filepath: name of mp3 file :param meta: dict of track metadata """ filename = filepath.rsplit('/', 1)[1][:-8] sys.stdout.flush() sys.stdout.write("\r({}/{}) [{}] :: Encoding: {}".format( self.track_num, self.num_tracks, "=" * 50, filename)) audio = MP3(filepath) audio.tags = None audio["TIT2"] = TIT2(encoding=3, text=["title"]) audio.save(filename=None, v1=2) audio = MP3(filepath) if self.grouping and meta["label"]: audio["TIT1"] = TIT1(encoding=3, text=meta["label"]) if self.lyrics: audio["USLT"] = USLT(encoding=3, lang='eng', desc='', text=meta['lyrics']) audio.save() audio = EasyMP3(filepath) audio["tracknumber"] = meta['track'] audio["title"] = meta["title"] audio["artist"] = meta['artist'] audio["album"] = meta['album'] audio["date"] = meta["date"] audio.save() os.rename(filepath, filepath[:-4]) sys.stdout.write("\r({}/{}) [{}] :: Finished: {}".format( self.track_num, self.num_tracks, "=" * 50, filename))
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)
def save_song_attrs_to_id3tags(tags, song): # - APIC: Artwork if song.artwork: tags["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=song.artwork.read()) # - TIT2: Song Title if song.title: tags["TIT2"] = TIT2(encoding=3, text=song.title.decode('unicode-escape')) # - TPE1: Artist if song.artist: tags["TPE1"] = TPE1(encoding=3, text=song.artist.decode('unicode-escape')) # - TDRC: Year if song.year: tags["TDRC"] = TDRC(encoding=3, text=str(song.year).decode('unicode-escape')) # - TALB: Album if song.album: tags["TALB"] = TALB(encoding=3, text=song.album.decode('unicode-escape')) #: Release date? # release_date = # - TPE2: Album artist if song.album_artist: tags["TPE2"] = TPE2(encoding=3, text=song.album_artist.decode('unicode-escape')) # - TRCK: Track number if song.track_number: tags["TRCK"] = TRCK(encoding=3, text=str( song.track_number).decode('unicode-escape')) # - TBPM: BPM if song.bpm: tags["TBPM"] = TBPM(encoding=3, text=str(song.bpm).decode('unicode-escape')) # - TOPE: Original artist if song.original_artist: tags["TOPE"] = TOPE(encoding=3, text=song.original_artist.decode('unicode-escape')) # - TKEY: Key if song.key: tags["TKEY"] = TKEY(encoding=3, text=song.key.decode('unicode-escape')) # - TCOM: Composer if song.composer: tags["TCOM"] = TCOM(encoding=3, text=song.composer.decode('unicode-escape')) # - TEXT: Lyricist if song.lyricist: tags["TEXT"] = TEXT(encoding=3, text=song.lyricist.decode('unicode-escape')) # - COMM: Comments if song.comments: tags["COMM"] = COMM(encoding=3, text=song.comments.decode('unicode-escape')) # - TPE4: Remixer if song.remixer: tags["TPE4"] = TPE4(encoding=3, text=song.remixer.decode('unicode-escape')) # - TPUB: Label/Publisher if song.label: tags["TPUB"] = TPUB(encoding=3, text=song.label.decode('unicode-escape')) # - TCON: Genre/content type if song.genre: tags["TCON"] = TCON(encoding=3, text=song.genre.decode('unicode-escape')) if song.lyrics: tags["USLT"] = USLT(encoding=3, text=song.lyrics.decode('unicode-escape'))
def modify(audioFile, trackData): artist = getAllArtists(trackData['album']['artists']) album = trackData["album"]["name"] title = trackData["name"] track = str(trackData["track_number"]) genre, year = getGenreYear(title, artist) track.encode('utf-8') year.encode('utf-8') try: audioFile.add_tags() except: pass saveAlbumArt(trackData['album']['images'][0]['url']) # Track Title audioFile.tags.add( TIT2( encoding=3, text=title ) ) # Track Album audioFile.tags.add( TALB( encoding=3, text=album ) ) # Track Artist audioFile.tags.add( TPE1( encoding=3, text=artist ) ) # Album Art audioFile.tags.add( APIC( encoding=3, mime="image/jpeg", type=3, desc=u"cover", data=open('image.jpg', 'rb').read() ) ) # Track Number audioFile.tags.add( TRCK( encoding=3, text=track ) ) # Track Year audioFile.tags.add( TYER( encoding=3, text=year ) ) # Track Genre audioFile.tags.add( TCON( encoding=3, text=genre ) ) audioFile.update() audioFile.tags.update_to_v23() audioFile.save(v2_version=3) os.remove('image.jpg')
def updateFileMetadata(track, tags): if track.location.endswith(".mp3"): # Check if the file has a tag header audioTag = ID3() if tags.trackTitle is not None: audioTag.add(TIT2(text=tags.trackTitle)) if tags.trackYear is not None: audioTag.add(TDRC(text=str(tags.trackYear))) if tags.trackArtist is not None: audioTag.add(TPE1(text=tags.trackArtist)) if tags.trackPerformer is not None: audioTag.add(TOPE(text=tags.trackPerformer)) if tags.trackComposer is not None: audioTag.add(TCOM(text=tags.trackComposer)) if tags.trackNumber is not None: if tags.albumTotalTrack is not None: audioTag.add( TRCK(text=str(tags.trackNumber) + "/" + str(tags.albumTotalTrack))) else: audioTag.add(TRCK(text=str(tags.trackNumber))) if tags.trackBPM is not None: audioTag.add(TBPM(text=str(tags.trackBPM))) if tags.lyrics is not None: audioTag.add(USLT(text=tags.lyrics)) if tags.trackGenre is not None: audioTag.add(TCON(text=tags.trackGenre)) if tags.albumTitle is not None: audioTag.add(TALB(text=tags.albumTitle)) if tags.albumArtist is not None: audioTag.add(TPE1(text=tags.albumArtist)) if tags.albumTotalDisc is not None: audioTag.add(TXXX(desc="TOTALDISCS", text=[tags.albumTotalDisc])) if tags.comment is not None: audioTag.add(COMM(text=tags.comment)) if tags.albumDiscNumber is not None: audioTag.add(TPOS(text=str(tags.albumDiscNumber))) if tags.cover is not None: audioTag.add(APIC(data=tags.cover, type=3)) audioTag.save(track.location) data = errorCheckMessage(True, None, updateFileMetadata) elif track.location.endswith(".flac"): audioTag = FLAC(track.location) if tags.trackTitle is not None: audioTag["TITLE"] = tags.trackTitle if tags.trackYear is not None: audioTag['DATE'] = str(tags.trackYear) if tags.trackArtist is not None: audioTag['ARTIST'] = tags.trackArtist if tags.trackPerformer is not None: audioTag['PERFORMER'] = tags.trackPerformer if tags.trackComposer is not None: audioTag['COMPOSER'] = tags.trackComposer if tags.trackNumber is not None: audioTag['TRACKNUMBER'] = str(tags.trackNumber) if tags.albumTotalTrack is not None: audioTag['TOTALTRACK'] = str(tags.albumTotalTrack) if tags.trackBPM is not None: audioTag['BPM'] = tags.trackBPM if tags.lyrics is not None: audioTag['LYRICS'] = tags.lyrics if tags.trackGenre is not None: audioTag['GENRE'] = tags.trackGenre if tags.albumTitle is not None: audioTag['ALBUM'] = tags.albumTitle if tags.albumArtist is not None: audioTag['ARTIST'] = tags.albumArtist if tags.albumTotalDisc is not None: audioTag['TOTALDISC'] = str(tags.albumTotalDisc) if tags.albumDiscNumber is not None: audioTag['DISCNUMBER'] = str(tags.albumDiscNumber) if tags.comment is not None: audioTag['COMMENT'] = str(tags.comment) if tags.cover is not None: picture = audioTag.pictures picture[0].data = tags.cover audioTag.save(track.location) data = errorCheckMessage(True, None, updateFileMetadata) else: data = errorCheckMessage(False, ErrorEnum.FORMAT_ERROR, updateFileMetadata) return data
def setTags(data): ''' Adding taggs to mp3 file :param filename: name of file :param data: dictionary with song data structure of dictionary: { 'uri' : 'str', # Song URI id 'name':'str', # Name of song 'artist':'tuple', # List of artists 'album':'str', # Name of album 'image':'str', # Url for image from Sporify } as example: { 'uri' : '4g5MorMCNI2aOwEBSov4RT', 'name': 'and then, it swallowed me', 'artist': ['Nohidea', 'killedmyself', 'Delta Sleep'], 'album': 'and then, it swallowed me', 'image': 'https://i.scdn.co/image/033879df...f2ddb66' } :return: boolean, in case of some errors - False, else True ''' if data: #download image TagEditor.getImageFromSpotify( data['image'], f"cache/{data['uri']}/{data['uri']}.png") audio = MP3(f"cache/{data['uri']}/{data['uri']}.mp3", ID3=ID3) #handle tag errors try: audio.add_tags() except error: pass #add a picture audio.tags.add( APIC( 3, 'image/jpeg', 3, 'Front cover', open(f"cache/{data['uri']}/{data['uri']}.png", 'rb').read())) #add song name audio.tags.add(TIT2(encoding=3, text=(data['name']))) #add song album audio.tags.add(TALB(encoding=3, text=(data['album']))) #add song artist audio.tags.add(TPE1(encoding=3, text=(data['artist'][0]))) #add song artist audio.tags.add( USLT(encoding=3, lang=u'eng', desc=u'desc', text=genius.getLyrics(data['artist'][0], data['name']))) #save result audio.save() ID3(f"cache/{data['uri']}/{data['uri']}.mp3").save(v2_version=3) return True else: return False
def download(self, location: str = "downloads/", file_name: str = None, use_better_file_name: bool = True, use_album_data: bool = True, artwork_url: str = None, artwork_crop_to_square: bool = True) -> None: """ Download the stream .. note:: When downloading a stream, it also attempts to download metadata and album artwork for it. The artists is the username user who uploaded the track, the title is the track title on SoundCloud and the artwork is whatever is provided with the track. It also does a quick check to see if the track appears in any albums. If it does, then it gets the first album and then gets album info and artwork from there instead. :param location: The location to download the stream to :param file_name: The name of the file :param use_better_file_name: If no file name specified, create one using the username and track title? :param use_album_data: Use the data of the first album that the track is in :param artwork_url: The url of the artwork to use :param artwork_crop_to_square: Should the artwork be cropped to a square? (Not currently used) :return: None """ if (self.client_id is not None): response = requests.get(self.url, stream=True) if (response.status_code != 200): print( f"Error: Could not download the file. (Status code {response.status_code})" ) return download_url = response.json()["url"] if (file_name is None): file_name = re.search(r"[a-zA-Z0-9\-]*\.[0-9]+\.(mp3|opus)", download_url).group() if (use_better_file_name and self.track_data is not None and self.track_data.track_artists is not None and self.track_data.track_title is not None): extension = file_name.split(".")[-1] file_name = "{} - {}.{}".format( self.track_data.track_artists[0], self.track_data.track_title, extension) file_name = SoundCloudStream.sanitize_file_name(file_name) if (not os.path.exists(location)): os.mkdir(location) output_location = os.path.join(location, file_name) http = urllib3.PoolManager() with http.request('GET', download_url, preload_content=False) as r, open( output_location, 'wb') as out_file: shutil.copyfileobj(r, out_file) try: tags = ID3(output_location) except Exception: tags = ID3() if (self.track_data is not None): # tags["TIT1"] = TIT1(encoding=3, text="Group description") if (self.track_data.track_title is not None): tags["TIT2"] = TIT2(encoding=3, text=self.track_data.track_title) if (self.track_data.track_subtitle is not None): tags["TIT3"] = TIT3(encoding=3, text=self.track_data) if (self.track_data.track_comments is not None): tags["COMM"] = COMM(encoding=3, lang=u"eng", desc=self.track_data.track_comments) if (self.track_data.track_artists is not []): tags["TPE1"] = TPE1(encoding=3, text=self.track_data.track_artists[0]) if (self.track_data.album_artist is not None): tags["TPE2"] = TPE2(encoding=3, text=self.track_data.album_artist) if (self.track_data.album_title is not None): tags["TALB"] = TALB(encoding=3, text=self.track_data.album_title) if (self.track_data.album_year is not None): tags["TDRC"] = TDRC(encoding=3, text=str(self.track_data.album_year)) if (self.track_data.track_number is not None): tags["TRCK"] = TRCK(encoding=3, text="{}/0".format( self.track_data.track_number)) if (self.track_data.genre is not None): tags["TCON"] = TCON(encoding=3, text=self.track_data.genre) if (self.track_data.album_artwork_url is not None): url = self.track_data.album_artwork_url.replace( "large", "t500x500") with http.request("GET", url, preload_content=False) as r,\ open(output_location + ".jpg", "wb") as out_file: shutil.copyfileobj(r, out_file) with open(output_location + ".jpg", "rb") as album_art: tags["APIC"] = APIC(encoding=3, mime="image/jpeg", type=3, desc=u"cover", data=album_art.read()) os.remove(output_location + ".jpg") tags.save(output_location) else: print("Error: No client ID provided")