mirror of
https://github.com/yt-dlp/yt-dlp
synced 2024-12-27 21:59:17 +01:00
[ModifyChapters] Allow removing sections by timestamp
Eg: --remove-chapters "*10:15-15:00". The `*` prefix is used so as to avoid any conflicts with other valid regex
This commit is contained in:
parent
e820fbaa6f
commit
2d9ec70423
4 changed files with 30 additions and 5 deletions
|
@ -847,7 +847,11 @@ Then simply run `make`. You can also run `make yt-dlp` instead to compile only t
|
||||||
--no-split-chapters Do not split video based on chapters
|
--no-split-chapters Do not split video based on chapters
|
||||||
(default)
|
(default)
|
||||||
--remove-chapters REGEX Remove chapters whose title matches the
|
--remove-chapters REGEX Remove chapters whose title matches the
|
||||||
given regular expression. This option can
|
given regular expression. Time ranges
|
||||||
|
prefixed by a "*" can also be used in place
|
||||||
|
of chapters to remove the specified range.
|
||||||
|
Eg: --remove-chapters "*10:15-15:00"
|
||||||
|
--remove-chapters "intro". This option can
|
||||||
be used multiple times
|
be used multiple times
|
||||||
--no-remove-chapters Do not remove any chapters from the file
|
--no-remove-chapters Do not remove any chapters from the file
|
||||||
(default)
|
(default)
|
||||||
|
|
|
@ -31,6 +31,7 @@ from .utils import (
|
||||||
expand_path,
|
expand_path,
|
||||||
match_filter_func,
|
match_filter_func,
|
||||||
MaxDownloadsReached,
|
MaxDownloadsReached,
|
||||||
|
parse_duration,
|
||||||
preferredencoding,
|
preferredencoding,
|
||||||
read_batch_urls,
|
read_batch_urls,
|
||||||
RejectedVideoReached,
|
RejectedVideoReached,
|
||||||
|
@ -490,8 +491,14 @@ def _real_main(argv=None):
|
||||||
if opts.allsubtitles and not opts.writeautomaticsub:
|
if opts.allsubtitles and not opts.writeautomaticsub:
|
||||||
opts.writesubtitles = True
|
opts.writesubtitles = True
|
||||||
# ModifyChapters must run before FFmpegMetadataPP
|
# ModifyChapters must run before FFmpegMetadataPP
|
||||||
remove_chapters_patterns = []
|
remove_chapters_patterns, remove_ranges = [], []
|
||||||
for regex in opts.remove_chapters:
|
for regex in opts.remove_chapters:
|
||||||
|
if regex.startswith('*'):
|
||||||
|
dur = list(map(parse_duration, regex[1:].split('-')))
|
||||||
|
if len(dur) == 2 and all(t is not None for t in dur):
|
||||||
|
remove_ranges.append(tuple(dur))
|
||||||
|
continue
|
||||||
|
parser.error(f'invalid --remove-chapters time range {regex!r}. Must be of the form ?start-end')
|
||||||
try:
|
try:
|
||||||
remove_chapters_patterns.append(re.compile(regex))
|
remove_chapters_patterns.append(re.compile(regex))
|
||||||
except re.error as err:
|
except re.error as err:
|
||||||
|
@ -501,6 +508,7 @@ def _real_main(argv=None):
|
||||||
'key': 'ModifyChapters',
|
'key': 'ModifyChapters',
|
||||||
'remove_chapters_patterns': remove_chapters_patterns,
|
'remove_chapters_patterns': remove_chapters_patterns,
|
||||||
'remove_sponsor_segments': opts.sponsorblock_remove,
|
'remove_sponsor_segments': opts.sponsorblock_remove,
|
||||||
|
'remove_ranges': remove_ranges,
|
||||||
'sponsorblock_chapter_title': opts.sponsorblock_chapter_title,
|
'sponsorblock_chapter_title': opts.sponsorblock_chapter_title,
|
||||||
'force_keyframes': opts.force_keyframes_at_cuts
|
'force_keyframes': opts.force_keyframes_at_cuts
|
||||||
})
|
})
|
||||||
|
|
|
@ -1378,7 +1378,11 @@ def parseOpts(overrideArguments=None):
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'--remove-chapters',
|
'--remove-chapters',
|
||||||
metavar='REGEX', dest='remove_chapters', action='append',
|
metavar='REGEX', dest='remove_chapters', action='append',
|
||||||
help='Remove chapters whose title matches the given regular expression. This option can be used multiple times')
|
help=(
|
||||||
|
'Remove chapters whose title matches the given regular expression. '
|
||||||
|
'Time ranges prefixed by a "*" can also be used in place of chapters to remove the specified range. '
|
||||||
|
'Eg: --remove-chapters "*10:15-15:00" --remove-chapters "intro". '
|
||||||
|
'This option can be used multiple times'))
|
||||||
postproc.add_option(
|
postproc.add_option(
|
||||||
'--no-remove-chapters', dest='remove_chapters', action='store_const', const=None,
|
'--no-remove-chapters', dest='remove_chapters', action='store_const', const=None,
|
||||||
help='Do not remove any chapters from the file (default)')
|
help='Do not remove any chapters from the file (default)')
|
||||||
|
|
|
@ -20,11 +20,12 @@ DEFAULT_SPONSORBLOCK_CHAPTER_TITLE = '[SponsorBlock]: %(category_names)l'
|
||||||
|
|
||||||
|
|
||||||
class ModifyChaptersPP(FFmpegPostProcessor):
|
class ModifyChaptersPP(FFmpegPostProcessor):
|
||||||
def __init__(self, downloader, remove_chapters_patterns=None, remove_sponsor_segments=None,
|
def __init__(self, downloader, remove_chapters_patterns=None, remove_sponsor_segments=None, remove_ranges=None,
|
||||||
sponsorblock_chapter_title=DEFAULT_SPONSORBLOCK_CHAPTER_TITLE, force_keyframes=False):
|
*, sponsorblock_chapter_title=DEFAULT_SPONSORBLOCK_CHAPTER_TITLE, force_keyframes=False):
|
||||||
FFmpegPostProcessor.__init__(self, downloader)
|
FFmpegPostProcessor.__init__(self, downloader)
|
||||||
self._remove_chapters_patterns = set(remove_chapters_patterns or [])
|
self._remove_chapters_patterns = set(remove_chapters_patterns or [])
|
||||||
self._remove_sponsor_segments = set(remove_sponsor_segments or [])
|
self._remove_sponsor_segments = set(remove_sponsor_segments or [])
|
||||||
|
self._ranges_to_remove = set(remove_ranges or [])
|
||||||
self._sponsorblock_chapter_title = sponsorblock_chapter_title
|
self._sponsorblock_chapter_title = sponsorblock_chapter_title
|
||||||
self._force_keyframes = force_keyframes
|
self._force_keyframes = force_keyframes
|
||||||
|
|
||||||
|
@ -97,6 +98,14 @@ class ModifyChaptersPP(FFmpegPostProcessor):
|
||||||
if warn_no_chapter_to_remove:
|
if warn_no_chapter_to_remove:
|
||||||
self.to_screen('There are no matching SponsorBlock chapters')
|
self.to_screen('There are no matching SponsorBlock chapters')
|
||||||
|
|
||||||
|
sponsor_chapters.extend({
|
||||||
|
'start_time': start,
|
||||||
|
'end_time': end,
|
||||||
|
'category': 'manually_removed',
|
||||||
|
'_categories': [('manually_removed', start, end)],
|
||||||
|
'remove': True,
|
||||||
|
} for start, end in self._ranges_to_remove)
|
||||||
|
|
||||||
return chapters, sponsor_chapters
|
return chapters, sponsor_chapters
|
||||||
|
|
||||||
def _get_supported_subs(self, info):
|
def _get_supported_subs(self, info):
|
||||||
|
|
Loading…
Reference in a new issue