[embedthumbnail] Embed in `mp4`/`m4a` using mutagen

Code from: https://github.com/ytdl-org/youtube-dl/pull/23525
Co-authored by: tripulse , pukkandan
pull/310/head
pukkandan 4 years ago
parent 09d18ad07e
commit acdecdfaef
No known key found for this signature in database
GPG Key ID: 0F00D95A001F4698

@ -8,9 +8,10 @@ import subprocess
import re import re
try: try:
from mutagen.oggvorbis import OggVorbis
from mutagen.oggopus import OggOpus
from mutagen.flac import Picture, FLAC from mutagen.flac import Picture, FLAC
from mutagen.mp4 import MP4, MP4Cover
from mutagen.oggopus import OggOpus
from mutagen.oggvorbis import OggVorbis
has_mutagen = True has_mutagen = True
except ImportError: except ImportError:
has_mutagen = False has_mutagen = False
@ -58,6 +59,9 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
return guess() return guess()
return int(mobj.group('w')), int(mobj.group('h')) return int(mobj.group('w')), int(mobj.group('h'))
def _report_run(self, exe, filename):
self.to_screen('%s: Adding thumbnail to "%s"' % (exe, filename))
def run(self, info): def run(self, info):
filename = info['filepath'] filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp') temp_filename = prepend_extension(filename, 'temp')
@ -94,7 +98,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
'-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3', '-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3',
'-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"'] '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"']
self.to_screen('Adding thumbnail to "%s"' % filename) self._report_run('ffmpeg', filename)
self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options) self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options)
elif info['ext'] in ['mkv', 'mka']: elif info['ext'] in ['mkv', 'mka']:
@ -111,10 +115,32 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
'-metadata:s:%d' % new_stream, 'mimetype=%s' % mimetype, '-metadata:s:%d' % new_stream, 'mimetype=%s' % mimetype,
'-metadata:s:%d' % new_stream, 'filename=cover.%s' % thumbnail_ext]) '-metadata:s:%d' % new_stream, 'filename=cover.%s' % thumbnail_ext])
self.to_screen('Adding thumbnail to "%s"' % filename) self._report_run('ffmpeg', filename)
self.run_ffmpeg(filename, temp_filename, options) self.run_ffmpeg(filename, temp_filename, options)
elif info['ext'] in ['m4a', 'mp4', 'mov']: elif info['ext'] in ['m4a', 'mp4', 'mov']:
# Method 1: Use mutagen
if not has_mutagen:
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 ffmpeg+ffprobe
if not success:
success = True
try: try:
options = ['-c', 'copy', '-map', '0', '-dn', '-map', '1'] options = ['-c', 'copy', '-map', '0', '-dn', '-map', '1']
@ -125,11 +151,15 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
new_stream -= 1 new_stream -= 1
options.extend(['-disposition:%s' % new_stream, 'attached_pic']) options.extend(['-disposition:%s' % new_stream, 'attached_pic'])
self.to_screen('Adding thumbnail to "%s"' % filename) self._report_run('ffmpeg', filename)
self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options) self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options)
except PostProcessingError as err: except PostProcessingError as err:
self.report_warning('unable to embed using ffprobe & ffmpeg; %s' % error_to_compat_str(err)) self.report_warning('unable to embed using ffprobe & ffmpeg; %s' % error_to_compat_str(err))
success = False
# Method 3: Use AtomicParsley
if not success:
success = True
atomicparsley = next(( atomicparsley = next((
x for x in ['AtomicParsley', 'atomicparsley'] x for x in ['AtomicParsley', 'atomicparsley']
if check_executable(x, ['-v'])), None) if check_executable(x, ['-v'])), None)
@ -144,7 +174,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
encodeFilename(temp_filename, True)] encodeFilename(temp_filename, True)]
cmd += [encodeArgument(o) for o in self._configuration_args('AtomicParsley')] cmd += [encodeArgument(o) for o in self._configuration_args('AtomicParsley')]
self.to_screen('Adding thumbnail to "%s"' % filename) self._report_run('atomicparsley', filename)
self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd)) self.write_debug('AtomicParsley command line: %s' % shell_quote(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = process_communicate_or_kill(p) stdout, stderr = process_communicate_or_kill(p)
@ -161,8 +191,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
if not has_mutagen: if not has_mutagen:
raise EmbedThumbnailPPError('module mutagen was not found. Please install using `python -m pip install mutagen`') raise EmbedThumbnailPPError('module mutagen was not found. Please install using `python -m pip install mutagen`')
self.to_screen('Adding thumbnail to "%s"' % filename) self._report_run('mutagen', filename)
temp_filename = filename
f = {'opus': OggOpus, 'flac': FLAC, 'ogg': OggVorbis}[info['ext']](filename) f = {'opus': OggOpus, 'flac': FLAC, 'ogg': OggVorbis}[info['ext']](filename)
pic = Picture() pic = Picture()
@ -180,6 +209,7 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
# https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE # https://wiki.xiph.org/VorbisComment#METADATA_BLOCK_PICTURE
f['METADATA_BLOCK_PICTURE'] = base64.b64encode(pic.write()).decode('ascii') f['METADATA_BLOCK_PICTURE'] = base64.b64encode(pic.write()).decode('ascii')
f.save() f.save()
temp_filename = filename
else: else:
raise EmbedThumbnailPPError('Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/mov') raise EmbedThumbnailPPError('Supported filetypes for thumbnail embedding are: mp3, mkv/mka, ogg/opus/flac, m4a/mp4/mov')

Loading…
Cancel
Save