Fix medium-severity defects across download, formats and tooling
- Format table: a missing acodec was treated as "has audio", skipping
the +bestaudio merge and producing silent videos for extractors that
omit the field.
- Progress bar: separate video/audio stream downloads each reported
0-100%, making the bar jump backwards; per-phase scaling now maps the
two streams onto 0-50/50-100.
- Custom commands: parse with shlex (quoted arguments with spaces were
shredded by str.split), keep POSIX mode off on Windows so backslash
paths survive, hide the console window like every other call site,
close the stdout pipe, and support cancellation of a running command.
- Settings dialog: _("settings", "error_saving", ...) passed two
positional args to the i18n helper, raising TypeError inside the
except handler instead of showing the intended error dialog.
- ffmpeg on Windows: Path(os.getenv("LOCALAPPDATA")) crashed with
TypeError when the variable is unset; fall back to the standard
AppData/Local location.
- Version cache: cached path (str) was compared against a Path, so the
cache never hit and every version query spawned a subprocess.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,8 @@ class DownloadThread(QThread):
|
||||
self.subtitle_files: List[str] = [] # Track subtitle files that are created
|
||||
self.initial_subtitle_files: Set[Path] = set() # Track initial subtitle files before download
|
||||
self.download_files: Set[Path] = set() # Every destination path this download wrote to
|
||||
self.expected_phases: int = 1 # 2 when video and audio download separately before merge
|
||||
self._media_phase: int = 0 # Index of the media stream currently downloading
|
||||
|
||||
def cleanup_partial_files(self) -> None:
|
||||
"""Delete partial files (.part/.ytdl and unmerged .fNNN. streams), but only
|
||||
@@ -293,6 +295,7 @@ class DownloadThread(QThread):
|
||||
logger.debug(f"Using progressive format with bundled audio: {clean_format_id}")
|
||||
else:
|
||||
cmd.extend(["-f", f"{clean_format_id}+bestaudio/best"])
|
||||
self.expected_phases = 2 # separate video and audio downloads
|
||||
logger.debug(f"Using video-only format merged with best audio: {clean_format_id}+bestaudio/best")
|
||||
else:
|
||||
# If no specific format ID, use resolution-based sorting (-S)
|
||||
@@ -635,6 +638,8 @@ class DownloadThread(QThread):
|
||||
filepath = dest_match.group(1).strip()
|
||||
self.current_filename = Path(filepath).name
|
||||
self.last_file_path = filepath # Store the full path for later cleanup
|
||||
if Path(filepath) not in self.download_files and Path(filepath).suffix.lower() not in SUBTITLE_EXTENSIONS:
|
||||
self._media_phase += 1
|
||||
self.download_files.add(Path(filepath))
|
||||
logger.debug(f"Extracted filename: {self.current_filename}") # DEBUG
|
||||
|
||||
@@ -755,6 +760,11 @@ class DownloadThread(QThread):
|
||||
if percent_match:
|
||||
try:
|
||||
percent = float(percent_match.group(1))
|
||||
# When video and audio download as separate streams, scale each
|
||||
# phase into its share of the bar instead of jumping 0-100 twice
|
||||
if self.expected_phases > 1 and not self.is_playlist:
|
||||
completed = max(0, min(self._media_phase - 1, self.expected_phases - 1))
|
||||
percent = (completed * 100.0 + percent) / self.expected_phases
|
||||
self.progress_signal.emit(percent)
|
||||
except (ValueError, IndexError):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user