]>
Commit | Line | Data |
---|---|---|
dcdb292f | 1 | # coding: utf-8 |
ddbed364 | 2 | from __future__ import unicode_literals |
3 | ||
4 | ||
5 | import os | |
6 | import subprocess | |
7 | ||
31fd9c76 | 8 | from .ffmpeg import FFmpegPostProcessor |
9 | ||
ddbed364 | 10 | from ..utils import ( |
11 | check_executable, | |
2cc6d135 | 12 | encodeArgument, |
ddbed364 | 13 | encodeFilename, |
14 | PostProcessingError, | |
15 | prepend_extension, | |
16 | shell_quote | |
17 | ) | |
18 | ||
19 | ||
20 | class EmbedThumbnailPPError(PostProcessingError): | |
21 | pass | |
22 | ||
23 | ||
31fd9c76 | 24 | class EmbedThumbnailPP(FFmpegPostProcessor): |
8e595397 YCH |
25 | def __init__(self, downloader=None, already_have_thumbnail=False): |
26 | super(EmbedThumbnailPP, self).__init__(downloader) | |
27 | self._already_have_thumbnail = already_have_thumbnail | |
28 | ||
ddbed364 | 29 | def run(self, info): |
30 | filename = info['filepath'] | |
31 | temp_filename = prepend_extension(filename, 'temp') | |
ddbed364 | 32 | |
8e595397 | 33 | if not info.get('thumbnails'): |
b5cbe3d6 AU |
34 | self._downloader.to_screen('[embedthumbnail] There aren\'t any thumbnails to embed') |
35 | return [], info | |
ddbed364 | 36 | |
8e595397 | 37 | thumbnail_filename = info['thumbnails'][-1]['filename'] |
ddbed364 | 38 | |
c33a8639 YCH |
39 | if not os.path.exists(encodeFilename(thumbnail_filename)): |
40 | self._downloader.report_warning( | |
41 | 'Skipping embedding the thumbnail because the file is missing.') | |
42 | return [], info | |
43 | ||
6011dd95 | 44 | # Check for mislabeled webp file |
e987deb5 AM |
45 | with open(encodeFilename(thumbnail_filename), "rb") as f: |
46 | b = f.read(16) | |
6011dd95 | 47 | if b'\x57\x45\x42\x50' in b: # Binary for WEBP |
ac0ad4f9 AM |
48 | [thumbnail_filename_path, thumbnail_filename_extension] = os.path.splitext(thumbnail_filename) |
49 | if not thumbnail_filename_extension == ".webp": | |
50 | webp_thumbnail_filename = thumbnail_filename_path + ".webp" | |
f6513e1a | 51 | os.rename(encodeFilename(thumbnail_filename), encodeFilename(webp_thumbnail_filename)) |
ac0ad4f9 | 52 | thumbnail_filename = webp_thumbnail_filename |
e987deb5 | 53 | |
6011dd95 | 54 | # If not a jpg or png thumbnail, convert it to jpg using ffmpeg |
e987deb5 AM |
55 | if not os.path.splitext(thumbnail_filename)[1].lower() in ['.jpg', '.png']: |
56 | jpg_thumbnail_filename = os.path.splitext(thumbnail_filename)[0] + ".jpg" | |
f6513e1a | 57 | jpg_thumbnail_filename = os.path.join(os.path.dirname(jpg_thumbnail_filename), os.path.basename(jpg_thumbnail_filename).replace('%', '_')) # ffmpeg interprets % as image sequence |
777d5a45 AM |
58 | |
59 | self._downloader.to_screen('[ffmpeg] Converting thumbnail "%s" to JPEG' % thumbnail_filename) | |
60 | ||
61 | self.run_ffmpeg(thumbnail_filename, jpg_thumbnail_filename, ['-bsf:v', 'mjpeg2jpeg']) | |
62 | ||
f6513e1a | 63 | os.remove(encodeFilename(thumbnail_filename)) |
777d5a45 AM |
64 | thumbnail_filename = jpg_thumbnail_filename |
65 | ||
8e2915d7 | 66 | if info['ext'] == 'mp3': |
92995e62 | 67 | options = [ |
bb8ca1d1 | 68 | '-c', 'copy', '-map', '0', '-map', '1', |
31fd9c76 | 69 | '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (Front)"'] |
ddbed364 | 70 | |
71 | self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) | |
72 | ||
bb8ca1d1 | 73 | self.run_ffmpeg_multiple_files([filename, thumbnail_filename], temp_filename, options) |
ddbed364 | 74 | |
8e595397 YCH |
75 | if not self._already_have_thumbnail: |
76 | os.remove(encodeFilename(thumbnail_filename)) | |
ddbed364 | 77 | os.remove(encodeFilename(filename)) |
78 | os.rename(encodeFilename(temp_filename), encodeFilename(filename)) | |
79 | ||
d6aa68ce | 80 | elif info['ext'] in ['m4a', 'mp4']: |
ddbed364 | 81 | if not check_executable('AtomicParsley', ['-v']): |
82 | raise EmbedThumbnailPPError('AtomicParsley was not found. Please install.') | |
83 | ||
2cc6d135 YCH |
84 | cmd = [encodeFilename('AtomicParsley', True), |
85 | encodeFilename(filename, True), | |
86 | encodeArgument('--artwork'), | |
87 | encodeFilename(thumbnail_filename, True), | |
88 | encodeArgument('-o'), | |
89 | encodeFilename(temp_filename, True)] | |
ddbed364 | 90 | |
91 | self._downloader.to_screen('[atomicparsley] Adding thumbnail to "%s"' % filename) | |
92 | ||
93 | if self._downloader.params.get('verbose', False): | |
94 | self._downloader.to_screen('[debug] AtomicParsley command line: %s' % shell_quote(cmd)) | |
95 | ||
96 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
97 | stdout, stderr = p.communicate() | |
98 | ||
99 | if p.returncode != 0: | |
100 | msg = stderr.decode('utf-8', 'replace').strip() | |
101 | raise EmbedThumbnailPPError(msg) | |
102 | ||
8e595397 YCH |
103 | if not self._already_have_thumbnail: |
104 | os.remove(encodeFilename(thumbnail_filename)) | |
ddbed364 | 105 | # for formats that don't support thumbnails (like 3gp) AtomicParsley |
106 | # won't create to the temporary file | |
107 | if b'No changes' in stdout: | |
108 | self._downloader.report_warning('The file format doesn\'t support embedding a thumbnail') | |
109 | else: | |
110 | os.remove(encodeFilename(filename)) | |
111 | os.rename(encodeFilename(temp_filename), encodeFilename(filename)) | |
112 | else: | |
d6aa68ce | 113 | raise EmbedThumbnailPPError('Only mp3 and m4a/mp4 are supported for thumbnail embedding for now.') |
ddbed364 | 114 | |
115 | return [], info |