diff options
Diffstat (limited to 'youtube_dlc/postprocessor')
-rw-r--r-- | youtube_dlc/postprocessor/__init__.py | 2 | ||||
-rw-r--r-- | youtube_dlc/postprocessor/embedthumbnail.py | 15 | ||||
-rw-r--r-- | youtube_dlc/postprocessor/ffmpeg.py | 11 | ||||
-rw-r--r-- | youtube_dlc/postprocessor/sponskrub.py | 86 |
4 files changed, 102 insertions, 12 deletions
diff --git a/youtube_dlc/postprocessor/__init__.py b/youtube_dlc/postprocessor/__init__.py index 2c4702823..e160909a7 100644 --- a/youtube_dlc/postprocessor/__init__.py +++ b/youtube_dlc/postprocessor/__init__.py @@ -17,6 +17,7 @@ from .ffmpeg import ( from .xattrpp import XAttrMetadataPP from .execafterdownload import ExecAfterDownloadPP from .metadatafromtitle import MetadataFromTitlePP +from .sponskrub import SponSkrubPP def get_postprocessor(key): @@ -38,5 +39,6 @@ __all__ = [ 'FFmpegVideoConvertorPP', 'FFmpegVideoRemuxerPP', 'MetadataFromTitlePP', + 'SponSkrubPP', 'XAttrMetadataPP', ] diff --git a/youtube_dlc/postprocessor/embedthumbnail.py b/youtube_dlc/postprocessor/embedthumbnail.py index 4a0d02fc4..94e3eca98 100644 --- a/youtube_dlc/postprocessor/embedthumbnail.py +++ b/youtube_dlc/postprocessor/embedthumbnail.py @@ -76,8 +76,8 @@ class EmbedThumbnailPP(FFmpegPostProcessor): if info['ext'] == 'mp3': options = [ - '-c', 'copy', '-map', '0', '-map', '1', - '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (Front)"'] + '-c', 'copy', '-map', '0:0', '-map', '1:0', '-id3v2_version', '3', + '-metadata:s:v', 'title="Album cover"', '-metadata:s:v', 'comment="Cover (front)"'] self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) @@ -89,12 +89,15 @@ class EmbedThumbnailPP(FFmpegPostProcessor): os.rename(encodeFilename(temp_filename), encodeFilename(filename)) elif info['ext'] == 'mkv': - os.rename(encodeFilename(thumbnail_filename), encodeFilename('cover.jpg')) old_thumbnail_filename = thumbnail_filename - thumbnail_filename = 'cover.jpg' + thumbnail_filename = os.path.join(os.path.dirname(old_thumbnail_filename), 'cover.jpg') + if os.path.exists(thumbnail_filename): + os.remove(encodeFilename(thumbnail_filename)) + os.rename(encodeFilename(old_thumbnail_filename), encodeFilename(thumbnail_filename)) options = [ - '-c', 'copy', '-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg'] + '-c', 'copy', '-map', '0', + '-attach', thumbnail_filename, '-metadata:s:t', 'mimetype=image/jpeg'] self._downloader.to_screen('[ffmpeg] Adding thumbnail to "%s"' % filename) @@ -140,6 +143,6 @@ class EmbedThumbnailPP(FFmpegPostProcessor): 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, mkv, m4a and mp4 are supported for thumbnail embedding for now.') return [], info diff --git a/youtube_dlc/postprocessor/ffmpeg.py b/youtube_dlc/postprocessor/ffmpeg.py index c38db3143..c7071d73d 100644 --- a/youtube_dlc/postprocessor/ffmpeg.py +++ b/youtube_dlc/postprocessor/ffmpeg.py @@ -359,7 +359,7 @@ class FFmpegVideoRemuxerPP(FFmpegPostProcessor): if information['ext'] == self._preferedformat: self._downloader.to_screen('[ffmpeg] Not remuxing video file %s - already is in target format %s' % (path, self._preferedformat)) return [], information - options = ['-c', 'copy'] + options = ['-c', 'copy', '-map', '0'] prefix, sep, ext = path.rpartition('.') outpath = prefix + sep + self._preferedformat self._downloader.to_screen('[' + 'ffmpeg' + '] Remuxing video from %s to %s, Destination: ' % (information['ext'], self._preferedformat) + outpath) @@ -428,8 +428,7 @@ class FFmpegEmbedSubtitlePP(FFmpegPostProcessor): input_files = [filename] + sub_filenames opts = [ - '-map', '0', - '-c', 'copy', + '-c', 'copy', '-map', '0', # Don't copy the existing subtitles, we may be running the # postprocessor a second time '-map', '-0:s', @@ -579,7 +578,7 @@ class FFmpegFixupStretchedPP(FFmpegPostProcessor): filename = info['filepath'] temp_filename = prepend_extension(filename, 'temp') - options = ['-c', 'copy', '-aspect', '%f' % stretched_ratio] + options = ['-c', 'copy', '-map', '0', '-aspect', '%f' % stretched_ratio] self._downloader.to_screen('[ffmpeg] Fixing aspect ratio in "%s"' % filename) self.run_ffmpeg(filename, temp_filename, options) @@ -597,7 +596,7 @@ class FFmpegFixupM4aPP(FFmpegPostProcessor): filename = info['filepath'] temp_filename = prepend_extension(filename, 'temp') - options = ['-c', 'copy', '-f', 'mp4'] + options = ['-c', 'copy', '-map', '0', '-f', 'mp4'] self._downloader.to_screen('[ffmpeg] Correcting container in "%s"' % filename) self.run_ffmpeg(filename, temp_filename, options) @@ -613,7 +612,7 @@ class FFmpegFixupM3u8PP(FFmpegPostProcessor): if self.get_audio_codec(filename) == 'aac': temp_filename = prepend_extension(filename, 'temp') - options = ['-c', 'copy', '-f', 'mp4', '-bsf:a', 'aac_adtstoasc'] + options = ['-c', 'copy', '-map', '0', '-f', 'mp4', '-bsf:a', 'aac_adtstoasc'] self._downloader.to_screen('[ffmpeg] Fixing malformed AAC bitstream in "%s"' % filename) self.run_ffmpeg(filename, temp_filename, options) diff --git a/youtube_dlc/postprocessor/sponskrub.py b/youtube_dlc/postprocessor/sponskrub.py new file mode 100644 index 000000000..8ef612050 --- /dev/null +++ b/youtube_dlc/postprocessor/sponskrub.py @@ -0,0 +1,86 @@ +from __future__ import unicode_literals +import os +import subprocess + +from .common import PostProcessor +from ..compat import compat_shlex_split +from ..utils import ( + check_executable, + encodeArgument, + shell_quote, + PostProcessingError, +) + + +class SponSkrubPP(PostProcessor): + _temp_ext = 'spons' + _def_args = [] + _exe_name = 'sponskrub' + + def __init__(self, downloader, path='', args=None, ignoreerror=False, cut=False, force=False): + PostProcessor.__init__(self, downloader) + self.force = force + self.cutout = cut + self.args = ['-chapter'] if not cut else [] + self.args += self._def_args if args is None else compat_shlex_split(args) + self.path = self.get_exe(path) + + if not ignoreerror and self.path is None: + if path: + raise PostProcessingError('sponskrub not found in "%s"' % path) + else: + raise PostProcessingError('sponskrub not found. Please install or provide the path using --sponskrub-path.') + + def get_exe(self, path=''): + if not path or not check_executable(path, ['-h']): + path = os.path.join(path, self._exe_name) + if not check_executable(path, ['-h']): + return None + return path + + def run(self, information): + if self.path is None: + return [], information + + if information['extractor_key'].lower() != 'youtube': + self._downloader.to_screen('[sponskrub] Skipping sponskrub since it is not a YouTube video') + return [], information + if self.cutout and not self.force and not information.get('__real_download', False): + self._downloader.to_screen( + '[sponskrub] Skipping sponskrub since the video was already downloaded. ' + 'Use --sponskrub-force to run sponskrub anyway') + return [], information + + self._downloader.to_screen('[sponskrub] Trying to %s sponsor sections' % ('remove' if self.cutout else 'mark')) + if self.cutout: + self._downloader.to_screen('WARNING: Cutting out sponsor segments will cause the subtitles to go out of sync.') + if not information.get('__real_download', False): + self._downloader.to_screen('WARNING: If sponskrub is run multiple times, unintended parts of the video could be cut out.') + + filename = information['filepath'] + temp_filename = filename + '.' + self._temp_ext + os.path.splitext(filename)[1] + if os.path.exists(temp_filename): + os.remove(temp_filename) + + cmd = [self.path] + if self.args: + cmd += self.args + cmd += ['--', information['id'], filename, temp_filename] + cmd = [encodeArgument(i) for i in cmd] + + if self._downloader.params.get('verbose', False): + self._downloader.to_screen('[debug] sponskrub command line: %s' % shell_quote(cmd)) + p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) + stdout, stderr = p.communicate() + + if p.returncode == 0: + os.remove(filename) + os.rename(temp_filename, filename) + self._downloader.to_screen('[sponskrub] Sponsor sections have been %s' % ('removed' if self.cutout else 'marked')) + elif p.returncode != 3: # error code 3 means there was no info about the video + stderr = stderr.decode('utf-8', 'replace') + msg = stderr.strip().split('\n')[-1] + raise PostProcessingError(msg if msg else 'sponskrub failed with error code %s!' % p.returncode) + else: + self._downloader.to_screen('[sponskrub] No segments in the SponsorBlock database') + return [], information |