Add episode queueing picker and configurable mpv video output
Activating an episode now opens a scope picker (episode / season / whole show) and plays the chosen queue back-to-back in one mpv instance, with only the first item honoring its resume position. A new mpv `vo` driver setting (CLI flag, env var, config file, and settings TUI) lets users opt into terminal-based vos like sixel/kitty/tct, which auto-enable mpv's terminal input so playback keys still work. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
1 parent
f0ebb4b9a4
commit
093b13f03e
9 files changed
+661
-72
No files matched your search
+18
-2
@@ -20,14 +20,16 @@ enum Field {
|
||||
Password,
|
||||
AudioLang,
|
||||
SubtitleLang,
|
||||
VideoOutput,
|
||||
}
|
||||
|
||||
const FIELDS: [Field; 5] = [
|
||||
const FIELDS: [Field; 6] = [
|
||||
Field::Server,
|
||||
Field::User,
|
||||
Field::Password,
|
||||
Field::AudioLang,
|
||||
Field::SubtitleLang,
|
||||
Field::VideoOutput,
|
||||
];
|
||||
|
||||
impl Field {
|
||||
@@ -47,6 +49,7 @@ struct Form {
|
||||
password: String,
|
||||
audio_lang: String,
|
||||
subtitle_lang: String,
|
||||
video_output: String,
|
||||
focus: Field,
|
||||
error: Option<String>,
|
||||
}
|
||||
@@ -59,6 +62,7 @@ impl Form {
|
||||
password: cfg.password.clone(),
|
||||
audio_lang: cfg.audio_lang.clone().unwrap_or_default(),
|
||||
subtitle_lang: cfg.subtitle_lang.clone().unwrap_or_default(),
|
||||
video_output: cfg.video_output.clone().unwrap_or_default(),
|
||||
focus: Field::Server,
|
||||
error: None,
|
||||
}
|
||||
@@ -71,6 +75,7 @@ impl Form {
|
||||
Field::Password => &mut self.password,
|
||||
Field::AudioLang => &mut self.audio_lang,
|
||||
Field::SubtitleLang => &mut self.subtitle_lang,
|
||||
Field::VideoOutput => &mut self.video_output,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,6 +144,7 @@ async fn apply(form: &mut Form, app: &mut App) -> Result<()> {
|
||||
password: form.password.clone(),
|
||||
audio_lang: trim_to_opt(&form.audio_lang),
|
||||
subtitle_lang: trim_to_opt(&form.subtitle_lang),
|
||||
video_output: trim_to_opt(&form.video_output),
|
||||
};
|
||||
|
||||
let creds_changed = new_cfg.server != app.config.server
|
||||
@@ -208,6 +214,7 @@ fn draw(f: &mut ratatui::Frame, form: &Form) {
|
||||
Constraint::Length(3), // password
|
||||
Constraint::Length(3), // audio lang
|
||||
Constraint::Length(3), // subtitle lang
|
||||
Constraint::Length(3), // video output
|
||||
Constraint::Min(1), // error / help
|
||||
])
|
||||
.split(inner);
|
||||
@@ -253,6 +260,15 @@ fn draw(f: &mut ratatui::Frame, form: &Form) {
|
||||
),
|
||||
rows[5],
|
||||
);
|
||||
f.render_widget(
|
||||
field_widget(
|
||||
"Video output (gpu/sixel/kitty/drm/tct, blank=mpv default)",
|
||||
&form.video_output,
|
||||
form.focus == Field::VideoOutput,
|
||||
false,
|
||||
),
|
||||
rows[6],
|
||||
);
|
||||
|
||||
let footer = if let Some(err) = &form.error {
|
||||
Line::from(Span::styled(
|
||||
@@ -265,5 +281,5 @@ fn draw(f: &mut ratatui::Frame, form: &Form) {
|
||||
Style::default().fg(Color::DarkGray),
|
||||
))
|
||||
};
|
||||
f.render_widget(Paragraph::new(footer), rows[6]);
|
||||
f.render_widget(Paragraph::new(footer), rows[7]);
|
||||
}
|
||||
Reference in new issue
Block a user