mirror of
https://codeberg.org/polarisfm/youtube-dl
synced 2024-11-26 02:14:32 +01:00
[ffmpeg] Support splitting target based on extracted chapters (#24858)
This introduces a new FFmpegPostProcessor, which looks for "chapters" extracted by IEs. For each identified chapter, it extracts a single track from the source file, using ffmpeg's -ss / -t arguments.
This commit is contained in:
parent
07af16b92e
commit
dcab7389ac
@ -293,6 +293,8 @@ def _real_main(argv=None):
|
|||||||
})
|
})
|
||||||
if not already_have_thumbnail:
|
if not already_have_thumbnail:
|
||||||
opts.writethumbnail = True
|
opts.writethumbnail = True
|
||||||
|
if opts.split_tracks:
|
||||||
|
postprocessors.append({'key': 'FFmpegSplitByTracks'})
|
||||||
# XAttrMetadataPP should be run after post-processors that may change file
|
# XAttrMetadataPP should be run after post-processors that may change file
|
||||||
# contents
|
# contents
|
||||||
if opts.xattrs:
|
if opts.xattrs:
|
||||||
|
@ -525,6 +525,11 @@ def parseOpts(overrideArguments=None):
|
|||||||
'--external-downloader-args',
|
'--external-downloader-args',
|
||||||
dest='external_downloader_args', metavar='ARGS',
|
dest='external_downloader_args', metavar='ARGS',
|
||||||
help='Give these arguments to the external downloader')
|
help='Give these arguments to the external downloader')
|
||||||
|
downloader.add_option(
|
||||||
|
'--split-tracks',
|
||||||
|
dest='split_tracks', action='store_true', default=False,
|
||||||
|
help="Split tracks based on chapters information"
|
||||||
|
)
|
||||||
|
|
||||||
workarounds = optparse.OptionGroup(parser, 'Workarounds')
|
workarounds = optparse.OptionGroup(parser, 'Workarounds')
|
||||||
workarounds.add_option(
|
workarounds.add_option(
|
||||||
|
@ -12,6 +12,7 @@ from .ffmpeg import (
|
|||||||
FFmpegMetadataPP,
|
FFmpegMetadataPP,
|
||||||
FFmpegVideoConvertorPP,
|
FFmpegVideoConvertorPP,
|
||||||
FFmpegSubtitlesConvertorPP,
|
FFmpegSubtitlesConvertorPP,
|
||||||
|
FFmpegSplitByTracksPP,
|
||||||
)
|
)
|
||||||
from .xattrpp import XAttrMetadataPP
|
from .xattrpp import XAttrMetadataPP
|
||||||
from .execafterdownload import ExecAfterDownloadPP
|
from .execafterdownload import ExecAfterDownloadPP
|
||||||
@ -27,6 +28,7 @@ __all__ = [
|
|||||||
'ExecAfterDownloadPP',
|
'ExecAfterDownloadPP',
|
||||||
'FFmpegEmbedSubtitlePP',
|
'FFmpegEmbedSubtitlePP',
|
||||||
'FFmpegExtractAudioPP',
|
'FFmpegExtractAudioPP',
|
||||||
|
'FFmpegSplitByTracksPP',
|
||||||
'FFmpegFixupM3u8PP',
|
'FFmpegFixupM3u8PP',
|
||||||
'FFmpegFixupM4aPP',
|
'FFmpegFixupM4aPP',
|
||||||
'FFmpegFixupStretchedPP',
|
'FFmpegFixupStretchedPP',
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import io
|
import io
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import time
|
import time
|
||||||
@ -655,3 +656,49 @@ class FFmpegSubtitlesConvertorPP(FFmpegPostProcessor):
|
|||||||
}
|
}
|
||||||
|
|
||||||
return sub_filenames, info
|
return sub_filenames, info
|
||||||
|
|
||||||
|
|
||||||
|
class FFmpegSplitByTracksPP(FFmpegPostProcessor):
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def _ffmpeg_time_string(self, seconds):
|
||||||
|
t_minutes, t_seconds = divmod(seconds, 60)
|
||||||
|
t_hours, t_minutes = divmod(t_minutes, 60)
|
||||||
|
t_string = '{hrs:02}:{min:02}:{sec:02}'.format(hrs=t_hours, min=t_minutes, sec=t_seconds)
|
||||||
|
return t_string
|
||||||
|
|
||||||
|
def _build_track_name(self, chapter, information):
|
||||||
|
track_title = chapter.get("title", "")
|
||||||
|
track_title = encodeFilename(track_title)
|
||||||
|
track_title = track_title.replace("/", "_")
|
||||||
|
|
||||||
|
prefix, sep, ext = information['filepath'].rpartition('.')
|
||||||
|
track_name = "%s - %s%s%s" % (prefix, track_title, sep, ext)
|
||||||
|
|
||||||
|
return track_name
|
||||||
|
|
||||||
|
def _extract_track_from_chapter(self, chapter, information):
|
||||||
|
start = int(chapter['start_time'])
|
||||||
|
end = int(chapter['end_time'])
|
||||||
|
duration = end - start
|
||||||
|
|
||||||
|
start = self._ffmpeg_time_string(start)
|
||||||
|
duration = self._ffmpeg_time_string(duration)
|
||||||
|
|
||||||
|
destination = self._build_track_name(chapter, information)
|
||||||
|
|
||||||
|
self.run_ffmpeg(information['filepath'], destination, ['-c', 'copy', '-ss', start, '-t', duration])
|
||||||
|
|
||||||
|
def run(self, information):
|
||||||
|
chapters = information.get('chapters', [])
|
||||||
|
if not isinstance(chapters, list) or len(chapters) == 0:
|
||||||
|
self.log.warning('[ffmpeg] There are no tracks to extract')
|
||||||
|
return [], information
|
||||||
|
|
||||||
|
for idx, chapter in enumerate(chapters):
|
||||||
|
try:
|
||||||
|
self._extract_track_from_chapter(chapter, information)
|
||||||
|
except Exception as e:
|
||||||
|
self.log.error('Splitting track failed: ' + repr(e))
|
||||||
|
|
||||||
|
return [], information
|
||||||
|
Loading…
Reference in New Issue
Block a user