fix: preserve video selection order for playback

This commit is contained in:
2026-10-25 12:06:13 +01:00
parent 090f077eeb
commit ae87bb8b36
6 changed files with 75 additions and 60 deletions
+4 -4
View File
@@ -119,8 +119,8 @@ actions! {
ViewTabNext, "view.tab.next", "Select the next view tab", VIEW, ["tab", "ctrl+tab"];
ViewTabPrevious, "view.tab.previous", "Select the previous view tab", VIEW, ["shift+tab"];
ViewRefresh, "view.refresh", "Refresh the current view and configuration", VIEW, ["r"];
VideoPlay, "video.play", "Play checked videos in displayed order, or the selected video", VIEW, ["enter"];
VideoEnqueue, "video.enqueue", "Append checked videos in displayed order, or the selected video, to Terebi's queue", VIEW, ["ctrl+enter"];
VideoPlay, "video.play", "Play checked videos in check order, or the selected video", VIEW, ["enter"];
VideoEnqueue, "video.enqueue", "Append checked videos in check order, or the selected video, to Terebi's queue", VIEW, ["ctrl+enter"];
VideoOpen, "video.open", "Open the selected YouTube video in the default browser", VIEW, ["o"];
VideoCopyUrl, "video.copy_url", "Copy the selected video's URL to the terminal clipboard", VIEW, ["y"];
VideoNext, "video.select.next", "Select the next video", VIEW, ["j", "down", "ctrl+j"];
@@ -486,11 +486,11 @@ impl Bindings {
(&[VideoNext, VideoPrevious], "Select next / previous video"),
(
&[VideoPlay],
"Play checked videos in displayed order, or the selected video",
"Play checked videos in check order, or the selected video",
),
(
&[VideoEnqueue],
"Append checked videos, or the selected video, to Terebi's queue",
"Append checked videos in check order, or the selected video, to Terebi's queue",
),
(
&[VideoToggle],
+12 -8
View File
File diff suppressed because one or more lines are too long
+26 -21
View File
@@ -93,7 +93,7 @@ struct DisplayRow {
struct Screen {
content: Content,
selection: ListState,
checked: BTreeSet<String>,
checked: Vec<String>,
description_scroll: u16,
error: Option<String>,
title: String,
@@ -106,7 +106,7 @@ impl Screen {
let mut screen = Self {
content,
selection: ListState::default(),
checked: BTreeSet::new(),
checked: Vec::new(),
description_scroll: 0,
error: None,
title: String::new(),
@@ -163,10 +163,13 @@ impl Screen {
}
fn toggle_checked(&mut self) {
if self.playable()
&& let Some(id) = self.selected_key().map(str::to_owned)
&& let Some(id) = self.selected_key()
{
if !self.checked.remove(&id) {
self.checked.insert(id);
if let Some(index) = self.checked.iter().position(|checked| checked == id) {
self.checked.remove(index);
} else {
let id = id.to_owned();
self.checked.push(id);
}
}
}
@@ -174,22 +177,24 @@ impl Screen {
if self.checked.is_empty() {
return self.selected_video().into_iter().collect();
}
match &self.content {
Content::Series {
media,
data: Some(data),
} => data
.iter()
.filter(|episode| self.checked.contains(&episode.identity.key()))
.map(|episode| episode.snapshot(media))
.collect(),
Content::Collection { videos, .. } => videos
.iter()
.filter(|video| self.checked.contains(&video.id))
.cloned()
.collect(),
_ => Vec::new(),
}
// ponytail: scan rows per check; index IDs if very large lists need it.
self.checked
.iter()
.filter_map(|id| {
let index = self
.rows
.iter()
.position(|row| row.key.as_ref() == Some(id))?;
match &self.content {
Content::Series {
media,
data: Some(data),
} => data.get(index).map(|episode| episode.snapshot(media)),
Content::Collection { videos, .. } => videos.get(index).cloned(),
_ => None,
}
})
.collect()
}
fn selected_key(&self) -> Option<&str> {
self.selection