diff --git a/CHANGES b/CHANGES index 14a9d1d..f5d64d3 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,13 @@ # Changelog +## Version 5.7.1 + +* Fixing profile audio box not being able to select pattern match +* Fixing #561 Subtitles all show as English in FastFlix subtitles screen (thanks to David James) +* Fixing #562 Audio conversion window defaults channel layout to stereo (thanks to David James) +* Fixing #563 No Thumbnails When Importing Video (thanks to Damundai) +* Fixing #564 Audio custom bitrate box shows units in kilobits/second but passes bits/second as the parameter (thanks to tcmbackwards) + ## Version 5.7.0 * Adding new audio encoding panel diff --git a/fastflix/encoders/common/audio.py b/fastflix/encoders/common/audio.py index b84421a..f2b719e 100644 --- a/fastflix/encoders/common/audio.py +++ b/fastflix/encoders/common/audio.py @@ -43,7 +43,10 @@ def build_audio(audio_tracks, audio_file_index=0): if not track.conversion_codec or track.conversion_codec == "none": command_list.append(f"-c:{track.outdex} copy") elif track.conversion_codec: - cl = track.downmix if "downmix" in track and track.downmix else track.raw_info.channel_layout + try: + cl = track.downmix if "downmix" in track and track.downmix else track.raw_info.channel_layout + except AssertionError: + cl = "stereo" downmix = ( f"-ac:{track.outdex} {channel_list[cl]} -filter:{track.outdex} aformat=channel_layouts={cl}" if track.downmix @@ -51,8 +54,13 @@ def build_audio(audio_tracks, audio_file_index=0): ) bitrate = "" if track.conversion_codec not in lossless: + conversion_bitrate = ( + track.conversion_bitrate + if track.conversion_bitrate.lower().endswith(("k", "m", "g", "kb", "mb", "gb")) + else f"{track.conversion_bitrate}k" + ) channel_layout = f'-filter:{track.outdex} aformat=channel_layouts="{track.raw_info.channel_layout}"' - bitrate = f"-b:{track.outdex} {track.conversion_bitrate} {channel_layout}" + bitrate = f"-b:{track.outdex} {conversion_bitrate} {channel_layout}" command_list.append(f"-c:{track.outdex} {track.conversion_codec} {bitrate} {downmix}") if getattr(track, "dispositions", None): diff --git a/fastflix/encoders/common/encc_helpers.py b/fastflix/encoders/common/encc_helpers.py index 05f1f84..944f427 100644 --- a/fastflix/encoders/common/encc_helpers.py +++ b/fastflix/encoders/common/encc_helpers.py @@ -101,7 +101,12 @@ def build_audio(audio_tracks: list[AudioTrack], audio_streams): bitrate = "" if track.conversion_codec not in lossless: if track.conversion_bitrate: - bitrate = f"--audio-bitrate {audio_id}?{track.conversion_bitrate} " + conversion_bitrate = ( + track.conversion_bitrate + if track.conversion_bitrate.lower().endswith(("k", "m", "g", "kb", "mb", "gb")) + else f"{track.conversion_bitrate}k" + ) + bitrate = f"--audio-bitrate {audio_id}?{conversion_bitrate} " else: bitrate = f"--audio-quality {audio_id}?{track.conversion_aq} " command_list.append( diff --git a/fastflix/encoders/common/setting_panel.py b/fastflix/encoders/common/setting_panel.py index 1c94a45..44abd27 100644 --- a/fastflix/encoders/common/setting_panel.py +++ b/fastflix/encoders/common/setting_panel.py @@ -450,6 +450,9 @@ def _add_modes( return layout + def set_mode(self): + raise NotImplementedError("Child must implement this function") + @property def ffmpeg_extras(self): return ffmpeg_extra_command diff --git a/fastflix/version.py b/fastflix/version.py index 08393cc..36aa9c0 100644 --- a/fastflix/version.py +++ b/fastflix/version.py @@ -1,4 +1,4 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -__version__ = "5.7.0" +__version__ = "5.7.1" __author__ = "Chris Griffith" diff --git a/fastflix/widgets/main.py b/fastflix/widgets/main.py index 25731a1..42dde7c 100644 --- a/fastflix/widgets/main.py +++ b/fastflix/widgets/main.py @@ -1681,12 +1681,14 @@ def thread_logger(text): @reusables.log_exception("fastflix", show_traceback=False) def thumbnail_generated(self, status=0): - if status == 0 or not status or not self.thumb_file.exists(): - self.widgets.preview.setText(t("Error Updating Thumbnail")) - return if status == 2: + self.app.fastflix.opencl_support = False self.generate_thumbnail() return + if status == 0 or not status or not self.thumb_file.exists(): + self.widgets.preview.setText(t("Error Updating Thumbnail")) + return + pixmap = QtGui.QPixmap(str(self.thumb_file)) pixmap = pixmap.scaled(420, 260, QtCore.Qt.KeepAspectRatio) self.widgets.preview.setPixmap(pixmap) diff --git a/fastflix/widgets/panels/abstract_list.py b/fastflix/widgets/panels/abstract_list.py index 00da12d..a2490b8 100644 --- a/fastflix/widgets/panels/abstract_list.py +++ b/fastflix/widgets/panels/abstract_list.py @@ -20,11 +20,13 @@ def __init__(self, app: FastFlixApp, parent, list_name, list_type, top_row_layou self.inner_layout = None self.list_type = list_type - layout = QtWidgets.QGridLayout() + layout = QtWidgets.QVBoxLayout() if top_row_layout: - layout.addLayout(top_row_layout, 0, 0) + layout.addLayout(top_row_layout) else: - layout.addWidget(QtWidgets.QLabel(t(list_name))) + header_text = QtWidgets.QLabel(t(list_name)) + header_text.setFixedHeight(30) + layout.addWidget(header_text) self.inner_widget = QtWidgets.QWidget() diff --git a/fastflix/widgets/panels/audio_panel.py b/fastflix/widgets/panels/audio_panel.py index a052697..84673b1 100644 --- a/fastflix/widgets/panels/audio_panel.py +++ b/fastflix/widgets/panels/audio_panel.py @@ -189,21 +189,13 @@ def init_move_buttons(self): layout.addWidget(self.widgets.down_button) return layout - def get_conversion_bitrates(self, channels=None): - if not channels: - channels = self.channels or 2 - bitrates = [x for x in range(16 * channels, (256 * channels) + 1, 16 * channels)] - if channels > 1: - bitrates.append(640) - return [f"{x}k" for x in sorted(set(bitrates))] - def update_enable(self): enabled = self.widgets.enable_check.isChecked() audio_track = self.app.fastflix.current_video.audio_tracks[self.index] audio_track.enabled = enabled self.widgets.track_number.setText(f"{audio_track.index}:{audio_track.outdex}" if enabled else "❌") self.parent.reorder(update=True) - self.parent.parent.subtitles.reorder() + # self.parent.parent.subtitles.reorder() def page_update(self): if not self.loading: diff --git a/fastflix/widgets/panels/subtitle_panel.py b/fastflix/widgets/panels/subtitle_panel.py index f774e22..0327a9b 100644 --- a/fastflix/widgets/panels/subtitle_panel.py +++ b/fastflix/widgets/panels/subtitle_panel.py @@ -59,12 +59,15 @@ def __init__(self, app, parent, index, enabled=True, first=False): self.outdex = None self.first = first self.last = False - self.setFixedHeight(60) + # self.setFixedHeight(180) sub_track: SubtitleTrack = self.app.fastflix.current_video.subtitle_tracks[index] + long_name = ( + f" {sub_track.long_name}" if sub_track.long_name else f" {t('Subtitle Type')}:{sub_track.subtitle_type}" + ) self.widgets = Box( track_number=QtWidgets.QLabel(f"{sub_track.index}:{sub_track.outdex}" if enabled else "❌"), - title=QtWidgets.QLabel(f" {sub_track.long_name}"), + title=QtWidgets.QLabel(long_name), up_button=QtWidgets.QPushButton( QtGui.QIcon(get_icon("up-arrow", self.parent.app.fastflix.config.theme)), "" ), @@ -135,7 +138,7 @@ def __init__(self, app, parent, index, enabled=True, first=False): self.grid.addLayout(disposition_layout, 0, 4) self.grid.addWidget(self.widgets.burn_in, 0, 5) - self.grid.addLayout(self.init_language(), 0, 6) + self.grid.addLayout(self.init_language(sub_track), 0, 6) self.grid.addWidget(self.widgets.enable_check, 0, 8) @@ -170,11 +173,11 @@ def extract(self): self.widgets.extract.hide() self.movie.start() - def init_language(self): + def init_language(self, sub_track: SubtitleTrack): self.widgets.language.addItems(language_list) self.widgets.language.setMaximumWidth(110) try: - self.widgets.language.setCurrentIndex(language_list.index(Lang(self.subtitle_lang).name)) + self.widgets.language.setCurrentIndex(language_list.index(Lang(sub_track.language).name)) except Exception: self.widgets.language.setCurrentIndex(language_list.index("English")) self.widgets.language.currentIndexChanged.connect(self.page_update) diff --git a/fastflix/widgets/windows/audio_conversion.py b/fastflix/widgets/windows/audio_conversion.py index b2a7869..0bc9c09 100644 --- a/fastflix/widgets/windows/audio_conversion.py +++ b/fastflix/widgets/windows/audio_conversion.py @@ -41,6 +41,7 @@ "quad(side)": 4, "5.0": 5, "5.1": 6, + "5.1(side)": 6, "6.0": 6, "6.0(front)": 6, "hexagonal": 6, @@ -52,6 +53,17 @@ "7.1(wide)": 8, } +back_channel_list = { + 1: "mono", + 2: "stereo", + 3: "2.1", + 4: "3.1", + 5: "5.0", + 6: "5.1", + 7: "6.1", + 8: "7.1", +} + class AudioConversion(QtWidgets.QWidget): def __init__(self, app: FastFlixApp, track_index, encoders, audio_track_update): @@ -118,11 +130,19 @@ def __init__(self, app: FastFlixApp, track_index, encoders, audio_track_update): quality_layout.addWidget(self.bitrate) quality_layout.addWidget(QtWidgets.QLabel("kb/s")) - # Downmix + channel_layout = self.audio_track.raw_info.get("channel_layout") self.downmix = QtWidgets.QComboBox() self.downmix.addItems([t("None")] + list(channel_list.keys())) - self.downmix.setCurrentIndex(2) + try: + if channel_layout: + self.downmix.setCurrentText(channel_layout) + else: + guess = back_channel_list[self.audio_track.raw_info.get("channels")] + logger.warning(f"Channel layout not found for {self.audio_track.title}, guessing {guess}") + self.downmix.setCurrentText(guess) + except Exception: + self.downmix.setCurrentIndex(2) if self.audio_track.downmix: self.downmix.setCurrentText(self.audio_track.downmix) diff --git a/fastflix/widgets/windows/profile_window.py b/fastflix/widgets/windows/profile_window.py index 420b71c..a6c6e64 100644 --- a/fastflix/widgets/windows/profile_window.py +++ b/fastflix/widgets/windows/profile_window.py @@ -164,35 +164,54 @@ def __init__(self, app, parent, main): self.tracks = [] self.main = main - self.passthrough_checkbox = QtWidgets.QCheckBox(t("Passthrough All")) - self.disable_audio_checkbox = QtWidgets.QCheckBox(t("Don't Select Any Audio")) + self.audio_select_type = QtWidgets.QButtonGroup() + + self.passthrough_name = t("Passthrough All") + self.disable_audio_name = t("Don't Select Any Audio") + self.patter_match_name = t("Pattern Match") + + self.passthrough_checkbox = QtWidgets.QRadioButton(self.passthrough_name) + self.disable_audio_checkbox = QtWidgets.QRadioButton(self.disable_audio_name) + self.patter_match_checkbox = QtWidgets.QRadioButton(self.patter_match_name) + + self.audio_select_type.addButton(self.passthrough_checkbox) + self.audio_select_type.addButton(self.disable_audio_checkbox) + self.audio_select_type.addButton(self.patter_match_checkbox) + self.audio_select_type.buttonClicked.connect(self.set_audio_mode) self.add_button = QtWidgets.QPushButton(f' {t("Add Pattern Match")} ') if self.app.fastflix.config.theme == "onyx": self.add_button.setStyleSheet("border-radius: 10px;") - self.passthrough_checkbox.toggled.connect(self.passthrough_check) - self.disable_audio_checkbox.toggled.connect(self.disable_audio_check) + # self.passthrough_checkbox.toggled.connect(self.passthrough_check) + # self.disable_audio_checkbox.toggled.connect(self.disable_audio_check) self.add_button.clicked.connect(self.add_track) + button_layout = QtWidgets.QVBoxLayout() + button_layout.addWidget(self.passthrough_checkbox) + button_layout.addWidget(self.disable_audio_checkbox) + button_layout.addWidget(self.patter_match_checkbox) + + top_layout = QtWidgets.QHBoxLayout() + top_layout.addLayout(button_layout) + top_layout.addWidget(self.add_button) + layout = self.layout() # self.scroll_area = super().scroll_area layout.removeWidget(self.scroll_area) + layout.addLayout(top_layout) - layout.addWidget(self.passthrough_checkbox, 0, 0) - layout.addWidget(self.disable_audio_checkbox, 0, 1) - layout.addWidget(self.add_button, 0, 2, alignment=QtCore.Qt.AlignRight) - - layout.addWidget(self.scroll_area, 1, 0, 1, 3) + layout.addWidget(self.scroll_area) self.hardware_warning = QtWidgets.QLabel(t("Rigaya's encoders will only match one encoding per track")) self.hardware_warning.hide() - layout.addWidget(self.hardware_warning, 2, 0) + layout.addWidget(self.hardware_warning) self.passthrough_checkbox.setChecked(True) - self.disable_audio_checkbox.setChecked(False) - # self.passthrough_checkbox.setChecked(True) + self.scroll_area.setDisabled(True) + self.add_button.setDisabled(True) + super()._new_source(self.tracks) def update_settings(self): @@ -212,23 +231,23 @@ def remove_track(self, index): track.index = i self.reorder(height=126) - def passthrough_check(self): - if self.passthrough_checkbox.isChecked(): - if self.disable_audio_checkbox.isChecked(): - self.disable_audio_checkbox.setChecked(False) + def set_audio_mode(self, button): + if button.text() == self.passthrough_name: + # self.passthrough_checkbox.setChecked(True) + # self.disable_audio_checkbox.setChecked(False) + # self.patter_match_checkbox.setChecked(False) self.scroll_area.setDisabled(True) self.add_button.setDisabled(True) - else: - self.scroll_area.setEnabled(True) - self.add_button.setEnabled(True) - - def disable_audio_check(self): - if self.disable_audio_checkbox.isChecked(): - if self.passthrough_checkbox.isChecked(): - self.passthrough_checkbox.setChecked(False) + elif button.text() == self.disable_audio_name: + # self.passthrough_checkbox.setChecked(False) + # self.disable_audio_checkbox.setChecked(True) + # self.patter_match_checkbox.setChecked(False) self.scroll_area.setDisabled(True) self.add_button.setDisabled(True) - else: + elif button.text() == self.patter_match_name: + # self.passthrough_checkbox.setChecked(False) + # self.disable_audio_checkbox.setChecked(False) + # self.patter_match_checkbox.setChecked(True) self.scroll_area.setEnabled(True) self.add_button.setEnabled(True)