diff --git a/yt_dlp/postprocessor/ffmpeg.py b/yt_dlp/postprocessor/ffmpeg.py index e8b569d72..f712547a8 100644 --- a/yt_dlp/postprocessor/ffmpeg.py +++ b/yt_dlp/postprocessor/ffmpeg.py @@ -251,22 +251,23 @@ def get_stream_number(self, path, keys, value): None) return num, len(streams) - def _get_real_video_duration(self, info, fatal=True): + def _get_real_video_duration(self, filepath, 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']: + duration = float_or_none( + traverse_obj(self.get_metadata_object(filepath), ('format', 'duration'))) + if not duration: raise PostProcessingError('ffprobe returned empty duration') + return duration except PostProcessingError as e: if fatal: - raise PostProcessingError(f'Unable to determine video duration; {e}') - return info.setdefault('_real_duration', None) + raise PostProcessingError(f'Unable to determine video duration: {e.msg}') def _duration_mismatch(self, d1, d2): if not d1 or not d2: return None - return abs(d1 - d2) > 1 + # The duration is often only known to nearest second. So there can be <1sec disparity natually. + # Further excuse an additional <1sec difference. + return abs(d1 - d2) > 2 def run_ffmpeg_multiple_files(self, input_paths, out_path, opts, **kwargs): return self.real_run_ffmpeg( @@ -575,22 +576,22 @@ def __init__(self, downloader=None, already_have_subtitle=False): self._already_have_subtitle = already_have_subtitle @PostProcessor._restrict_to(images=False) - def run(self, information): - if information['ext'] not in ('mp4', 'webm', 'mkv'): + def run(self, info): + if info['ext'] not in ('mp4', 'webm', 'mkv'): self.to_screen('Subtitles can only be embedded in mp4, webm or mkv files') - return [], information - subtitles = information.get('requested_subtitles') + return [], info + subtitles = info.get('requested_subtitles') if not subtitles: self.to_screen('There aren\'t any subtitles to embed') - return [], information + return [], info - filename = information['filepath'] - if information.get('duration') and self._duration_mismatch( - self._get_real_video_duration(information, False), information['duration']): + filename = info['filepath'] + if info.get('duration') and not info.get('__real_download') and self._duration_mismatch( + self._get_real_video_duration(filename, False), info['duration']): self.to_screen(f'Skipping {self.pp_key()} since the real and expected durations mismatch') - return [], information + return [], info - ext = information['ext'] + ext = info['ext'] sub_langs, sub_names, sub_filenames = [], [], [] webm_vtt_warn = False mp4_ass_warn = False @@ -615,7 +616,7 @@ def run(self, information): self.report_warning('ASS subtitles cannot be properly embedded in mp4 files; expect issues') if not sub_langs: - return [], information + return [], info input_files = [filename] + sub_filenames @@ -628,7 +629,7 @@ def run(self, information): # https://trac.ffmpeg.org/ticket/6016) '-map', '-0:d', ] - if information['ext'] == 'mp4': + if info['ext'] == 'mp4': opts += ['-c:s', 'mov_text'] for i, (lang, name) in enumerate(zip(sub_langs, sub_names)): opts.extend(['-map', '%d:0' % (i + 1)]) @@ -644,7 +645,7 @@ def run(self, information): os.replace(temp_filename, filename) files_to_delete = [] if self._already_have_subtitle else sub_filenames - return files_to_delete, information + return files_to_delete, info class FFmpegMetadataPP(FFmpegPostProcessor): diff --git a/yt_dlp/postprocessor/modify_chapters.py b/yt_dlp/postprocessor/modify_chapters.py index dca876200..0728bdcf5 100644 --- a/yt_dlp/postprocessor/modify_chapters.py +++ b/yt_dlp/postprocessor/modify_chapters.py @@ -38,7 +38,7 @@ def run(self, info): if not chapters and not sponsor_chapters: return [], info - real_duration = self._get_real_video_duration(info) + real_duration = self._get_real_video_duration(info['filepath']) if not chapters: chapters = [{'start_time': 0, 'end_time': real_duration, 'title': info['title']}] @@ -72,7 +72,6 @@ def remove_chapters(file, is_sub): os.replace(out_file, in_file) files_to_remove.append(uncut_file) - info['_real_duration'] = info['chapters'][-1]['end_time'] return files_to_remove, info def _mark_chapters_to_remove(self, chapters, sponsor_chapters):