From e6d2a3aa32032925320dbcd88b28c6cc79b5646d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Alfredo=20N=C3=BA=C3=B1ez?= Date: Mon, 12 Mar 2018 09:19:13 -0300 Subject: [PATCH 1/3] Added a FFmpegCutVideo postprocessor, for cutting the video after download. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcos Alfredo Núñez --- youtube_dl/postprocessor/__init__.py | 2 ++ youtube_dl/postprocessor/ffmpeg.py | 53 ++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/youtube_dl/postprocessor/__init__.py b/youtube_dl/postprocessor/__init__.py index 3ea518399..85f187af0 100644 --- a/youtube_dl/postprocessor/__init__.py +++ b/youtube_dl/postprocessor/__init__.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals from .embedthumbnail import EmbedThumbnailPP from .ffmpeg import ( FFmpegPostProcessor, + FFmpegCutVideoPP, FFmpegEmbedSubtitlePP, FFmpegExtractAudioPP, FFmpegFixupStretchedPP, @@ -26,6 +27,7 @@ __all__ = [ 'EmbedThumbnailPP', 'ExecAfterDownloadPP', 'FFmpegEmbedSubtitlePP', + 'FFmpegCutVideoPP', 'FFmpegExtractAudioPP', 'FFmpegFixupM3u8PP', 'FFmpegFixupM4aPP', diff --git a/youtube_dl/postprocessor/ffmpeg.py b/youtube_dl/postprocessor/ffmpeg.py index 3ea1afcf3..973d9ad84 100644 --- a/youtube_dl/postprocessor/ffmpeg.py +++ b/youtube_dl/postprocessor/ffmpeg.py @@ -215,6 +215,59 @@ class FFmpegPostProcessor(PostProcessor): return 'file:' + fn if fn != '-' else fn +class FFmpegCutVideoPP(FFmpegPostProcessor): + def __init__(self, downloader=None, startTime=0, endTime=None): + FFmpegPostProcessor.__init__(self, downloader) + self._startTime = startTime + self._endTime = endTime + + def toTime(self, seconds): + m, s = divmod(seconds, 60) + h, m = divmod(m, 60) + return "%d:%02d:%02d" % (h, m, s) + + def run(self, information): + if not self._startTime and not self._endTime: + self._downloader.to_screen('[ffmpeg] No startTime or endTime. Keeping original') + return [], information + + if self._endTime <= self._startTime: + raise PostProcessingError("WARNING: endTime smaller than startTime") + + duration = information['duration'] + if self._endTime and self._endTime > duration: + self._downloader.to_screen('WARNING: endTime greater than video duration') + self._endTime = None + + options = ['-c', 'copy'] + message = '[ffmpeg] Cutting video ' + + if self._startTime: + start = self.toTime(self._startTime) + options.extend(['-ss', start]) + message += 'from %s ' % (start) + duration -= self._startTime + + if self._endTime and self._endTime < duration: + end = self.toTime(self._endTime) + options.extend(['-to', end]) + message += 'to %s' % (end) + duration -= self._endTime + + if '-to' not in options and '-ss' not in options: + self._downloader.to_screen('[ffmpeg] Nothing to cut. Keeping original') + return [], information + + path = information['filepath'] + temp_filename = prepend_extension(path, 'temp') + self._downloader.to_screen(message) + information['duration'] = duration + self.run_ffmpeg(path, temp_filename, options) + os.remove(encodeFilename(path)) + os.rename(encodeFilename(temp_filename), encodeFilename(path)) + return [], information + + class FFmpegExtractAudioPP(FFmpegPostProcessor): def __init__(self, downloader=None, preferredcodec=None, preferredquality=None, nopostoverwrites=False): FFmpegPostProcessor.__init__(self, downloader) From afc763ee2e193b5711e9af53b1e133031611e72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Alfredo=20N=C3=BA=C3=B1ez?= Date: Mon, 12 Mar 2018 13:29:01 -0300 Subject: [PATCH 2/3] Added options to __init__.py and took into acount the possibility of not havin duration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcos Alfredo Núñez --- youtube_dl/__init__.py | 7 +++++++ youtube_dl/options.py | 8 ++++++++ youtube_dl/postprocessor/ffmpeg.py | 31 ++++++++++++++++++------------ 3 files changed, 34 insertions(+), 12 deletions(-) diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py index 9bb952457..3e4ecc2f1 100644 --- a/youtube_dl/__init__.py +++ b/youtube_dl/__init__.py @@ -283,6 +283,13 @@ def _real_main(argv=None): postprocessors.append({ 'key': 'FFmpegEmbedSubtitle', }) + if opts.starttime or opts.endtime: + d = {'key': 'FFmpegCutVideo'} + if opts.starttime: + d['startTime'] = int(opts.starttime) + if opts.endtime: + d['endTime'] = int(opts.endtime) + postprocessors.append(d) if opts.embedthumbnail: already_have_thumbnail = opts.writethumbnail or opts.write_all_thumbnails postprocessors.append({ diff --git a/youtube_dl/options.py b/youtube_dl/options.py index 7d1bbc021..6bf0ea197 100644 --- a/youtube_dl/options.py +++ b/youtube_dl/options.py @@ -853,6 +853,14 @@ def parseOpts(overrideArguments=None): '--convert-subs', '--convert-subtitles', metavar='FORMAT', dest='convertsubtitles', default=None, help='Convert the subtitles to other format (currently supported: srt|ass|vtt|lrc)') + postproc.add_option( + '--start-time', + metavar='TIME', dest='starttime', default=None, + help='Cuts the video/audio starting at start-time') + postproc.add_option( + '--end-time', + metavar='TIME', dest='endtime', default=None, + help='Cuts the vidoe/audio up to end-time') parser.add_option_group(general) parser.add_option_group(network) diff --git a/youtube_dl/postprocessor/ffmpeg.py b/youtube_dl/postprocessor/ffmpeg.py index 973d9ad84..b5bae917f 100644 --- a/youtube_dl/postprocessor/ffmpeg.py +++ b/youtube_dl/postprocessor/ffmpeg.py @@ -227,32 +227,38 @@ class FFmpegCutVideoPP(FFmpegPostProcessor): return "%d:%02d:%02d" % (h, m, s) def run(self, information): - if not self._startTime and not self._endTime: - self._downloader.to_screen('[ffmpeg] No startTime or endTime. Keeping original') + if self._startTime == 0 and self._endTime == None: + self._downloader.to_screen('[ffmpeg] No start time or end time. Keeping original') return [], information - if self._endTime <= self._startTime: - raise PostProcessingError("WARNING: endTime smaller than startTime") + if self._endTime and self._endTime <= self._startTime: + raise PostProcessingError("end time smaller or equal to the start time") - duration = information['duration'] - if self._endTime and self._endTime > duration: - self._downloader.to_screen('WARNING: endTime greater than video duration') + if self._endTime == 0: + raise PostProcessingError("end time can't be zero") + + duration = information.get('duration') + + if self._endTime and duration and self._endTime >= duration: + self._downloader.to_screen('WARNING: end time greater than video duration') self._endTime = None options = ['-c', 'copy'] - message = '[ffmpeg] Cutting video ' + message = '[ffmpeg] Cutting video ' if self._startTime: start = self.toTime(self._startTime) options.extend(['-ss', start]) message += 'from %s ' % (start) - duration -= self._startTime + if duration: + duration -= self._startTime - if self._endTime and self._endTime < duration: + if self._endTime: end = self.toTime(self._endTime) options.extend(['-to', end]) message += 'to %s' % (end) - duration -= self._endTime + if duration: + duration -= self._endTime if '-to' not in options and '-ss' not in options: self._downloader.to_screen('[ffmpeg] Nothing to cut. Keeping original') @@ -261,7 +267,8 @@ class FFmpegCutVideoPP(FFmpegPostProcessor): path = information['filepath'] temp_filename = prepend_extension(path, 'temp') self._downloader.to_screen(message) - information['duration'] = duration + if duration: + information['duration'] = duration self.run_ffmpeg(path, temp_filename, options) os.remove(encodeFilename(path)) os.rename(encodeFilename(temp_filename), encodeFilename(path)) From d2fdec2f09ba754f09244922b4d0e641c1a9cdff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20Alfredo=20N=C3=BA=C3=B1ez?= Date: Mon, 12 Mar 2018 17:01:14 -0300 Subject: [PATCH 3/3] Fixed duration calculation and moved checks to __init__ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcos Alfredo Núñez --- youtube_dl/postprocessor/ffmpeg.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/youtube_dl/postprocessor/ffmpeg.py b/youtube_dl/postprocessor/ffmpeg.py index b5bae917f..1ad4935c8 100644 --- a/youtube_dl/postprocessor/ffmpeg.py +++ b/youtube_dl/postprocessor/ffmpeg.py @@ -221,6 +221,11 @@ class FFmpegCutVideoPP(FFmpegPostProcessor): self._startTime = startTime self._endTime = endTime + if self._endTime and self._endTime <= self._startTime: + raise PostProcessingError("end time smaller or equal to the start time") + if self._endTime == 0: + raise PostProcessingError("end time can't be zero") + def toTime(self, seconds): m, s = divmod(seconds, 60) h, m = divmod(m, 60) @@ -231,16 +236,10 @@ class FFmpegCutVideoPP(FFmpegPostProcessor): self._downloader.to_screen('[ffmpeg] No start time or end time. Keeping original') return [], information - if self._endTime and self._endTime <= self._startTime: - raise PostProcessingError("end time smaller or equal to the start time") - - if self._endTime == 0: - raise PostProcessingError("end time can't be zero") - duration = information.get('duration') if self._endTime and duration and self._endTime >= duration: - self._downloader.to_screen('WARNING: end time greater than video duration') + self._downloader.to_screen('WARNING: end time greater or equal to duration') self._endTime = None options = ['-c', 'copy'] @@ -258,7 +257,7 @@ class FFmpegCutVideoPP(FFmpegPostProcessor): options.extend(['-to', end]) message += 'to %s' % (end) if duration: - duration -= self._endTime + duration = self._endTime - (duration - self._endTime) if '-to' not in options and '-ss' not in options: self._downloader.to_screen('[ffmpeg] Nothing to cut. Keeping original')