def write_metadata(self, filename, force=False): # MP4 needs these attributes as TXXX. for value in ('original album', 'original_artist', 'original_year'): self.txxx[value.upper().replace('_', ' ')] = value track = self.track log.debug("Writing metadata for: %s", filename) if os.path.exists(filename) is False: log.warn("Couldn't find MP4 file!: %s", filename) return None self.tags = mutagen.mp4.MP4(filename) if not force and self.is_up_to_date(): log.debug('Up to date: "%s"' % filename) return None # Clear out any old data. self.tags.clear() # Basics first. for atom, key in self.attributes.items(): if hasattr(track, key): value = getattr(track, key, None) log.debug("Trying: key: %s (%s)", key, value) if isinstance(value, str): value = value.encode('utf-8') # 'tmpo' needs to be a list of integers. if key == 'bpm' and value is not None: value = [int(value)] if value is not None: self.tags[atom] = value # Hack alert.. not sure how better to "detect" this. if track.genre: for genre in list(track.genre): if genre in self.gapless: self.tags["pgap"] = True if track.compilation: self.tags["cpil"] = True if track.tracknumber and track.tracktotal: self.tags["trkn"] = [(track.tracknumber, track.tracktotal)] elif track.tracknumber: self.tags["trkn"] = [(track.tracknumber, 0)] # Convert RG tags into iTunes SoundCheck # TODO: Find what tags aacgain uses as well. if track.replaygain_album_gain: self.tags['----:com.apple.iTunes:iTunNORM'] = replay_gain_to_soundcheck(track.replaygain_album_gain, track.replaygain_album_peak) elif track.replaygain_track_gain: self.tags['----:com.apple.iTunes:iTunNORM'] = replay_gain_to_soundcheck(track.replaygain_track_gain, track.replaygain_track_peak) # if track.discnumber and track.disctotal: try: self.tags["disk"] = [(track.discnumber, track.disctotal)] except ValueError: pass elif track.disctotal: self.tags["disk"] = [(track.disctotal, track.disctotal)] # Artwork time.. if track.cover_file and os.path.exists(track.cover_file): with open(track.cover_file, 'rb') as fh: if track.cover_file.endswith(".png"): self.tags["covr"] = [ MP4Cover(fh.read(), MP4Cover.FORMAT_PNG) ] elif track.cover_file.endswith(".jpg"): self.tags["covr"] = [ MP4Cover(fh.read(), MP4Cover.FORMAT_JPEG) ] # Always add the check & time stamp for next time. if track.checksum: self.tags['----:com.sully.flac2mp4:checksum'] = str(track.checksum) self.tags['----:com.sully.flac2mp4:flacmtime'] = str(track.mtime) # Convert all user defined tags. for tag, attribute in self.txxx.items(): if getattr(track, attribute, None): self.tags['----:com.apple.iTunes:' + tag] = getattr(track, attribute).encode('utf-8') try: self.tags.save(filename) except Exception as e: log.warn("Couldn't save file %s: %s", filename, e)
def writeTags(self, mp4Path, artwork=True, thumbnail=False): self.log.info("Tagging file: %s." % mp4Path) ext = os.path.splitext(mp4Path)[1][1:] if ext not in valid_output_extensions: self.log.error("File is not the correct format.") sys.exit() try: MP4(mp4Path).delete() except IOError: self.log.debug( "Unable to clear original tags, attempting to proceed.") video = MP4(mp4Path) video["\xa9nam"] = self.title # Movie title video["desc"] = self.shortdescription # Short description video["ldes"] = self.description # Long description video["\xa9day"] = self.date # Year video["stik"] = [9] # Movie iTunes category if self.HD is not None: video["hdvd"] = self.HD if self.genre is not None: genre = None for g in self.genre: if genre is None: genre = g['name'] break #else: #genre += ", " + g['name'] video["\xa9gen"] = genre # Genre(s) video[ "----:com.apple.iTunes:iTunMOVI"] = self.xml # XML - see xmlTags method rating = self.rating() if rating is not None: video["----:com.apple.iTunes:iTunEXTC"] = rating if artwork: path = self.getArtwork(mp4Path) if path is not None: cover = open(path, 'rb').read() if path.endswith('png'): video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG) ] # png poster else: video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG) ] # jpeg poster if self.original: video["\xa9too"] = "MDH:" + os.path.basename(self.original) else: video["\xa9too"] = "MDH:" + os.path.basename(mp4Path) for i in range(3): try: self.log.info("Trying to write tags.") video.save() self.log.info("Tags written successfully.") break except IOError as e: self.log.info("Exception: %s" % e) self.log.exception( "There was a problem writing the tags. Retrying.") time.sleep(5)
def run(self, info): filename = info['filepath'] temp_filename = prepend_extension(filename, 'temp') if not info.get('thumbnails'): self.to_screen('There aren\'t any thumbnails to embed') return [], info idx = next((-i for i, t in enumerate(info['thumbnails'][::-1], 1) if t.get('filepath')), None) if idx is None: self.to_screen('There are no thumbnails on disk') return [], info thumbnail_filename = info['thumbnails'][idx]['filepath'] if not os.path.exists(encodeFilename(thumbnail_filename)): self.report_warning( 'Skipping embedding the thumbnail because the file is missing.' ) return [], info # Correct extension for WebP file with wrong extension (see #25687, #25717) convertor = FFmpegThumbnailsConvertorPP(self._downloader) convertor.fixup_webp(info, idx) original_thumbnail = thumbnail_filename = info['thumbnails'][idx][ 'filepath'] # Convert unsupported thumbnail formats (see #25687, #25717) # PNG is preferred since JPEG is lossy thumbnail_ext = os.path.splitext(thumbnail_filename)[1][1:] if info['ext'] not in ('mkv', 'mka') and thumbnail_ext not in ('jpg', 'jpeg', 'png'): thumbnail_filename = convertor.convert_thumbnail( thumbnail_filename, 'png') thumbnail_ext = 'png' mtime = os.stat(encodeFilename(filename)).st_mtime success = True if info['ext'] == 'mp3': options = [ '-c', 'copy', '-map', '0:0', '-map', '1:0', '-write_id3v1', '1', '-id3v2_version', '3', '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"' ] self._report_run('ffmpeg', filename) self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options) elif info['ext'] in ['mkv', 'mka']: options = list(self.stream_copy_opts()) mimetype = f'image/{thumbnail_ext.replace("jpg", "jpeg")}' old_stream, new_stream = self.get_stream_number( filename, ('tags', 'mimetype'), mimetype) if old_stream is not None: options.extend(['-map', '-0:%d' % old_stream]) new_stream -= 1 options.extend([ '-attach', thumbnail_filename, '-metadata:s:%d' % new_stream, 'mimetype=%s' % mimetype, '-metadata:s:%d' % new_stream, 'filename=cover.%s' % thumbnail_ext ]) self._report_run('ffmpeg', filename) self.run_ffmpeg(filename, temp_filename, options) elif info['ext'] in ['m4a', 'mp4', 'mov']: prefer_atomicparsley = 'embed-thumbnail-atomicparsley' in self.get_param( 'compat_opts', []) # Method 1: Use mutagen if not mutagen or prefer_atomicparsley: success = False else: try: self._report_run('mutagen', filename) meta = MP4(filename) # NOTE: the 'covr' atom is a non-standard MPEG-4 atom, # Apple iTunes 'M4A' files include the 'moov.udta.meta.ilst' atom. f = { 'jpeg': MP4Cover.FORMAT_JPEG, 'png': MP4Cover.FORMAT_PNG }[imghdr.what(thumbnail_filename)] with open(thumbnail_filename, 'rb') as thumbfile: thumb_data = thumbfile.read() meta.tags['covr'] = [ MP4Cover(data=thumb_data, imageformat=f) ] meta.save() temp_filename = filename except Exception as err: self.report_warning('unable to embed using mutagen; %s' % error_to_compat_str(err)) success = False # Method 2: Use AtomicParsley if not success: success = True atomicparsley = next( (x for x in ['AtomicParsley', 'atomicparsley'] if check_executable(x, ['-v'])), None) if atomicparsley is None: self.to_screen( 'Neither mutagen nor AtomicParsley was found. Falling back to ffmpeg' ) success = False else: if not prefer_atomicparsley: self.to_screen( 'mutagen was not found. Falling back to AtomicParsley' ) cmd = [ encodeFilename(atomicparsley, True), encodeFilename(filename, True), encodeArgument('--artwork'), encodeFilename(thumbnail_filename, True), encodeArgument('-o'), encodeFilename(temp_filename, True) ] cmd += [ encodeArgument(o) for o in self._configuration_args('AtomicParsley') ] self._report_run('atomicparsley', filename) self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd)) p = Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout, stderr = p.communicate_or_kill() if p.returncode != 0: msg = stderr.decode('utf-8', 'replace').strip() self.report_warning( f'Unable to embed thumbnails using AtomicParsley; {msg}' ) # for formats that don't support thumbnails (like 3gp) AtomicParsley # won't create to the temporary file if b'No changes' in stdout: self.report_warning( 'The file format doesn\'t support embedding a thumbnail' ) success = False # Method 3: Use ffmpeg+ffprobe # Thumbnails attached using this method doesn't show up as cover in some cases # See https://github.com/yt-dlp/yt-dlp/issues/2125, https://github.com/yt-dlp/yt-dlp/issues/411 if not success: success = True try: options = [*self.stream_copy_opts(), '-map', '1'] old_stream, new_stream = self.get_stream_number( filename, ('disposition', 'attached_pic'), 1) if old_stream is not None: options.extend(['-map', '-0:%d' % old_stream]) new_stream -= 1 options.extend( ['-disposition:%s' % new_stream, 'attached_pic']) self._report_run('ffmpeg', filename) self.run_ffmpeg_multiple_files( [filename, thumbnail_filename], temp_filename, options) except PostProcessingError as err: success = False raise EmbedThumbnailPPError( f'Unable to embed using ffprobe & ffmpeg; {err}') elif info['ext'] in ['ogg', 'opus', 'flac']: if not mutagen: raise EmbedThumbnailPPError( 'module mutagen was not found. Please install using `python -m pip install mutagen`' ) self._report_run('mutagen', filename) f = { 'opus': OggOpus, 'flac': FLAC, 'ogg': OggVorbis }[info['ext']](filename) pic = Picture() pic.mime = 'image/%s' % imghdr.what(thumbnail_filename) with open(thumbnail_filename, 'rb') as thumbfile: pic.data = thumbfile.read() pic.type = 3 # front cover res = self._get_thumbnail_resolution(thumbnail_filename, info['thumbnails'][idx]) if res is not None: pic.width, pic.height = res if info['ext'] == 'flac': f.add_picture(pic) else: # https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE f['METADATA_BLOCK_PICTURE'] = base64.b64encode( pic.write()).decode('ascii') f.save() temp_filename = filename else: raise EmbedThumbnailPPError( 'Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/mov' ) if success and temp_filename != filename: os.replace(temp_filename, filename) self.try_utime(filename, mtime, mtime) converted = original_thumbnail != thumbnail_filename self._delete_downloaded_files( thumbnail_filename if converted or not self._already_have_thumbnail else None, original_thumbnail if converted and not self._already_have_thumbnail else None, info=info) return [], info
def applyData(filePath): global data, artwork tagged_file= MP4(filePath) genres=[] if 'genres' in data: for genre in data['genres']: genres.append(genre['name']) tagged_file['\xa9gen'] = genres if 'overview' in data: tagged_file['ldes'] = data['overview'] tagged_file['desc'] = data['overview'] if 'title' in data: tagged_file['\xa9alb'] = data['title'] tagged_file['aART'] = data['title'] tagged_file['\xa9nam'] = data['title'] elif 'original_title' in data: tagged_file['\xa9alb'] = data['original_title'] tagged_file['aART'] = data['original_title'] tagged_file['\xa9nam'] = data['original_title'] if 'season_number' in data: tagged_file['tvsn'] = [data['season_number']] if 'episode_number' in data: tagged_file['tves'] = [data['episode_number']] if artwork != "": with open(artwork, "rb") as f: tagged_file["covr"] = [ MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG) ] if 'air_date' in data: tagged_file['\xa9day'] = data['air_date'][:4] if 'name' in data: tagged_file['\xa9nam'] = data['name'] if 'original_name' in data: tagged_file['tvsh'] = data['original_name'] tagged_file['\xa9alb'] = data['original_name'] tagged_file['\xa9ART'] = data['original_name'] tagged_file['aART'] = data['original_name'] if 'release_date' in data: tagged_file['\xa9day'] = data['release_date'][:4] vid = cv2.VideoCapture(filePath) width = vid.get(cv2.CAP_PROP_FRAME_WIDTH) if width > 1919 and width < 3839: tagged_file['hdvd'] = [2] elif width < 1919 and width > 1279: tagged_file['hdvd'] = [1] elif width > 3839: tagged_file['hdvd'] = [3] else: tagged_file['hdvd'] = [0] if isTV: cast_crew_data = getCastandCrew(data['id'], "tv") else: cast_crew_data = getCastandCrew(data['id'], "movie") cast = [] directors = [] screenwriters = [] producers = [] producer_re = re.compile("Producer$") for cast_member in cast_crew_data['cast']: cast.append(cast_member['name']) for crew_members in cast_crew_data['crew']: if crew_members['job'] == "Director": directors.append(crew_members['name']) if crew_members['department'] == "Writing": screenwriters.append(crew_members['name']) if producer_re.search(crew_members['job']): producers.append(crew_members['name']) xml_str = "<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" xml_str += "<plist version=\"1.0\">\n" xml_str += "<dict>" xml_str += generateXML(cast, "cast") xml_str += generateXML(directors, "directors") xml_str += generateXML(screenwriters, "screenwriters") xml_str += generateXML(producers, "producers") xml_str += "</dict>" xml_str += "</plist>" tagged_file['----:com.apple.iTunes:iTunMOVI'] = str.encode(xml_str) rating = getClassification(data['id']) tagged_file['----:com.apple.iTunes:iTunEXTC'] = str.encode( "b'mpaa|" + rating + "|300|") if isTV: tagged_file['stik'] = [10] else: tagged_file['stik'] = [9] tagged_file.save()
def downloadSong(web_url,baseFolder,file,performance,username): # Construct full path to filename filename = baseFolder + file # If the file already exists, skip it if path.exists(filename): print(f"ALREADY EXISTS - {filename}") return 0 # Print filename print(f"Downloading {filename}") try: # Print out the web_url for debugging purposes # TODO: Convert to debug message? #print(web_url) # The web_url returns an HTML page that contains the link to the content we wish to download with request.urlopen(web_url) as url: # First get the HTML for the web_url htmlstr = str(url.read()) #print(htmlstr) # Next, parse out the actual media_url, which is in the content field of the "twitter:player:stream" object # We need to strip out the "amp;" values and convert the "+" value to URL-friendly value media_url = unquote(re.search('twitter:player:stream.*?content=".*?"',htmlstr).group(0).split('"')[2]).replace("amp;","").replace("+","%2B") #print(media_url) # Print out the media_url for debugging purposes # TODO: Convert this to a debug message? #print(media_url) # Open the file in binary write mode and write the data from the media_url f = open(filename,'w+b') f.write(request.urlopen(media_url).read()) f.close() except Exception as e: print("FAILED TO DOWNLOAD!!!!!!!!!!!!!!") if "'NoneType' object has no attribute 'group'" in str(e): print("Recording not available - attempting to play in order to make it available") media_url = unquote(re.search('twitter:player" content=".*?"',htmlstr).group(0).split('"')[2]).replace("amp;","").replace("+","%2B") # webbrowser registration does not seem to be needed #webbrowser.register('chrome',None,webbrowser.BackgroundBrowser("C://Program Files (x86)//Google//Chrome//Application//chrome.exe")) #webbrowser.get('chrome').open(media_url) webbrowser.open(media_url) #print(f"NEED TO PLAY: {media_url}") else: print(str(e)) print("-----") #if (not "HTTP Error 504" in str(e)) and (not "HTTP Error 410" in str(e)) and (not "'NoneType' object has no attribute 'group'" in str(e)): #raise return 1 try: # Calculate necessary dates createdat = performance["created_at"] perfdate = datetime.strptime(createdat[0:10],"%Y-%m-%d") # Set the album date to the start of the week on which the song was created albumdate = (perfdate - timedelta(days=perfdate.weekday())).strftime("%Y-%m-%d") albumyear = createdat[0:4] # Write the tags for the M4A file af = MP4(filename) af["\xa9nam"] = performance["fixed_title"] af["\xa9ART"] = performance["performers"] # Set Album Artist to the username we searched for af["aART"] = username # Android seems to have a bug where wrong art is displayed if "Album" tag is empty so set it to "Smule" followed by current date af["\xa9alb"] = f"Smule - {albumdate}" af["\xa9day"] = f"{albumyear}" af["purd"] = createdat af["\xa9cmt"] = f"Performed on {createdat}" # Write the JPEG to the M4A file as album cover. Ignore any errors reading the image try: pic_url = performance['display_pic_url'] img = MP4Cover(request.urlopen(pic_url).read(), imageformat=MP4Cover.FORMAT_JPEG) af["covr"] = [img] except: pass # Save the updated tags to the file af.save() except Exception as e: print("FAILED TO UPDATE TAGS!!!") print(str(e)) return 0 # Print pic URL for debugging purposes # print(pic_url) return 0
def test_cmp_bytes(self): self.assertReallyEqual(MP4Cover(b'woooo'), b"woooo") self.assertReallyNotEqual(MP4Cover(b'woooo'), b"foo") if PY2: self.assertReallyEqual(MP4Cover(b'woooo'), u"woooo") self.assertReallyNotEqual(MP4Cover(b'woooo'), u"foo")
def process_a_file(self, input_path, output_dir): au_id = input_path.name if not au_id.isdigit(): print(f'unexpected file: {input_path}') return au_id = int(au_id) file_kind = File(input_path) if isinstance(file_kind, MP4): suffix = '.m4a' elif isinstance(file_kind, FLAC): suffix = '.flac' elif file_kind is None: raise TypeError('unknown file kind') else: raise TypeError( f'unsupport file kind {file_kind.__class__.__name__}') audio_info = self.audio_cache.get(au_id) filename = f'{spilt_artist_str(audio_info["author"])[0]} - {audio_info["title"]}{suffix}' output_path = output_dir / filename if not self.overwrite and output_path.is_file(): print(f'{filename} exists, skipped') return print(f'processing: {filename}') shutil.copyfile(input_path, output_path) album_id = audio_info['pgc_info']['pgc_menu']['menuId'] album_info = self.album_cache.get(album_id) album_cover_url = album_info['menusRespones']['coverUrl'] album_au_ids = list(map(lambda x: x['id'], album_info['songsList'])) track_id = album_au_ids.index(au_id) assert album_cover_url == album_info['songsList'][track_id][ 'cover_url'] album_cover_path = self.cover_cache.get(album_cover_url) if album_cover_path.suffix == '.jpg': image_format = AtomDataType.JPEG elif album_cover_path.suffix == '.png': image_format = AtomDataType.PNG else: raise TypeError( f'Unsupport format: {album_cover_path.suffix}, Only support jpg and png.' ) with album_cover_path.open('rb') as fp: cover_image = fp.read() audio_file = File(output_path) if isinstance(audio_file, MP4): tags = { '\xa9nam': audio_info['title'], '\xa9alb': album_info['menusRespones']['title'], '\xa9ART': format_artist_list(spilt_artist_str(audio_info['author'])), '\xa9day': str( get_year_from_timestamp( album_info['menusRespones']['pbtime'])), 'aART': format_artist_list( spilt_artist_str(album_info['menusRespones']['mbnames'])), 'trkn': [(track_id + 1, album_info['menusRespones']['songNum'])], 'disk': [(1, 1)], 'covr': [MP4Cover(cover_image, imageformat=image_format)], } elif isinstance(audio_file, FLAC): tags = { 'ALBUM': album_info['menusRespones']['title'], 'ARTIST': format_artist_list(spilt_artist_str(audio_info['author'])), 'ALBUMARTIST': format_artist_list( spilt_artist_str(album_info['menusRespones']['mbnames'])), 'DATE': str( get_year_from_timestamp( album_info['menusRespones']['pbtime'])), 'TITLE': audio_info['title'], 'DISCNUMBER': '1', 'DISCTOTAL': '1', 'TRACKTOTAL': str(album_info['menusRespones']['songNum']), 'TRACKNUMBER': str(track_id + 1), } picture = Picture() picture.data = cover_image picture.type = PictureType.COVER_FRONT audio_file.add_picture(picture) audio_file.update(tags) audio_file.save()
def writeTags(self, mp4Path, artwork=True, thumbnail=False): self.log.debug("Tagging file %s" % mp4Path) if MkvtoMp4(self.settings).validSource(mp4Path) == True: video = MP4(mp4Path) try: video.delete() except IOError: self.log.debug( "Unable to clear original tags, attempting to proceed") video["\xa9nam"] = self.title # Movie title #video["desc"] = self.shortdescription # Short description #video["ldes"] = self.description # Long description video["\xa9day"] = self.date # Year #video["stik"] = [9] # Movie iTunes category if self.HD is not None: video["hdvd"] = self.HD #if self.genre is not None: # genre = None # for g in self.genre: # if genre is None: # genre = g['name'] # break # # else: # # genre += ", " + g['name'] # video["\xa9gen"] = genre # Genre(s) #video["----:com.apple.iTunes:iTunMOVI"] = self.xml # XML - see xmlTags method #rating = self.rating() #if rating is not None: # video["----:com.apple.iTunes:iTunEXTC"] = rating if artwork: path = self.getArtwork(mp4Path) if path is not None: cover = open(path, 'rb').read() if path.endswith('png'): video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG) ] # png poster else: video["covr"] = [ MP4Cover(cover, MP4Cover.FORMAT_JPEG) ] # jpeg poster #if self.original: # video["\xa9too"] = ("meks-ffmpeg movie [%s-%s]" % (self.provider, self.providerid)) #else: # video["\xa9too"] = ("meks-ffmpeg movie [%s-%s]" % (self.provider, self.providerid)) video = metadata_stamper.stamp_encoder( video=video, save=False, stamp=("movie [%s-%s]" % (self.provider, self.providerid))) for i in range(3): try: self.log.debug("Trying to write tags") video.save() self.log.info("Tags written successfully") return True except IOError as e: self.log.exception( "There was a problem writing the tags. Retrying") time.sleep(5) else: self.log.error("The file is invalid") raise IOError
videoquality = int(args.quality) title = args.songtitle album = args.songalbum artist = args.songartist artistalbum = args.songartistalbum date = args.songdate genre = args.songgenre picture = args.songartwork tracknumber = (trackn, 0) audio = MP4(filename) audio["\xa9nam"] = [title] audio["\xa9alb"] = [album] audio["\xa9ART"] = [artist] audio["aART"] = [artistalbum] audio["\xa9day"] = [date] if genre: audio["\xa9gen"] = [genre] if tracknumber == 0: audio["trkn"] = [tracknumber] audio["hdvd"] = [videoquality] audio["stik"] = [6] with open(picture, "rb") as f: audio["covr"] = [ MP4Cover(f.read(), MP4Cover.FORMAT_JPEG) ] #audio["\xa9lyr"] = [syncedlyrics] audio.pprint() audio.save()
def pandora_downloader(): """Download songs from Pandora, Woop Woop.""" # playlist path playlist_path = os.sep.join([ ROOT_FOLDER, re.sub(r'[<>\*:\\/"|?]', "", request.form["station"]) + ".m3u", ]) # build the song's path - remove any invalid characters relative_song_path = FILE_TEMPLATE.format( station=re.sub(r'[<>\*:\\/"|?]', "", request.form["station"]), artist=re.sub(r'[<>\*:\\/"|?]', "", request.form["artist"]), album=re.sub(r'[<>\*:\\/"|?]', "", request.form["album"]), title=re.sub(r'[<>\*:\\/"|?]', "", request.form["title"]), ) song_path = os.sep.join([ROOT_FOLDER, relative_song_path]) # check to see if the file has been downloaded before! if os.path.exists(song_path): print("Song found already") return jsonify(status="alreadyDownloaded") else: print("Downloading {!r}".format(request.form["title"])) # create the directories if they don't exist if not os.path.isdir(os.path.split(song_path)[0]): os.makedirs(os.path.split(song_path)[0]) # download the song try: urllib.urlretrieve(request.form["url"], song_path) except BaseException: print("Something went wrong... skipping this song!") return jsonify(status="failed") # open the song with mutagen so we can tag it # and put the album art in it try: song = MP4(song_path) except BaseException: print("Something went wrong... skipping this song!") return jsonify(status="failed") # set the tags song["\xa9nam"] = [request.form["title"]] song["\xa9ART"] = [request.form["artist"]] song["\xa9alb"] = [request.form["album"]] # download the album art and put it in the file album_art_request = urllib.urlopen(request.form["albumArt"]) album_art = MP4Cover(album_art_request.read()) album_art_request.close() song["covr"] = [album_art] song.save() # append the song in the playlist with open(playlist_path, "a+") as playlist: playlist.write((relative_song_path + "\n")) print("Download Complete!") return jsonify(status="success")
from mutagen import File # filename = "/Users/mgermaine93/Desktop/Test-Music/01 Dragonfly.m4a" # album_art = "/Users/mgermaine93/Desktop/looking_wolf_artwork.jpg" filename = "/Users/mgermaine93/Desktop/Test-Music/01 Living In The Country.m4a" album_art = "/Users/mgermaine93/Desktop/Album-Art/0image.jpg" try: track = MP4(filename) tags = track.tags tags['covr'] print("Track already has album artwork") except KeyError: print("Track does not currently have album artwork") track = MP4(filename) # Thanks to: https://stackoverflow.com/questions/37897801/embedding-album-cover-in-mp4-file-using-mutagen with open(album_art, "rb") as f: track.tags["covr"] = [ MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG) ] track.save() print("artwork saved") # Alternate way: # covr = [] # artworkfile = open(album_art, "rb").read() # covr.append(M4ACover(artworkfile, M4ACover.FORMAT_JPEG)) # track.tags['covr'] = covr # track.save()
def TagTrack(self, folder, export=''): ''' 'Tag' a song's trackdata with the infomation given in folder Call once all download tasks is finished Suppports MP3,M4A(ALAC/MP4),FLAC ''' export = export if export else self.output folder = str(folder) audio = [f for f in os.listdir(folder) if f.split('.')[-1].lower() in ['mp3', 'm4a', 'flac','ogg']] if not audio: logger.error('Supported audio file for %s is missing,Cannot continue formatting!' % folder) return audio = audio[-1] audio = self.GenerateDownloadPath(filename=audio, folder=folder) format = audio.split('.')[-1].lower() # Locate audio file,uses last match track = self.GenerateDownloadPath(filename='track.json', folder=folder) # Locate track file cover = self.GenerateDownloadPath(filename='cover.jpg', folder=folder) # Locate cover image track = json.loads(open(track, encoding='utf-8').read()) tHelper = TrackHelper(track) def write_keys(song): # Write trackdatas song['title'] = tHelper.TrackName song['artist'] = tHelper.Artists if tHelper.Artists else 'Various Artists' song['album'] = tHelper.AlbumName if tHelper.AlbumName else 'Unknown' song['tracknumber'] = str(tHelper.TrackNumber) song['date'] = str(tHelper.TrackPublishTime) song.save() if format == 'm4a': # Process m4a files: Apple’s MP4 (aka M4A, M4B, M4P) song = easymp4.EasyMP4(audio) write_keys(song) if os.path.exists(cover): song = MP4(audio) # Write cover image song['covr'] = [MP4Cover(open(cover, 'rb').read())] song.save() elif format == 'mp3': # Process mp3 files: MPEG audio stream information and tags song = EasyMP3(audio) write_keys(song) if os.path.exists(cover): song = ID3(audio) # Write cover image song.add(APIC(encoding=3, mime='image/jpeg', type=3, desc='Cover', data=open(cover, 'rb').read())) song.save() elif format == 'flac': # Process FLAC files:Free Lossless Audio Codec song = FLAC(audio) write_keys(song) if os.path.exists(cover): pic = Picture() pic.data = open(cover, 'rb').read() pic.mime = 'image/jpeg' song.add_picture(pic) song.save() elif format == 'ogg': # Process OGG files:Ogg Encapsulation Format song = OggVorbis(audio) write_keys(song) if os.path.exists(cover): pic = Picture() pic.data = open(cover, 'rb').read() pic.mime = 'image/jpeg' song["metadata_block_picture"] = [base64.b64encode(pic.write()).decode('ascii')] song.save() # Rename & move file savename = tHelper.Title + '.' + format try: path = self.GenerateDownloadPath(filename=savename, folder=export) shutil.copy(audio, path) logger.debug('Exported audio to path %s' % path[-truncate_length:]) return path except Exception as e: raise Exception('While copying audio file:%s' % e)
if producer: audio["----:com.apple.iTunes:PRODUCER"] = producer.encode() if mixer: audio["----:com.apple.iTunes:MIXER"] = mixer.encode() if label: audio["----:com.apple.iTunes:LABEL"] = label.encode() if barcode: audio["----:com.apple.iTunes:BARCODE"] = barcode.encode() if isrc: audio["----:com.apple.iTunes:ISRC"] = isrc.encode() if albumartistid: audio[ "----:com.apple.iTunes:MusicBrainz Album Artist Id"] = albumartistid.encode( ) if releasegroupid: audio[ "----:com.apple.iTunes:MusicBrainz Release Group Id"] = releasegroupid.encode( ) if albumid: audio["----:com.apple.iTunes:MusicBrainz Album Id"] = albumid.encode() if (compilation == 1): audio["cpil"] = [compilation] audio["stik"] = [1] audio["\xa9cmt"] = [comment] with open(picture, "rb") as f: audio["covr"] = [MP4Cover(f.read(), MP4Cover.FORMAT_JPEG)] #audio["\xa9lyr"] = [syncedlyrics] audio.pprint() audio.save()
def get_mp4_coverart(path): with open(path, 'rb') as f: data = f.read() cover = MP4Cover(data) return cover
def set_M4A_data(SONG_INFO, is_quiet, song_path, choice): """ Set the tags in the m4a file passed. """ cover_added = False try: # If more than one choice then call getChoice option = 0 if len(SONG_INFO) > 1: if not is_quiet: option = getChoice(SONG_INFO, 'metadata') elif choice is not None and choice in range(1, len(SONG_INFO)): option = choice SONG_PATH = os.path.join(defaults.DEFAULT.SONG_TEMP_DIR, song_path) audio = MP4(SONG_PATH) # Download the cover image, if failed, pass if dwCover(SONG_INFO, option): imagedata = open(defaults.DEFAULT.COVER_IMG, 'rb').read() audio["covr"] = [MP4Cover( imagedata, imageformat=MP4Cover.FORMAT_JPEG )] # REmove the image os.remove(defaults.DEFAULT.COVER_IMG) cover_added = True # If tags are not present then add them try: audio.add_tags() except Exception: pass audio.save() option = int(option) # Add the meta data, the key's can be found at # https://mutagen.readthedocs.io/en/latest/api/mp4.html#mutagen.mp4.MP4Tags audio["\xa9nam"] = SONG_INFO[option].track_name audio["\xa9alb"] = SONG_INFO[option].collection_name audio["\xa9ART"] = SONG_INFO[option].artist_name audio["\xa9day"] = SONG_INFO[option].release_date audio["\xa9gen"] = SONG_INFO[option].primary_genre_name # Adding track number would probably thwor some kind # of render error, will leave for later audio.save() defaults.DEFAULT.SONG_NAME_TO_SAVE = SONG_INFO[option].track_name + '.m4a' # Rename the downloaded file os.rename(SONG_PATH, os.path.join( defaults.DEFAULT.SONG_TEMP_DIR, defaults.DEFAULT.SONG_NAME_TO_SAVE )) return option, cover_added except Exception as e: return e
def writeTags(self, path, artwork=True, thumbnail=False, width=None, height=None): self.log.info("Tagging file: %s." % path) if width and height: try: self.setHD(width, height) except: self.log.exception("Unable to set HD tag.") try: video = MP4(path) except MP4StreamInfoError: self.log.error( 'File is not a valid MP4 file and cannot be tagged.') return False try: video.delete() except: self.log.debug("Unable to clear original tags, will proceed.") if self.mediatype == MediaType.Movie: video["\xa9nam"] = self.title # Movie title video["desc"] = self.tagline # Short description video["ldes"] = self.description # Long description video["\xa9day"] = self.date # Year video["stik"] = [9] # Movie iTunes category elif self.mediatype == MediaType.TV: video["tvsh"] = self.showname # TV show title video["\xa9nam"] = self.title # Video title video["tven"] = self.title # Episode title video["desc"] = self.shortDescription # Short description video["ldes"] = self.description # Long description network = [x['name'] for x in self.network] video["tvnn"] = network # Network video["\xa9day"] = self.airdate # Airdate video["tvsn"] = [self.season] # Season number video["disk"] = [(self.season, 0)] # Season number as disk video["\xa9alb"] = self.showname + ", Season " + str( self.season) # iTunes Album as Season video["tves"] = [self.episode] # Episode number video["trkn"] = [ (self.episode, len(self.seasondata.get('episodes', []))) ] # Episode number iTunes video["stik"] = [10] # TV show iTunes category if self.HD: video["hdvd"] = self.HD if self.genre and len(self.genre) > 0: video["\xa9gen"] = self.genre[0].get('name') video["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode( "UTF-8", errors="ignore") # XML - see xmlTags method if self.rating: video["----:com.apple.iTunes:iTunEXTC"] = self.rating.encode( "UTF-8", errors="ignore") # iTunes content rating if artwork: coverpath = self.getArtwork(path, thumbnail=thumbnail) if coverpath is not None: cover = open(coverpath, 'rb').read() if path.endswith('png'): video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG) ] # png poster else: video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG) ] # jpeg poster if self.original: video["\xa9too"] = "SMA:" + os.path.basename(self.original) else: video["\xa9too"] = "SMA:" + os.path.basename(path) try: self.log.info("Trying to write tags.") video.save() self.log.info("Tags written successfully.") return True except: self.log.exception("There was an error writing the tags.") return False
def writeTags(self, path, converter, artwork=True, thumbnail=False, width=None, height=None): self.log.info("Tagging file: %s." % path) if width and height: try: self.setHD(width, height) except: self.log.exception("Unable to set HD tag.") try: video = MP4(path) except MP4StreamInfoError: self.log.debug( 'File is not a valid MP4 file and cannot be tagged using mutagen, falling back to FFMPEG limited tagging.' ) try: metadata = {} if self.mediatype == MediaType.Movie: metadata['TITLE'] = self.title # Movie title metadata["COMMENT"] = self.description # Long description metadata["DATE_RELEASE"] = self.date # Year metadata["DATE"] = self.date # Year elif self.mediatype == MediaType.TV: metadata['TITLE'] = self.title # Video title metadata["COMMENT"] = self.description # Long description metadata["DATE_RELEASE"] = self.airdate # Air Date metadata["DATE"] = self.airdate # Air Date metadata["ALBUM"] = self.showname + ", Season " + str( self.season) # Album as Season if self.genre and len(self.genre) > 0: metadata["GENRE"] = self.genre[0].get('name') metadata["ENCODER"] = "SMA" coverpath = None if artwork: coverpath = self.getArtwork(path, thumbnail=thumbnail) try: conv = converter.tag(path, metadata, coverpath) except: self.log.exception("FFMPEG Tag Error.") return False _, cmds = next(conv) self.log.debug("Metadata tagging FFmpeg command:") self.log.debug(" ".join(str(item) for item in cmds)) for timecode, debug in conv: self.log.debug(debug) self.log.info( "Tags written successfully using FFMPEG fallback method.") return True except: self.log.exception( "Unexpected tagging error using FFMPEG fallback method.") return False try: video.delete() except: self.log.debug("Unable to clear original tags, will proceed.") if self.mediatype == MediaType.Movie: video["\xa9nam"] = self.title # Movie title video["desc"] = self.tagline # Short description video["ldes"] = self.description # Long description video["\xa9day"] = self.date # Year video["stik"] = [9] # Movie iTunes category elif self.mediatype == MediaType.TV: video["tvsh"] = self.showname # TV show title video["\xa9nam"] = self.title # Video title video["tven"] = self.title # Episode title video["desc"] = self.shortDescription # Short description video["ldes"] = self.description # Long description network = [x['name'] for x in self.network] video["tvnn"] = network # Network video["\xa9day"] = self.airdate # Airdate video["tvsn"] = [self.season] # Season number video["disk"] = [(self.season, 0)] # Season number as disk video["\xa9alb"] = self.showname + ", Season " + str( self.season) # iTunes Album as Season video["tves"] = [self.episode] # Episode number video["trkn"] = [ (self.episode, len(self.seasondata.get('episodes', []))) ] # Episode number iTunes video["stik"] = [10] # TV show iTunes category if self.HD: video["hdvd"] = self.HD if self.genre and len(self.genre) > 0: video["\xa9gen"] = self.genre[0].get('name') video["----:com.apple.iTunes:iTunMOVI"] = self.xml.encode( "UTF-8", errors="ignore") # XML - see xmlTags method if self.rating: video["----:com.apple.iTunes:iTunEXTC"] = self.rating.encode( "UTF-8", errors="ignore") # iTunes content rating if artwork: coverpath = self.getArtwork(path, thumbnail=thumbnail) if coverpath is not None: cover = open(coverpath, 'rb').read() if coverpath.endswith('png'): video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG) ] # png poster else: video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG) ] # jpeg poster if self.original: video["\xa9too"] = "SMA:" + os.path.basename(self.original) else: video["\xa9too"] = "SMA:" + os.path.basename(path) try: self.log.info("Trying to write tags.") video.save() self.log.info("Tags written successfully using mutagen.") return True except: self.log.exception("There was an error writing the tags.") return False
def start_process(filenames, mode): """ This is the main funtion of the script where it does its main processing.\n filenames is the list of files to be processed\n mode = 1,2,3 or 4\n 1 means mp4 to tagged mp4\n 2 means mp4 with sub to subbed and tagged mp4\n 3 means mkv to tagged mp4\n 4 means mkv with sub to subbed and tagged mp4 """ for filename in filenames: try: title = filename[:-4] stream_md = collect_stream_metadata(filename) streams_to_process = [] dvdsub_exists=False for stream in stream_md['streams']: if not stream['codec_name'] in sub_codec_blacklist: streams_to_process.append(stream['index']) else: dvdsub_exists=True print('\nSearching IMDb for "{}"'.format(title)) imdb = Imdb() movie_results = [] results = imdb.search_for_title(title) for result in results: if result['type'] == "feature": movie_results.append(result) if not movie_results: while not movie_results: title = input('\nNo results for "' + title + '" Enter alternate/correct movie title >> ') results = imdb.search_for_title(title) for result in results: if result['type'] == "feature": movie_results.append(result) # The most prominent result is the first one # mpr - Most Prominent Result mpr = movie_results[0] print('\nFetching data for {} ({})'.format(mpr['title'], mpr['year'])) # imdb_movie is a dict of info about the movie imdb_movie = imdb.get_title(mpr['imdb_id']) imdb_movie_title = imdb_movie['base']['title'] imdb_movie_year = imdb_movie['base']['year'] imdb_movie_id = mpr['imdb_id'] imdb_movie_rating = imdb_movie['ratings']['rating'] if not 'outline' in imdb_movie['plot']: imdb_movie_plot_outline = (imdb_movie['plot']['summaries'][0] ['text']) print("\nPlot outline does not exist. Fetching plot summary " "instead.\n\n") else: imdb_movie_plot_outline = imdb_movie['plot']['outline']['text'] # Composing a string to have the rating and the plot of the # movie which will go into the 'comment' metadata of the # mp4 file. imdb_rating_and_plot = str('IMDb rating [' + str(float(imdb_movie_rating)) + '/10] - ' + imdb_movie_plot_outline) imdb_movie_genres = imdb.get_title_genres(imdb_movie_id)['genres'] # Composing the 'genre' string of the movie. # I use ';' as a delimeter to searate the multiple genre values genre = ';'.join(imdb_movie_genres) newfilename = (imdb_movie_title + ' (' + str(imdb_movie_year) + ').mp4') # We don't want the characters not allowed in a filename newfilename = (newfilename .replace(':', ' -') .replace('/', ' ') .replace('?', '')) command = "" stream_map = [] for f in streams_to_process: stream_map.append("-map 0:{}".format(f)) stream_map_str = ' '.join(stream_map) if mode == 1: # it is required to rename it as its already an mp4 file that # wasn't proccessed by ffmpeg os.rename(filename, newfilename) if mode == 2 or mode == 4: command = ('ffmpeg -i "' + filename + '" -sub_charenc UTF-8 -i "' + filename[:-4] + '.srt" ' + stream_map_str + ' -map 1 -c copy -c:s mov_text ' '"' + newfilename + '"') subprocess.run(shlex.split(command)) if mode == 3: command = ('ffmpeg -i ' + '"' + filename + '" ' + stream_map_str + ' -c copy -c:s mov_text ' '"' + newfilename + '"') subprocess.run(shlex.split(command)) if dvdsub_exists: print("\nRemoved DVD Subtitles due to uncompatibility with " "mp4 file format") # The poster is fetched from tmdb only if there is no file # named " filename + '.jpg' " in the working directory # this way user can provide their own poster image to be used poster_filename = filename[:-4] + '.jpg' if not os.path.isfile(poster_filename): print('\nFetching the movie poster...') tmdb_find = tmdb.Find(imdb_movie_id) tmdb_find.info(external_source = 'imdb_id') path = tmdb_find.movie_results[0]['poster_path'] complete_path = r'https://image.tmdb.org/t/p/w780' + path uo = urllib.request.urlopen(complete_path) with open(poster_filename, "wb") as poster_file: poster_file.write(uo.read()) poster_file.close() video = MP4(newfilename) with open(poster_filename, "rb") as f: video["covr"] = [MP4Cover( f.read(), imageformat=MP4Cover.FORMAT_JPEG)] video['\xa9day'] = str(imdb_movie_year) video['\xa9nam'] = imdb_movie_title video['\xa9cmt'] = imdb_rating_and_plot video['\xa9gen'] = genre print('\nAdding poster and tagging file...') try: video.save() # I have encounterd this error in pevious version # of script, now I handle it by removing the metadata # of the file. That seems to solve the probelem except OverflowError: remove_meta_command = ('ffmpeg -i "' + newfilename + '" -codec copy -map_metadata -1 "' + newfilename[:-4] + 'new.mp4"') subprocess.run(shlex.split(remove_meta_command)) video_new = MP4(newfilename[:-4] + 'new.mp4') with open(poster_filename, "rb") as f: video_new["covr"] = [MP4Cover( f.read(), imageformat=MP4Cover.FORMAT_JPEG)] video_new['\xa9day'] = str(imdb_movie_year) video_new['\xa9nam'] = imdb_movie_title video_new['\xa9cmt'] = imdb_rating_and_plot video_new['\xa9gen'] = genre print('\nAdding poster and tagging file...') try: video_new.save() if not os.path.exists('auto fixed files'): os.makedirs('auto fixed files') os.rename(newfilename[:-4] + 'new.mp4', 'auto fixed files\\' + newfilename[:-4] + '.mp4') os.remove(newfilename) except OverflowError: errored_files.append(filename + (' - Could not save even after' 'striping metadata')) continue os.remove(poster_filename) print('\n' + filename + (' was proccesed successfuly!\n\n====================' '======================================')) except Exception as e: print('\nSome error occured while processing ' + filename + '\n\n====================================================') errored_files.append(filename + ' - ' + str(e)) PrintException()
def writeTags(self, mp4Path, artwork=True, thumbnail=False): self.log.info("Tagging file: %s." % mp4Path) ext = os.path.splitext(mp4Path)[1][1:] if ext not in valid_output_extensions: self.log.error("File is not the correct format.") sys.exit() video = MP4(mp4Path) try: video.delete() except IOError: self.log.debug( "Unable to clear original tags, attempting to proceed.") video["tvsh"] = self.show # TV show title video["\xa9nam"] = self.title # Video title video["tven"] = self.title # Episode title video["desc"] = self.shortDescription() # Short description video[ "ldes"] = self.description # Long description (same a short for tv) video["tvnn"] = self.network # Network if self.airdate != "0000-00-00": video["\xa9day"] = self.airdate # Airdate video["tvsn"] = [self.season] # Season number video["disk"] = [(int(self.season), 0)] # Season number as disk video["\xa9alb"] = (self.show + ", Season " + str(self.season) ) # iTunes Album as Season video["tves"] = [self.episode] # Episode number video["trkn"] = [(int(self.episode), len(self.seasondata)) ] # Episode number iTunes video["stik"] = [10] # TV show iTunes category if self.HD is not None: video["hdvd"] = self.HD if self.genre is not None: video["\xa9gen"] = self.genre[1:-1].split("|")[0] # video["\xa9gen"] = self.genre.replace('|', ',')[1:-1] # Genre(s) video[ "----:com.apple.iTunes:iTunMOVI"] = self.xml # XML - see xmlTags method video["----:com.apple.iTunes:iTunEXTC"] = self.setRating( ) # iTunes content rating if artwork: path = self.getArtwork(mp4Path, thumbnail=thumbnail) if path is not None: cover = open(path, "rb").read() if path.endswith("png"): video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_PNG) ] # png poster else: video["covr"] = [MP4Cover(cover, MP4Cover.FORMAT_JPEG) ] # jpeg poster if self.original: video["\xa9too"] = "MDH:" + os.path.basename(self.original) else: video["\xa9too"] = "MDH:" + os.path.basename(mp4Path) MP4(mp4Path).delete(mp4Path) for i in range(3): try: self.log.info("Trying to write tags.") video.save() self.log.info("Tags written successfully.") break except IOError as e: self.log.exception( "There was a problem writing the tags. Retrying.") time.sleep(5)
def tagFile(self, filename, metadata, art_url): if not self.file_done: return image = None if art_url is not None: self.getFile('artwork.jpg', art_url, True) try: with open('artwork.jpg', 'rb') as file: image = file.read() except: pass if filename.endswith('.mp3'): audio = MP3(filename, ID3=ID3) try: audio.add_tags() except: pass if image: audio.tags.add( APIC( encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=image ) ) audio.tags["TIT2"] = TIT2(encoding=3, text=(metadata.get('title', ''))) try: audio.tags["TPE1"] = TPE1(encoding=3, text=metadata.get('artist', '')) except: pass audio.tags["TDRC"] = TDRC(encoding=3, text=(metadata.get('year', ''))) audio.tags["TCON"] = TCON(encoding=3, text=(metadata.get('genre', ' '))) audio.save() elif filename.endswith('.flac'): audio = FLAC(filename) try: audio.add_tags() except: pass audio.tags['title'] = metadata['title'] audio.tags['artist'] = metadata['artist'] audio.tags['year'] = metadata['year'] audio.tags['genre'] = metadata['genre'] audio.tags.add( APIC( encoding=3, mime='image/jpeg', type=3, desc=u'Cover', data=image ) ) audio.save() elif filename.endswith('.m4a'): audio = MP4(filename) try: audio.add_tags() except: pass covr = [] covr.append(MP4Cover(image, MP4Cover.FORMAT_JPEG)) audio.tags['covr'] = covr audio.tags['title'] = metadata['title'] audio.tags['artist'] = metadata['artist'] #audio.tags['year'] = metadata['year'] audio.tags['genre'] = metadata['genre'] audio.save() if os.path.isfile('artwork.jpg'): os.remove('artwork.jpg')
def single_album(artist_name, album_name): # Create query query = artist.replace(" ", "+") + "+" + album.replace(" ", "+") + "+album" # Story query album image URL album_url = search(query) # Album subfolder is just the given album name album_subfolder = album_name # Create the /album_art folder and the album subfolder make_img_folder(album_subfolder) # Download the image from the album_url URL and save it in given album name subfolder filename, headers = urllib.urlretrieve( album_url, "album_art/%s/" % album_subfolder + "img.jpg") print("\nDone!") print("\nAdding artwork to specified album...") # Check if album actually exists in music directory if os.path.exists(music_dir + artist_name + album_name): for dirpath, subdirs, files in os.walk(music_dir + artist_name + album_name): for song_name in files: if song_name != ".DS_Store": print("Replacing %s artwork" % song_name) path = music_dir + artist_name + album_name + "/" # If m4a file, convert to mp3 if song_name.endswith("m4a"): # print("Converting to %s MP3" % song_name) # new_song = convert_song(artist_name, album_name, song_name) # Remove old m4a file # os.remove(music_dir + "%s/%s/%s" % (artist_name, album_name, song_name)) song = MP4(music_dir + "%s/%s/%s" % (artist_name, album_name, song_name)) with open( dir_path + "/album_art/%s/img.jpg" % album_subfolder, "rb") as f: song["covr"] = [ MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_JPEG) ] song.save() # song = mp3.MP3(path + new_song) elif song_name.endswith("mp3"): song = mp3.MP3(path + song_name) # Change album artwork imagedata = open( dir_path + "/album_art/%s/img.jpg" % album_subfolder, "rb").read() song.tags.add( id3.APIC(3, 'image/jpg', 3, 'Album Artwork', imagedata)) song.save() print("Done!") else: print( "Artist/album not found. Make sure you have spelt the name exactly correct." )
def test_cover_png(self): self.set_key('covr', [ MP4Cover(b'woooo', MP4Cover.FORMAT_PNG), MP4Cover(b'hoooo', MP4Cover.FORMAT_JPEG), ])
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = MP4(encode_filename(self.filename)) if file.tags is None: file.add_tags() tags = file.tags if config.setting["clear_existing_tags"]: tags.clear() for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' if name in self.__r_text_tags: tags[self.__r_text_tags[name]] = values elif name in self.__r_bool_tags: tags[self.__r_bool_tags[name]] = (values[0] == '1') elif name in self.__r_int_tags: try: tags[self.__r_int_tags[name]] = [int(value) for value in values] except ValueError: pass elif name in self.__r_freeform_tags: values = [v.encode("utf-8") for v in values] tags[self.__r_freeform_tags[name]] = values elif name in self.__r_freeform_tags_ci: values = [v.encode("utf-8") for v in values] delall_ci(tags, self.__r_freeform_tags_ci[name]) if name in self.__casemap: name = self.__casemap[name] else: name = self.__r_freeform_tags_ci[name] tags[name] = values elif name == "musicip_fingerprint": tags["----:com.apple.iTunes:fingerprint"] = [b"MusicMagic Fingerprint%s" % v.encode('ascii') for v in values] elif self.supports_tag(name) and name not in ('tracknumber', 'totaltracks', 'discnumber', 'totaldiscs'): values = [v.encode("utf-8") for v in values] name = self.__casemap.get(name, name) tags['----:com.apple.iTunes:' + name] = values if "tracknumber" in metadata: if "totaltracks" in metadata: tags["trkn"] = [(int(metadata["tracknumber"]), int(metadata["totaltracks"]))] else: tags["trkn"] = [(int(metadata["tracknumber"]), 0)] if "discnumber" in metadata: if "totaldiscs" in metadata: tags["disk"] = [(int(metadata["discnumber"]), int(metadata["totaldiscs"]))] else: tags["disk"] = [(int(metadata["discnumber"]), 0)] covr = [] for image in metadata.images.to_be_saved_to_tags(): if image.mimetype == "image/jpeg": covr.append(MP4Cover(image.data, MP4Cover.FORMAT_JPEG)) elif image.mimetype == "image/png": covr.append(MP4Cover(image.data, MP4Cover.FORMAT_PNG)) if covr: tags["covr"] = covr self._remove_deleted_tags(metadata, tags) file.save()
def FormatSong(self, folder, export=''): ''' 'Format' a song's metadata with the infomation given in folder Call once all download tasks is finished Suppports MP3,M4A(ALAC/MP4),FLAC ''' export = export if export else self.output folder = str(folder) audio = [ f for f in os.listdir(folder) if f.split('.')[-1] in ['mp3', 'm4a', 'flac'] ] if not audio: return audio = audio[-1] audio = self.GenerateDownloadPath(filename=audio, folder=folder) format = audio.split('.')[-1] # Locate audio file,uses last match meta = self.GenerateDownloadPath(filename='meta.json', folder=folder) # Locate meta file cover = self.GenerateDownloadPath(filename='cover.jpg', folder=folder) # Locate cover image if not audio: self.log('audio.m4a / audio.mp3 / audio.flac', format=strings.ERROR_FILE_MISSING) return if not os.path.exists(meta): self.log('meta.json', format=strings.ERROR_FILE_MISSING) return if not os.path.exists(cover): self.log('cover.jpg', format=strings.WARN_FILE_MISSING) meta = json.loads(open(meta, encoding='utf-8').read()) def write_keys(song): # Write metadatas song['title'] = meta['title'] song['artist'] = meta['author'] song['album'] = meta['album'] song.save() if format == 'm4a': # Process m4a files: Apple’s MP4 (aka M4A, M4B, M4P) song = easymp4.EasyMP4(audio) write_keys(song) if os.path.exists(cover): song = MP4(audio) # Write cover image song['covr'] = [MP4Cover(open(cover, 'rb').read())] song.save() elif format == 'mp3': # Process mp3 files: MPEG audio stream information and tags song = EasyMP3(audio) write_keys(song) if os.path.exists(cover): song = ID3(audio) # Write cover image song.add( APIC(encoding=3, mime='image/jpeg', type=3, desc='Cover', data=open(cover, 'rb').read())) song.save() elif format == 'flac': # Process FLAC files:Free Lossless Audio Codec song = FLAC(audio) write_keys(song) if os.path.exists(cover): pic = Picture() pic.data = open(cover, 'rb').read() pic.mime = 'image/jpeg' song.add_picture(pic) song.save() # Rename & move file savename = '{1} - {0}.{2}'.format(meta['title'], meta['author'], format) try: path = self.GenerateDownloadPath(filename=savename, folder=export) shutil.copy(audio, path) self.log(path, format=strings.INFO_EXPORT_COMPLETE) except Exception as e: self.log(e, format=strings.ERROR_INVALID_OPERATION) return path
def mp3_tag(absolute_song_fp, song): '''tag mp3 with metdata''' default_path = os.path.dirname(os.path.realpath(__file__)) no_cover_art = [ '/img/no_album_art.png', '', '/web-client/images/empty_album.png', '/web-client/images/empty_album.png' ] song['coverart'] = song['coverart'].replace('"', '') ## Seeing if the try except clause below will fix the url error when no album art is available # if song['coverart'] not in no_cover_art: # r = urllib2.urlopen(song['coverart']) # picture_type = song['coverart'].split('.')[-1] # cover_art_path = default_path + '\\' + 'coverart' + '.' + picture_type # temp_art = open(cover_art_path, 'wb') # temp_art.write(r.read()) # temp_art.close() # else: try: r = urllib2.urlopen(song['coverart']) picture_type = song['coverart'].split('.')[-1] cover_art_path = default_path + '\\' + 'coverart' + '.' + picture_type temp_art = open(cover_art_path, 'wb') temp_art.write(r.read()) temp_art.close() except: song['coverart'] = None if SONG_QUALITY == '.m4a': try: audio = MP4(absolute_song_fp) if song['coverart']: with open(cover_art_path, 'rb') as f: audio['covr'] = [ MP4Cover(f.read(), imageformat=MP4Cover.FORMAT_PNG) ] os.remove(cover_art_path) # delete coverart audio["\xa9nam"] = unicode(song['song']) audio["\xa9ART"] = unicode(song['artist']) audio["\xa9alb"] = unicode(song['album']) audio.save() except: print "\nUnexpected error:", sys.exc_info()[0] pass if SONG_QUALITY == '.mp3': try: audio = MP3(absolute_song_fp) if song['coverart']: audio.tags.add( APIC( encoding=3, # 3 is for utf-8 mime='image/' + picture_type, # image/jpeg or image/png type=3, # 3 is for the cover image desc=u'Cover', data=open(cover_art_path, 'rb').read())) os.remove(cover_art_path) # delete coverart audio.tags.add(TIT2(encoding=3, text=unicode(song['song']))) audio.tags.add(TPE1(encoding=3, text=unicode(song['artist']))) audio.tags.add(TALB(encoding=3, text=unicode(song['album']))) audio.save(mp3, v1=2, v2_version=3) except: print "\nUnexpected error:", sys.exc_info()[0] pass print ""