Add audio format selection for audio-only downloads

Introduces settings and UI for forcing audio format conversion on audio-only downloads, including support for selecting preferred audio formats. Updates language files for all supported languages, adds config options, and passes new settings through the downloader and main app logic.
This commit is contained in:
oop7
2025-11-17 15:23:48 +02:00
parent d5c3b4799b
commit f2b6dc26cb
18 changed files with 263 additions and 15 deletions
+14 -1
View File
@@ -61,6 +61,8 @@ class DownloadThread(QThread):
geo_proxy_url=None,
force_output_format=False,
preferred_output_format="mp4",
force_audio_format=False,
preferred_audio_format="best",
) -> None:
super().__init__()
self.url = url
@@ -86,6 +88,8 @@ class DownloadThread(QThread):
self.geo_proxy_url = geo_proxy_url
self.force_output_format = force_output_format
self.preferred_output_format = preferred_output_format
self.force_audio_format = force_audio_format
self.preferred_audio_format = preferred_audio_format
self.paused: bool = False
self.cancelled: bool = False
self.process: Optional[subprocess.Popen] = None
@@ -184,7 +188,7 @@ class DownloadThread(QThread):
res_value: str = self.resolution if self.resolution else "720" # Default to 720p if no resolution specified
cmd.extend(["-S", f"res:{res_value}"])
# Force output format if enabled and merging is needed
# Force output format if enabled and merging is needed (for video)
if self.force_output_format and not self.is_audio_only:
if self.format_has_audio:
# Progressive format (video with audio) - use remux to convert container
@@ -195,6 +199,15 @@ class DownloadThread(QThread):
cmd.extend(["--merge-output-format", self.preferred_output_format])
logger.debug(f"Using --merge-output-format to force merged format to: {self.preferred_output_format}")
# Force audio format conversion for audio-only downloads
if self.is_audio_only and self.force_audio_format:
cmd.append("--extract-audio")
if self.preferred_audio_format and self.preferred_audio_format != "best":
cmd.extend(["--audio-format", self.preferred_audio_format])
logger.debug(f"Using --extract-audio with --audio-format {self.preferred_audio_format} for audio-only download")
else:
logger.debug("Using --extract-audio with best quality (no conversion) for audio-only download")
# Output template with resolution in filename
# Use string concatenation instead of Path.joinpath to avoid Path object issues
base_path: str = self.path.as_posix()
@@ -234,6 +234,52 @@ class DownloadSettingsDialog(QDialog):
output_format_group_box.setLayout(output_format_layout)
layout.addWidget(output_format_group_box)
# --- Audio Format Settings Section (for audio-only downloads) ---
audio_format_group_box = QGroupBox(_("settings.audio_format_settings"))
audio_format_layout = QVBoxLayout()
# Load current audio format settings from ConfigManager
self.force_audio_format_enabled = ConfigManager.get("force_audio_format") or False
self.preferred_audio_format_value = ConfigManager.get("preferred_audio_format") or "best"
# Enable/Disable force audio format checkbox
self.force_audio_format_checkbox = QCheckBox(_("settings.force_audio_format"))
self.force_audio_format_checkbox.setChecked(self.force_audio_format_enabled)
audio_format_layout.addWidget(self.force_audio_format_checkbox)
# Audio format selection layout
audio_format_select_layout = QHBoxLayout()
audio_format_label = QLabel(_("settings.preferred_audio_format"))
audio_format_label.setStyleSheet("color: #ffffff; margin-top: 5px;")
audio_format_select_layout.addWidget(audio_format_label)
self.audio_format_combo = QComboBox()
self.audio_format_combo.addItems([
_("settings.audio_format_best"),
_("settings.audio_format_aac"),
_("settings.audio_format_mp3"),
_("settings.audio_format_flac"),
_("settings.audio_format_wav"),
_("settings.audio_format_opus"),
_("settings.audio_format_m4a"),
_("settings.audio_format_vorbis")
])
# Set current selection based on saved format
audio_format_index_map = {"best": 0, "aac": 1, "mp3": 2, "flac": 3, "wav": 4, "opus": 5, "m4a": 6, "vorbis": 7}
self.audio_format_combo.setCurrentIndex(audio_format_index_map.get(self.preferred_audio_format_value, 0))
audio_format_select_layout.addWidget(self.audio_format_combo)
audio_format_select_layout.addStretch()
audio_format_layout.addLayout(audio_format_select_layout)
# Help text for audio format
audio_help_label = QLabel(_("settings.force_audio_format_help"))
audio_help_label.setWordWrap(True)
audio_help_label.setStyleSheet("color: #cccccc; margin: 5px; font-size: 10px;")
audio_format_layout.addWidget(audio_help_label)
audio_format_group_box.setLayout(audio_format_layout)
layout.addWidget(audio_format_group_box)
# Dialog buttons (OK/Cancel)
button_box = QDialogButtonBox()
ok_button = button_box.addButton(_("buttons.ok"), QDialogButtonBox.ButtonRole.AcceptRole)
@@ -277,6 +323,15 @@ class DownloadSettingsDialog(QDialog):
format_map = {0: "mp4", 1: "webm", 2: "mkv"}
return format_map.get(self.format_combo.currentIndex(), "mp4")
def get_force_audio_format_enabled(self) -> bool:
"""Returns whether force audio format is enabled."""
return self.force_audio_format_checkbox.isChecked()
def get_preferred_audio_format(self) -> str:
"""Returns the selected preferred audio format (lowercase)."""
audio_format_map = {0: "best", 1: "aac", 2: "mp3", 3: "flac", 4: "wav", 5: "opus", 6: "m4a", 7: "vorbis"}
return audio_format_map.get(self.audio_format_combo.currentIndex(), "best")
def _create_styled_message_box(self, icon, title, text) -> QMessageBox:
"""Create a styled QMessageBox that matches the app theme."""
msg_box = QMessageBox(self)
@@ -321,6 +376,12 @@ class DownloadSettingsDialog(QDialog):
ConfigManager.set("force_output_format", force_format)
ConfigManager.set("preferred_output_format", preferred_format)
# Save audio format settings
force_audio_format = self.get_force_audio_format_enabled()
preferred_audio_format = self.get_preferred_audio_format()
ConfigManager.set("force_audio_format", force_audio_format)
ConfigManager.set("preferred_audio_format", preferred_audio_format)
QMessageBox.information(
self,
_("settings.settings_saved_title"),
+4
View File
@@ -125,6 +125,8 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from
# Initialize output format settings
self.force_output_format = ConfigManager.get("force_output_format") or False
self.preferred_output_format = ConfigManager.get("preferred_output_format") or "mp4"
self.force_audio_format = ConfigManager.get("force_audio_format") or False
self.preferred_audio_format = ConfigManager.get("preferred_audio_format") or "best"
# Track if video analysis is completed
self.analysis_completed = False
@@ -898,6 +900,8 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from
geo_proxy_url=self.geo_proxy_url, # Pass the geo-verification proxy URL
force_output_format=self.force_output_format, # Pass force output format setting
preferred_output_format=self.preferred_output_format, # Pass preferred format
force_audio_format=self.force_audio_format, # Pass force audio format setting
preferred_audio_format=self.preferred_audio_format, # Pass preferred audio format
)
# Connect signals
+2
View File
@@ -84,6 +84,8 @@ class ConfigManager:
"ytdlp_channel": "stable",
"force_output_format": False,
"preferred_output_format": "mp4",
"force_audio_format": False,
"preferred_audio_format": "best",
"cached_versions": {
"ytdlp": {"version": None, "path": None, "last_check": 0, "path_mtime": 0},
"ffmpeg": {"version": None, "path": None, "last_check": 0, "path_mtime": 0},