[ModifyChapters] fixes (See desc)

* [docs] Fix typo
* Do not enable `sponskrub` by default
* Fix `--force-keyframes-at-cuts`
* Don't embed subtitles if the video has been cut. Previously, running `--remove-chapters` with `--embed-subs` multiple times caused repeated cuts and out-of-sync subtitles
* Store `_real_duration` to prevent running ffprobe multiple times
This commit is contained in:
pukkandan 2021-09-04 01:37:41 +05:30
parent dd594deb2a
commit 165efb823b
No known key found for this signature in database
GPG key ID: 0F00D95A001F4698
3 changed files with 29 additions and 15 deletions

View file

@ -1394,7 +1394,7 @@ def _dict_from_options_callback(
'SponsorBlock categories to create chapters for, separated by commas. ' 'SponsorBlock categories to create chapters for, separated by commas. '
'Available categories are all, %s. You can prefix the category with a "-" to exempt it. ' 'Available categories are all, %s. You can prefix the category with a "-" to exempt it. '
'See https://wiki.sponsor.ajay.app/index.php/Segment_Categories for description of the categories. ' 'See https://wiki.sponsor.ajay.app/index.php/Segment_Categories for description of the categories. '
'Eg: --sponsorblock-query all,-preview' % ', '.join(SponsorBlockPP.CATEGORIES.keys()))) 'Eg: --sponsorblock-mark all,-preview' % ', '.join(SponsorBlockPP.CATEGORIES.keys())))
sponsorblock.add_option( sponsorblock.add_option(
'--sponsorblock-remove', metavar='CATS', '--sponsorblock-remove', metavar='CATS',
dest='sponsorblock_remove', default=set(), action='callback', type='str', dest='sponsorblock_remove', default=set(), action='callback', type='str',
@ -1421,7 +1421,7 @@ def _dict_from_options_callback(
sponsorblock.add_option( sponsorblock.add_option(
'--sponskrub', '--sponskrub',
action='store_true', dest='sponskrub', default=None, action='store_true', dest='sponskrub', default=False,
help=optparse.SUPPRESS_HELP) help=optparse.SUPPRESS_HELP)
sponsorblock.add_option( sponsorblock.add_option(
'--no-sponskrub', '--no-sponskrub',

View file

@ -15,6 +15,7 @@
dfxp2srt, dfxp2srt,
encodeArgument, encodeArgument,
encodeFilename, encodeFilename,
float_or_none,
get_exe_version, get_exe_version,
is_outdated_version, is_outdated_version,
ISO639Utils, ISO639Utils,
@ -233,6 +234,23 @@ def get_stream_number(self, path, keys, value):
None) None)
return num, len(streams) return num, len(streams)
def _get_real_video_duration(self, info, fatal=True):
try:
if '_real_duration' not in info:
info['_real_duration'] = float_or_none(
traverse_obj(self.get_metadata_object(info['filepath']), ('format', 'duration')))
if not info['_real_duration']:
raise PostProcessingError('ffprobe returned empty duration')
except PostProcessingError as e:
if fatal:
raise PostProcessingError(f'Unable to determine video duration; {e}')
return info.setdefault('_real_duration', None)
def _duration_mismatch(self, d1, d2):
if not d1 or not d2:
return None
return abs(d1 - d2) > 1
def run_ffmpeg_multiple_files(self, input_paths, out_path, opts, **kwargs): def run_ffmpeg_multiple_files(self, input_paths, out_path, opts, **kwargs):
return self.real_run_ffmpeg( return self.real_run_ffmpeg(
[(path, []) for path in input_paths], [(path, []) for path in input_paths],
@ -528,6 +546,10 @@ def run(self, information):
return [], information return [], information
filename = information['filepath'] filename = information['filepath']
if self._duration_mismatch(
self._get_real_video_duration(information, False), information['duration']):
self.to_screen(f'Skipping {self.pp_key()} since the real and expected durations mismatch')
return [], information
ext = information['ext'] ext = information['ext']
sub_langs, sub_names, sub_filenames = [], [], [] sub_langs, sub_names, sub_filenames = [], [], []

View file

@ -9,11 +9,9 @@
) )
from .sponsorblock import SponsorBlockPP from .sponsorblock import SponsorBlockPP
from ..utils import ( from ..utils import (
float_or_none,
orderedSet, orderedSet,
PostProcessingError, PostProcessingError,
prepend_extension, prepend_extension,
traverse_obj,
) )
@ -37,7 +35,7 @@ def run(self, info):
if not chapters and not sponsor_chapters: if not chapters and not sponsor_chapters:
return [], info return [], info
real_duration = self._get_real_video_duration(info['filepath']) real_duration = self._get_real_video_duration(info)
if not chapters: if not chapters:
chapters = [{'start_time': 0, 'end_time': real_duration, 'title': info['title']}] chapters = [{'start_time': 0, 'end_time': real_duration, 'title': info['title']}]
@ -45,8 +43,8 @@ def run(self, info):
if not cuts: if not cuts:
return [], info return [], info
if abs(real_duration - info['duration']) > 1: if self._duration_mismatch(real_duration, info.get('duration')):
if abs(real_duration - info['chapters'][-1]['end_time']) < 1: if not self._duration_mismatch(real_duration, info['chapters'][-1]['end_time']):
self.to_screen(f'Skipping {self.pp_key()} since the video appears to be already cut') self.to_screen(f'Skipping {self.pp_key()} since the video appears to be already cut')
return [], info return [], info
if not info.get('__real_download'): if not info.get('__real_download'):
@ -72,6 +70,7 @@ def remove_chapters(file, is_sub):
os.replace(out_file, in_file) os.replace(out_file, in_file)
files_to_remove.append(uncut_file) files_to_remove.append(uncut_file)
info['_real_duration'] = info['chapters'][-1]['end_time']
return files_to_remove, info return files_to_remove, info
def _mark_chapters_to_remove(self, chapters, sponsor_chapters): def _mark_chapters_to_remove(self, chapters, sponsor_chapters):
@ -101,13 +100,6 @@ def _mark_chapters_to_remove(self, chapters, sponsor_chapters):
return chapters, sponsor_chapters return chapters, sponsor_chapters
def _get_real_video_duration(self, filename):
duration = float_or_none(
traverse_obj(self.get_metadata_object(filename), ('format', 'duration')))
if duration is None:
raise PostProcessingError('ffprobe returned empty duration')
return duration
def _get_supported_subs(self, info): def _get_supported_subs(self, info):
for sub in (info.get('requested_subtitles') or {}).values(): for sub in (info.get('requested_subtitles') or {}).values():
sub_file = sub.get('filepath') sub_file = sub.get('filepath')
@ -311,7 +303,7 @@ def remove_chapters(self, filename, ranges_to_cut, concat_opts, force_keyframes=
in_file = filename in_file = filename
out_file = prepend_extension(in_file, 'temp') out_file = prepend_extension(in_file, 'temp')
if force_keyframes: if force_keyframes:
in_file = self.force_keyframes(in_file, (t for r in ranges_to_cut for t in r)) in_file = self.force_keyframes(in_file, (t for c in ranges_to_cut for t in (c['start_time'], c['end_time'])))
self.to_screen(f'Removing chapters from {filename}') self.to_screen(f'Removing chapters from {filename}')
self.concat_files([in_file] * len(concat_opts), out_file, concat_opts) self.concat_files([in_file] * len(concat_opts), out_file, concat_opts)
if in_file != filename: if in_file != filename: