Add playlist filter and show video durations in selection dialog

Introduces a filter input to the PlaylistSelectionDialog for searching videos by title and displays video durations next to each entry. Updates English translations to support the new filter placeholder and analysis status message.
This commit is contained in:
oop7
2026-01-17 21:43:01 +02:00
parent 2b7cce1333
commit ffb938b181
2 changed files with 50 additions and 3 deletions
+2
View File
@@ -92,6 +92,7 @@
"sponsorblock_description": "Select which types of video segments to automatically remove during download.\nSponsorBlock uses community-submitted data to identify these segments.", "sponsorblock_description": "Select which types of video segments to automatically remove during download.\nSponsorBlock uses community-submitted data to identify these segments.",
"select_subtitles": "Select Subtitles", "select_subtitles": "Select Subtitles",
"filter_languages_placeholder": "Filter languages (e.g., en, es)...", "filter_languages_placeholder": "Filter languages (e.g., en, es)...",
"filter_playlist_placeholder": "Filter videos...",
"no_subtitles_available": "No subtitles available", "no_subtitles_available": "No subtitles available",
"matching": "matching" "matching": "matching"
}, },
@@ -336,6 +337,7 @@
"analyzing_updating_table": "Analyzing (95%)... Updating format table", "analyzing_updating_table": "Analyzing (95%)... Updating format table",
"analysis_complete": "Analysis complete!", "analysis_complete": "Analysis complete!",
"analyzing_extracting_ytdlp": "Analyzing (30%)... Extracting info", "analyzing_extracting_ytdlp": "Analyzing (30%)... Extracting info",
"analyzing_fetching_first_video": "Analyzing... Fetching formats for first video",
"analyzing_processing_data": "Analyzing (60%)... Processing data", "analyzing_processing_data": "Analyzing (60%)... Processing data",
"analyzing_processing_formats_ytdlp": "Analyzing (75%)... Processing formats", "analyzing_processing_formats_ytdlp": "Analyzing (75%)... Processing formats",
"analyzing_loading_thumbnail_ytdlp": "Analyzing (85%)... Loading thumbnail", "analyzing_loading_thumbnail_ytdlp": "Analyzing (85%)... Loading thumbnail",
@@ -208,6 +208,27 @@ class PlaylistSelectionDialog(QDialog):
# Main layout # Main layout
main_layout = QVBoxLayout(self) main_layout = QVBoxLayout(self)
# Filter Input
self.filter_input = QLineEdit()
self.filter_input.setPlaceholderText(_("dialogs.filter_playlist_placeholder"))
self.filter_input.textChanged.connect(self.filter_list)
self.filter_input.setStyleSheet(
"""
QLineEdit {
background-color: #363636;
border: 2px solid #3d3d3d;
border-radius: 4px;
padding: 5px;
min-height: 30px;
color: white;
}
QLineEdit:focus {
border-color: #ff0000;
}
"""
)
main_layout.addWidget(self.filter_input)
# Top buttons (Select/Deselect All) # Top buttons (Select/Deselect All)
button_layout = QHBoxLayout() button_layout = QHBoxLayout()
select_all_btn = QPushButton(_("buttons.select_all")) select_all_btn = QPushButton(_("buttons.select_all"))
@@ -339,6 +360,13 @@ class PlaylistSelectionDialog(QDialog):
pass # Ignore invalid numbers pass # Ignore invalid numbers
return selected_indices return selected_indices
def filter_list(self, text: str) -> None:
"""Filter the list of checkboxes based on title."""
text = text.lower()
for checkbox in self.checkboxes:
title = (checkbox.property("full_title") or "").lower()
checkbox.setVisible(text in title)
def _populate_list(self, previously_selected_string) -> None: def _populate_list(self, previously_selected_string) -> None:
"""Populates the scroll area with checkboxes for each video.""" """Populates the scroll area with checkboxes for each video."""
selected_indices = self._parse_selection_string(previously_selected_string) selected_indices = self._parse_selection_string(previously_selected_string)
@@ -356,12 +384,29 @@ class PlaylistSelectionDialog(QDialog):
video_index = index + 1 # yt-dlp uses 1-based indexing video_index = index + 1 # yt-dlp uses 1-based indexing
title = entry.get("title", f"Video {video_index}") title = entry.get("title", f"Video {video_index}")
# Shorten title if too long
display_title = (title[:70] + "...") if len(title) > 73 else title # Format duration
duration = entry.get("duration")
duration_str = ""
if duration:
try:
m, s = divmod(int(duration), 60)
h, m = divmod(m, 60)
if h > 0:
duration_str = f" [{h}:{m:02d}:{s:02d}]"
else:
duration_str = f" [{m:02d}:{s:02d}]"
except (ValueError, TypeError):
pass
# Shorten title if too long but keep enough space for duration
max_len = 65
display_title = (title[:max_len] + "...") if len(title) > max_len + 3 else title
checkbox = QCheckBox(f"{video_index}. {display_title}") checkbox = QCheckBox(f"{video_index}. {display_title}{duration_str}")
checkbox.setChecked(video_index in selected_indices) checkbox.setChecked(video_index in selected_indices)
checkbox.setProperty("video_index", video_index) # Store index checkbox.setProperty("video_index", video_index) # Store index
checkbox.setProperty("full_title", title) # Store full title for filtering
checkbox.setStyleSheet( checkbox.setStyleSheet(
""" """
QCheckBox { QCheckBox {