def write_id3(mp3_file, track, cover=None): t = mp3.Open(mp3_file) if not t.tags: t.add_tags() album = track['albums'][0] t_add = t.tags.add t_add(id3.TIT2(encoding=3, text=track['title'])) t_add(id3.TPE1(encoding=3, text=track['artists'])) t_add(id3.TCOM(encoding=3, text=track[FLD_COMPOSERS])) t_add(id3.TALB(encoding=3, text=album['title'])) if 'labels' in album: t_add(id3.TPUB(encoding=3, text=', '.join(l['name'] for l in album['labels']))) if FLD_TRACKNUM in track: tnum = '{}/{}'.format(track[FLD_TRACKNUM], album['trackCount']) t_add(id3.TRCK(encoding=3, text=tnum)) if FLD_VOLUMENUM in album: t_add(id3.TPOS(encoding=3, text=str(album[FLD_VOLUMENUM]))) if 'year' in album: t_add(id3.TDRC(encoding=3, text=str(album['year']))) if args.genre: t_add(id3.TCON(encoding=3, text=album['genre'].title())) if cover: t_add(id3.APIC(encoding=3, desc='', mime=cover.mime, type=3, data=cover.data)) t.tags.update_to_v23() #id3.ID3v1SaveOptions.CREATE = 2 t.save(v1=2, v2_version=3)
def save(self): if self.clr: for file in self.audiofiles: tmp = mid3.ID3(file) tmp.clear() tmp.add(mid3.TIT2(text="")) # title frame tmp.add(mid3.TPE1(text="")) # artist frame tmp.add(mid3.TALB(text="")) # album frame tmp.add(mid3.TPE2(text="")) # album artist frame tmp.add(mid3.TCOM(text="")) # composer frame tmp.add(mid3.TCON(text="")) # genre frame tmp.add(mid3.TDRC(text="")) # date frame tmp.add(mid3.TRCK(text="")) # tracknumber frame tmp.add(mid3.TPOS(text="")) # discnumber frame tmp.add(mid3.TBPM(text="")) # bpm frame tmp.save() if self.artwork: with open(self.artwork, 'rb') as albumart: for file in self.audiofiles: tmp = mid3.ID3(file) tmp['APIC'] = mid3.APIC( encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=albumart.read() ) tmp.save() albumart.seek(0) for file in self.audiofiles: tmp = EasyID3(file) for tag in self.__sets: if self.__sets[tag]: tmp[tag] = self.__sets[tag] tmp.save()
def __update_tag(self, download_dir, audio_file, image_file, song_title=None, album_title=None, album_artist=None, album_composer=None, track_number=-1, process_index=-1, process_total=-1): """ The function that update audio metadata for each song. :param str download_dir: Download directory :param str audio_file: Path to audio file :param str image_file: Path to image file :param str song_title: Song title :param str album_title: Album title to be saved in metadata :param str album_artist: Album artist to be saved in metadata :param str album_composer: Album composer to be saved in metadata :param int track_number: track number to be saved in metadata :param int process_index: Current process index displayed in log message :param int process_total: Total number of process displayed in log message """ if audio_file is None: logger.warning('[Process:{}/{}][Track:{}] Could not update metadata because there is no data found on the playlist. The video may be private or deleted.'.format(process_index, process_total, track_number)) return if process_index > 0 and process_total > 0: if track_number > 0: log_prefix = '[Process:{}/{}][Track:{}]'.format(process_index, process_total, track_number) else: log_prefix = '[Process:{}/{}]'.format(process_index, process_total) else: log_prefix = '' audio_filename = os.path.basename(audio_file) try: # Validate audio data if not os.path.isfile(audio_file): raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), audio_file) audio_mime_type = mimetypes.guess_type(audio_file) if contains_at_least(audio_mime_type, ['audio/x-mp4', 'audio/x-m4a', 'audio/mp4a-latm']): # For more info about mp4 tag is available at # https://github.com/quodlibet/mutagen/blob/cf399dc58940fb1356f672809d763be9e2af0033/mutagen/mp4/__init__.py # http://atomicparsley.sourceforge.net/mpeg-4files.html mp4_data = mp4.MP4(audio_file) # Track Number if not self.no_track_number and track_number > 0: mp4_data['trkn'] = [(track_number, 0)] # Cover image if not self.no_artwork: image_data = self.__get_tag_image(image_file, audio_mime_type) if image_data: mp4_data['covr'] = [image_data] # Album title if not self.no_album_title and album_title is not None: mp4_data['\xa9alb'] = album_title # Album artist if not self.no_album_artist and album_artist is not None: mp4_data['aART'] = album_artist # Composer if not self.no_composer and album_composer is not None: mp4_data['\xa9wrt'] = album_composer # Part of compilation if not self.no_compilation: mp4_data['cpil'] = True # Save mp4_data.save() elif contains_at_least(audio_mime_type, ['audio/x-mp3', 'audio/mpeg']): # For more info about ID3v2 tag is available at # https://github.com/quodlibet/mutagen/blob/4a5d7d17f1a611280cc52d229aa70b77ca3c55dd/mutagen/id3/_frames.py # https://help.mp3tag.de/main_tags.html mp3_data = id3.ID3(audio_file) # Cover image if not self.no_artwork: image_data = self.__get_tag_image(image_file, audio_mime_type) if image_data: mp3_data['APIC'] = image_data # Track number if not self.no_track_number and track_number > 0: mp3_data.add(id3.TRCK(encoding=3, text=['{}/{}'.format(track_number, 0)])) # Album title if not self.no_album_title and album_title is not None: mp3_data["TALB"] = id3.TALB(encoding=0, text=album_title) # Album artist if not self.no_album_artist and album_artist is not None: mp3_data["TPE2"] = id3.TPE2(encoding=0, text=album_artist) # Composer if not self.no_composer and album_composer is not None: mp3_data["TCOM"] = id3.TCOM(encoding=0, text=album_composer) # Part of compilation if not self.no_compilation: mp3_data['TCMP'] = id3.TCMP(encoding=0, text=['1']) # Save mp3_data.save() elif contains_at_least(audio_mime_type, ['audio/x-aac']): # TODO: Add AAC support pass # image_data = __get_tag_image(image_file, audio_mime_type) # aac_data = aac.AAC(audio_file) # if not self.no_track_number: # if track_number > 0 and track_total > 0: # aac_data.add_tags(id3.TRCK(encoding=3, text=['{}/{}'.format(track_number, track_total)])) # # mp3_data['TRCK'] = id3.TRCK(encoding=3, text=[str(track_number)]) # if image_data: # mp3_data['APIC'] = image_data # aac_data.save() elif contains_at_least(audio_mime_type, ['audio/x-flac']): # https://github.com/quodlibet/mutagen/blob/a1db79ece62c4e86259f15825e360d1ce0986a22/mutagen/flac.py # https://github.com/quodlibet/mutagen/blob/4a5d7d17f1a611280cc52d229aa70b77ca3c55dd/tests/test_flac.py flac_data = flac.FLAC(audio_file) # Artwork if not self.no_artwork: image_data = self.__get_tag_image(image_file, audio_mime_type) if image_data: flac_data.add_picture(image_data) # Save flac_data.save() flac_data = File(audio_file) # Track number if not self.no_track_number and track_number > 0: flac_data.tags['tracknumber'] = str(track_number) # Album title if not self.no_album_title and album_title is not None: flac_data.tags['album'] = album_title # Album artist if not self.no_album_artist and album_artist is not None: flac_data.tags['albumartist'] = album_artist # Composer if not self.no_composer and album_composer is not None: flac_data.tags['composer'] = album_composer # Part of compilation if not self.no_compilation: pass # Save flac_data.save() # audio = File(audio_file, easy=True) else: raise InvalidMimeTypeException("Invalid audio format.", audio_mime_type) # Remove artwork if succeeded if os.path.exists(image_file): os.remove(image_file) # Rename filename from id to title dest_audio_file = os.path.join(download_dir, '{}.{}'.format(song_title, self.audio_codec)) os.rename(audio_file, dest_audio_file) dest_audio_filename = os.path.basename(dest_audio_file) logger.info('{}[File:{}] Updated.'.format(log_prefix, dest_audio_filename)) except FileNotFoundError: message = 'File not found. Skipped.' logger.warning('{}[File:{}] {}'.format(log_prefix, audio_filename, message)) except InvalidDataException as e: message = e.message + ' Skipped.' logger.warning('{}[File:{}] {}'.format(log_prefix, audio_filename, message)) except InvalidMimeTypeException as e: message = e.message + ' Skipped.' logger.warning('{}[File:{}] {}'.format(log_prefix, audio_filename, message)) except Exception as e: message = 'Error {}: {} Skipped.'.format(type(e), str(e)) logger.error('{}[File:{}] {}'.format(log_prefix, audio_filename, message))
def _write_tags(self, tags): for tag, value in tags.items(): if tag == "releaseName" or tag == "release_name" or tag == "TALB": self._add_tag(id3.TALB(encoding=UTF_8, text=value)) elif tag == "front_cover" or tag == "APIC_FRONT": mime, desc, data = value self._add_tag(id3.APIC(UTF_8, mime, FRONT_COVER, desc, data)) elif tag == "backCover" or tag == "APIC_BACK": mime, desc, data = value self._add_tag(id3.APIC(UTF_8, mime, BACK_COVER, desc, data)) elif tag == "lead_performer" or tag == "TPE1": self._add_tag(id3.TPE1(encoding=UTF_8, text=value)) elif tag == "lead_performer_region" or tag == "TXXX_LEAD_PERFORMER_REGION": self._add_tag( id3.TXXX(encoding=UTF_8, desc="LEAD-PERFORMER-REGION:UN/LOCODE", text=value)) elif tag == "lead_performer_date_of_birth" or tag == "TXXX_LEAD_PERFORMER_DATE_OF_BIRTH": self._add_tag( id3.TXXX(encoding=UTF_8, desc="LEAD-PERFORMER-DATE-OF-BIRTH", text=value)) elif tag == "guestPerformers" or tag == "TMCL": self._add_tag(id3.TMCL(encoding=UTF_8, people=value)) elif tag == "label_name" or tag == "TOWN": self._add_tag(id3.TOWN(encoding=UTF_8, text=value)) elif tag == "catalogNumber" or tag == "TXXX_CATALOG_NUMBER": self._add_tag( id3.TXXX(encoding=UTF_8, desc="Catalog Number", text=value)) elif tag == "upc" or tag == "TXXX_UPC": """ Deprecated and replaced with BARCODE """ self._add_tag(id3.TXXX(encoding=UTF_8, desc="UPC", text=value)) elif tag == "barcode" or tag == "TXXX_BARCODE": self._add_tag( id3.TXXX(encoding=UTF_8, desc="BARCODE", text=value)) elif tag == "recording_time" or tag == "TDRC": self._add_tag( id3.TDRC(encoding=UTF_8, text=[id3.ID3TimeStamp(value)])) elif tag == "releaseTime" or tag == "TDRL": self._add_tag( id3.TDRL(encoding=UTF_8, text=[id3.ID3TimeStamp(value)])) elif tag == "originalReleaseTime" or tag == "TDOR": self._add_tag( id3.TDOR(encoding=UTF_8, text=[id3.ID3TimeStamp(value)])) elif tag == "tagging_time" or tag == "TDTG": self._add_tag( id3.TDTG(encoding=UTF_8, text=[id3.ID3TimeStamp(value)])) elif tag == "recordingStudios" or tag == "TXXX_RECORDING_STUDIO": self._add_tag( id3.TXXX(encoding=UTF_8, desc="Recording Studio", text=value)) elif tag == "TIPL": self._add_tag(id3.TIPL(encoding=UTF_8, people=value)) elif tag == "comments" or tag == "COMM": text, lang = value self._add_tag( id3.COMM(encoding=UTF_8, text=text, desc="", lang=lang)) elif tag == "track_title" or tag == "TIT2": self._add_tag(id3.TIT2(encoding=UTF_8, text=value)) elif tag == "version_info" or tag == "TPE4": self._add_tag(id3.TPE4(encoding=UTF_8, text=value)) elif tag == "featured_guest" or tag == "TXXX_FEATURED_GUEST": self._add_tag( id3.TXXX(encoding=UTF_8, desc="Featured Guest", text=value)) elif tag == "lyricist" or tag == "TEXT": self._add_tag(id3.TEXT(encoding=UTF_8, text=value)) elif tag == "composer" or tag == "TCOM": self._add_tag(id3.TCOM(encoding=UTF_8, text=value)) elif tag == "publisher" or tag == "TPUB": self._add_tag(id3.TPUB(encoding=UTF_8, text=value)) elif tag == "isrc" or tag == "TSRC": self._add_tag(id3.TSRC(encoding=UTF_8, text=value)) elif tag == "labels" or tag == "TXXX_TAGS": self._add_tag(id3.TXXX(encoding=UTF_8, desc="Tags", text=value)) elif tag == "isni" or tag == "TXXX_ISNI_Joel_Miller": self._add_tag( id3.TXXX(encoding=UTF_8, desc="ISNI:Joel Miller", text=value)) elif tag == "TXXX_ISNI_Rebecca_Ann_Maloy": self._add_tag( id3.TXXX(encoding=UTF_8, desc="ISNI:Rebecca Ann Maloy", text=value)) elif tag == "TXXX_IPI_Joel_Miller": self._add_tag( id3.TXXX(encoding=UTF_8, desc="IPI:Joel Miller", text=value)) elif tag == "TXXX_IPI_Rebecca_Ann_Maloy": self._add_tag( id3.TXXX(encoding=UTF_8, desc="IPI:Rebecca Ann Maloy", text=value)) elif tag == "TXXX_ISNI": self._add_tag(id3.TXXX(encoding=UTF_8, desc="ISNI", text=value)) elif tag == "iswc" or tag == "TXXX_ISWC": self._add_tag(id3.TXXX(encoding=UTF_8, desc="ISWC", text=value)) elif tag == "lyrics" or tag == "USLT": text, lang = value self._add_tag( id3.USLT(encoding=UTF_8, text=text, desc="", lang=lang)) elif tag == "language" or tag == "TLAN": self._add_tag(id3.TLAN(encoding=UTF_8, text=value)) elif tag == "primary_style" or tag == "TCON": self._add_tag(id3.TCON(encoding=UTF_8, text=value)) elif tag == "compilation" or tag == "TCMP": self._add_tag(id3.TCMP(encoding=UTF_8, text=value)) elif tag == "tagger" or tag == "TXXX_TAGGER": self._add_tag( id3.TXXX(encoding=UTF_8, desc="TAGGER", text=value)) elif tag == "TXXX_Tagger": """ Deprecated and replaced with separate TAGGER and VERSION tags """ self._add_tag( id3.TXXX(encoding=UTF_8, desc="Tagger", text=value)) elif tag == "tagger_version" or tag == "TXXX_TAGGER_VERSION": self._add_tag( id3.TXXX(encoding=UTF_8, desc="TAGGER_VERSION", text=value)) elif tag == "TXXX_Tagging_Time": """ Deprecated and replaced with TAGGING_TIME """ self._add_tag( id3.TXXX(encoding=UTF_8, desc="Tagging Time", text=value)) elif tag == "TXXX_TAGGING_TIME": """ Deprecated and replaced with TDTG """ self._add_tag( id3.TXXX(encoding=UTF_8, desc="TAGGING_TIME", text=value)) elif tag == "TXXX_PRODUCTION_COMPANY": self._add_tag( id3.TXXX(encoding=UTF_8, desc="PRODUCTION-COMPANY", text=value)) elif tag == "TXXX_PRODUCTION_COMPANY_REGION": self._add_tag( id3.TXXX(encoding=UTF_8, desc="PRODUCTION-COMPANY-REGION:UN/LOCODE", text=value)) elif tag == "TXXX_RECORDING_STUDIO_REGION": self._add_tag( id3.TXXX(encoding=UTF_8, desc="RECORDING-STUDIO-REGION:UN/LOCODE", text=value)) elif tag == "TXXX_RECORDING_STUDIO_ADDRESS": self._add_tag( id3.TXXX(encoding=UTF_8, desc="RECORDING-STUDIO-ADDRESS", text=value)) elif tag == "TRCK": self._add_tag(id3.TRCK(encoding=UTF_8, text=value)) else: raise AssertionError("Knows nothing about '{0}'".format(tag))
try: url = api.get_stream_url(trackIDs[0]) urlretrieve(url, filePath) except: print("Error occurred downloading trackID " + trackIDs[0] + ". Skipping...") del trackIDs[0] continue errorTrack = 0 mp3File = File(filePath) mp3File.add_tags() mp3File.tags.add(id3.TIT2(encoding=3, text=id3Title)) mp3File.tags.add(id3.TALB(encoding=3, text=id3Album)) mp3File.tags.add(id3.TPE1(encoding=3, text=id3Artist)) mp3File.tags.add(id3.TPE2(encoding=3, text=id3AlbumArtist)) mp3File.tags.add(id3.TCOM(encoding=3, text=id3Composer)) if id3Genre: mp3File.tags.add(id3.TCON(encoding=3, text=id3Genre)) if id3Year: mp3File.tags.add(id3.TYER(encoding=3, text=id3Year)) mp3File.tags.add(id3.TRCK(encoding=3, text=id3TrackNumber)) mp3File.tags.add(id3.TPOS(encoding=3, text=id3DiscNumber)) if id3AlbumCover: mp3File.tags.add( id3.APIC(mime='image/jpeg', type=3, desc=u'Cover', data=id3AlbumCover)) mp3File.save() del trackIDs[0]