shin fd35c3fbaa 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.
2019-12-26 12:57:48 +05:30

95 lines
3.2 KiB
Python

# coding: utf-8
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 (
check_executable,
encodeArgument,
encodeFilename,
PostProcessingError,
prepend_extension,
shell_quote
)
class EmbedThumbnailPPError(PostProcessingError):
pass
class EmbedThumbnailPP(FFmpegPostProcessor):
def __init__(self, downloader=None, already_have_thumbnail=False):
super(EmbedThumbnailPP, self).__init__(downloader)
self._already_have_thumbnail = already_have_thumbnail
def run(self, info):
filename = info['filepath']
if not info.get('thumbnails'):
self._downloader.to_screen('[embedthumbnail] There aren\'t any thumbnails to embed')
return [], info
thumbnail_filename = info['thumbnails'][-1]['filename']
if not os.path.exists(encodeFilename(thumbnail_filename)):
self._downloader.report_warning(
'Skipping embedding the thumbnail because the file is missing.')
return [], info
if info['ext'] == 'mp3':
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))
elif info['ext'] in ['m4a', 'mp4']:
try:
meta = MP4(filename)
except:
raise EmbedThumbnailPPError("MPEG-4 file's atomic structure for embedding isn't correct!")
# 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
)]
meta.save()
self._downloader.to_screen('[mutagen.mp4] Merged thumbnail to "%s"' % filename)
if not self._already_have_thumbnail:
os.remove(encodeFilename(thumbnail_filename))
else:
raise EmbedThumbnailPPError('Only mp3, m4a/mp4 are supported for thumbnail embedding for now.')
return [], info