1
0
mirror of https://github.com/l1ving/youtube-dl synced 2025-03-09 12:10:49 +08:00

MP4/M4A files use 'mutagen' for thumbnail embedding

Previously, AtomicParsley was used to embed thumbnails into moov.udta.meta.ilst atom which contains iTunes style metadata for audio files. Using AtomicParsley for only embedding thumbnails was quite infiuriating.Mutagen can manipulate audio metadata and the module itself is quite lightweight and doesn't require any deps. I (shin-ts) favoured to have a package as addon instead of an executable, because this method is quite convinient in my opinion.
This commit is contained in:
shin 2019-12-26 12:57:48 +05:30
parent 18ff573e50
commit fd35c3fbaa

View File

@ -5,6 +5,10 @@ from __future__ import unicode_literals
import os
import subprocess
import imghdr
from mutagen.id3 import PictureType, ID3, APIC
from mutagen.mp4 import MP4, MP4Cover
from .ffmpeg import FFmpegPostProcessor
from ..utils import (
@ -28,7 +32,6 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
def run(self, info):
filename = info['filepath']
temp_filename = prepend_extension(filename, 'temp')
if not info.get('thumbnails'):
self._downloader.to_screen('[embedthumbnail] There aren\'t any thumbnails to embed')
@ -42,52 +45,51 @@ class EmbedThumbnailPP(FFmpegPostProcessor):
return [], info
if info['ext'] == 'mp3':
options = [
'-c', 'copy', '-map', '0', '-map', '1',
'-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (Front)"']
self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename)
self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options)
try:
meta = ID3(filename)
except:
raise EmbedThumbnailPPError("MP3 file doesn't have a existing ID3v2 tag.")
# Update older tags (eg. ID3v1) to a newer version,
# which supports embedded-thumbnails (e.g ID3v2.3).
# NOTE: ID3v2.4 might not be supported by programs.
meta.update_to_v23()
# Appends a Cover-front thumbnail, it's the most common
# type of thumbnail distributed with.
meta.add(APIC(
data= open(thumbnail_filename, 'rb').read(),
mime= 'image/'+imghdr.what(thumbnail_filename),
type= PictureType.COVER_FRONT
))
meta.save() # Save the changes to file, does in-place replacement.
self._downloader.to_screen('[mutagen.id3] Merged Thumbnail into "%s"' % filename)
if not self._already_have_thumbnail:
os.remove(encodeFilename(thumbnail_filename))
os.remove(encodeFilename(filename))
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
os.remove(encodeFilename(thumbnail_filename))
elif info['ext'] in ['m4a', 'mp4']:
if not check_executable('AtomicParsley', ['-v']):
raise EmbedThumbnailPPError('AtomicParsley was not found. Please install.')
try:
meta = MP4(filename)
except:
raise EmbedThumbnailPPError("MPEG-4 file's atomic structure for embedding isn't correct!")
cmd = [encodeFilename('AtomicParsley', True),
encodeFilename(filename, True),
encodeArgument('--artwork'),
encodeFilename(thumbnail_filename, True),
encodeArgument('-o'),
encodeFilename(temp_filename, True)]
# NOTE: the 'covr' atom is a non-standard MPEG-4 atom,
# Apple iTunes 'M4A' files include the 'moov.udta.meta.ilst' atom.
meta.tags['covr'] = [MP4Cover(
data= open(thumbnail_filename, 'rb').read(),
imageformat= MP4Cover.FORMAT_JPEG if \
imghdr.what(thumbnail_filename) == 'jpeg' \
else MP4Cover.FORMAT_PNG
)]
self._downloader.to_screen('[atomicparsley] Adding thumbnail to "%s"' % filename)
if self._downloader.params.get('verbose', False):
self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd))
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stdout, stderr = p.communicate()
if p.returncode != 0:
msg = stderr.decode('utf-8', 'replace').strip()
raise EmbedThumbnailPPError(msg)
meta.save()
self._downloader.to_screen('[mutagen.mp4] Merged thumbnail to "%s"' % filename)
if not self._already_have_thumbnail:
os.remove(encodeFilename(thumbnail_filename))
# for formats that don't support thumbnails (like 3gp) AtomicParsley
# won't create to the temporary file
if b'No changes' in stdout:
self._downloader.report_warning('The file format doesn\'t support embedding a thumbnail')
else:
os.remove(encodeFilename(filename))
os.rename(encodeFilename(temp_filename), encodeFilename(filename))
else:
raise EmbedThumbnailPPError('Only mp3 and m4a/mp4 are supported for thumbnail embedding for now.')
raise EmbedThumbnailPPError('Only mp3, m4a/mp4 are supported for thumbnail embedding for now.')
return [], info
return [], info