Skip to content

fix(downloader): prevent truncated videos from being reported as comp… - #66

Open
JunayedMh wants to merge 1 commit into
ayushjaipuriyar:mainfrom
JunayedMh:fix/incomplete-download-truncated-video
Open

fix(downloader): prevent truncated videos from being reported as comp…#66
JunayedMh wants to merge 1 commit into
ayushjaipuriyar:mainfrom
JunayedMh:fix/incomplete-download-truncated-video

Conversation

@JunayedMh

@JunayedMh JunayedMh commented Aug 16, 2026

Copy link
Copy Markdown

…lete

Episodes could finish "successfully" as a 1-3 minute file instead of the full ~23 minutes. Four independent defects combined to silently drop most of the video while the run still reported success:

  • download_segment padded truncated or empty HTTP bodies with NUL bytes and saved them, producing corrupt segments that made ffmpeg stop mid-video. It now rejects any empty or non-16-byte-aligned body and writes nothing, so the segment is retried instead of poisoning the merge.
  • 0-byte segment leftovers from a prior failed run were treated as "already downloaded" and skipped forever. Only non-empty files are skipped now.
  • The GUI download path discarded failed segments with no retry and no error, then compiled whatever was on disk. Segment downloading is now a single shared Downloader.download_segments() used by both CLI and GUI, which retries failing segments and reports incompleteness to the caller.
  • compile_video used ffmpeg's concat demuxer (which can reset per-file timestamps and truncate the output while still exiting 0) and never checked completeness. It now verifies every segment is present and non-empty, binary-concatenates the TS segments then remuxes, and rejects an output shorter than the playlist's expected duration (via ffprobe).

On any failure, segments are kept on disk so the next run resumes instead of overwriting a good partial download, and the playlist is fetched atomically.

Adds tests/test_download_integrity.py: 8 regression tests covering segment rejection, retry/failure reporting, and compile refusal. No network or ffmpeg required.

Pull Request

Description

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Performance improvement
  • Code refactoring
  • Test addition/modification
  • CI/CD changes

Related Issues

Fixes #
Relates to #

Changes Made

Testing

Test Configuration

  • Python version:
  • OS:
  • Test command:

Test Results

# Paste test output here

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published
  • I have updated the CHANGELOG.md (if applicable)
  • I have used conventional commit messages

Screenshots (if applicable)

Performance Impact

  • No performance impact
  • Performance improved
  • Performance degraded (explain why this is acceptable)

Breaking Changes

Additional Notes

Reviewer Checklist

  • Code quality is acceptable
  • Tests are adequate
  • Documentation is updated
  • No security concerns
  • Performance is acceptable

…lete

Episodes could finish "successfully" as a 1-3 minute file instead of the
full ~23 minutes. Four independent defects combined to silently drop most
of the video while the run still reported success:

- download_segment padded truncated or empty HTTP bodies with NUL bytes and
  saved them, producing corrupt segments that made ffmpeg stop mid-video. It
  now rejects any empty or non-16-byte-aligned body and writes nothing, so
  the segment is retried instead of poisoning the merge.
- 0-byte segment leftovers from a prior failed run were treated as "already
  downloaded" and skipped forever. Only non-empty files are skipped now.
- The GUI download path discarded failed segments with no retry and no error,
  then compiled whatever was on disk. Segment downloading is now a single
  shared Downloader.download_segments() used by both CLI and GUI, which
  retries failing segments and reports incompleteness to the caller.
- compile_video used ffmpeg's concat demuxer (which can reset per-file
  timestamps and truncate the output while still exiting 0) and never checked
  completeness. It now verifies every segment is present and non-empty,
  binary-concatenates the TS segments then remuxes, and rejects an output
  shorter than the playlist's expected duration (via ffprobe).

On any failure, segments are kept on disk so the next run resumes instead of
overwriting a good partial download, and the playlist is fetched atomically.

Adds tests/test_download_integrity.py: 8 regression tests covering segment
rejection, retry/failure reporting, and compile refusal. No network or
ffmpeg required.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant