feat: switch between provider sessions without restarting
This commit is contained in:
+76
-14
@@ -157,7 +157,7 @@ use ratatui::{
|
||||
use video_state::{CollectionKind, WatchStatus};
|
||||
use youtube::{Job, PAGE_SIZE, Page, PlayerLaunch, Video};
|
||||
|
||||
#[derive(Parser)]
|
||||
#[derive(Clone, Parser)]
|
||||
#[command(
|
||||
version,
|
||||
about = "Browse YouTube or Miruro and open selected videos in Terebi",
|
||||
@@ -611,7 +611,7 @@ impl KeyHints {
|
||||
(
|
||||
Context::Normal,
|
||||
format!(
|
||||
"NORMAL · {}/{} select · {} play · {status} · {}/{} later · {}/{} saved · {} search · {} help · {} quit",
|
||||
"NORMAL · {}/{} select · {} play · {status} · {}/{} later · {}/{} saved · {} search · {} provider · {} help · {} quit",
|
||||
key(Action::VideoNext),
|
||||
key(Action::VideoPrevious),
|
||||
key(Action::VideoPlay),
|
||||
@@ -620,6 +620,7 @@ impl KeyHints {
|
||||
key(Action::SavedVideoSave),
|
||||
key(Action::SavedVideoBrowse),
|
||||
key(Action::SearchEdit),
|
||||
key(Action::ProviderChoose),
|
||||
key(Action::Help),
|
||||
key(Action::Quit)
|
||||
),
|
||||
@@ -651,7 +652,7 @@ impl KeyHints {
|
||||
(
|
||||
Context::CollectionNormal,
|
||||
format!(
|
||||
"NORMAL · {}/{} select · {} play · {status} · {}/{} later · {}/{} saved · {} remove selected · {} remove list · {} search · {} help · {} quit",
|
||||
"NORMAL · {}/{} select · {} play · {status} · {}/{} later · {}/{} saved · {} remove selected · {} remove list · {} search · {} provider · {} help · {} quit",
|
||||
key(Action::VideoNext),
|
||||
key(Action::VideoPrevious),
|
||||
key(Action::VideoPlay),
|
||||
@@ -662,6 +663,7 @@ impl KeyHints {
|
||||
key(Action::CollectionRemoveSelected),
|
||||
key(Action::CollectionRemoveBulk),
|
||||
key(Action::SearchEdit),
|
||||
key(Action::ProviderChoose),
|
||||
key(Action::Help),
|
||||
key(Action::Quit)
|
||||
),
|
||||
@@ -3558,7 +3560,7 @@ impl App {
|
||||
);
|
||||
}
|
||||
|
||||
fn run(mut self, terminal: &mut DefaultTerminal) -> io::Result<()> {
|
||||
fn run(&mut self, terminal: &mut DefaultTerminal, initial: bool) -> io::Result<Option<bool>> {
|
||||
struct RestoreTerminalInput;
|
||||
impl Drop for RestoreTerminalInput {
|
||||
fn drop(&mut self) {
|
||||
@@ -3576,7 +3578,7 @@ impl App {
|
||||
SetCursorStyle::SteadyBlock
|
||||
)?;
|
||||
self.thumbnail.query_terminal();
|
||||
if !self.views[self.view_index].query.trim().is_empty() {
|
||||
if initial && !self.views[self.view_index].query.trim().is_empty() {
|
||||
self.search();
|
||||
}
|
||||
let started = Instant::now();
|
||||
@@ -3587,8 +3589,13 @@ impl App {
|
||||
if event::poll(refresh)? {
|
||||
match event::read()? {
|
||||
Event::Key(key) if key.kind != KeyEventKind::Release => {
|
||||
if self.config.keys.resolve(self.key_context(), key)
|
||||
== Some(Action::ProviderChoose)
|
||||
{
|
||||
return choose_provider(terminal, &self.config.keys, Some(false));
|
||||
}
|
||||
if self.key(key) {
|
||||
return Ok(());
|
||||
return Ok(None);
|
||||
}
|
||||
}
|
||||
Event::Paste(text) => self.paste(&text),
|
||||
@@ -3694,15 +3701,17 @@ fn provider_selection(
|
||||
fn choose_provider(
|
||||
terminal: &mut DefaultTerminal,
|
||||
bindings: &keys::Bindings,
|
||||
current: Option<bool>,
|
||||
) -> io::Result<Option<bool>> {
|
||||
let mut selected = 0;
|
||||
let mut selected = usize::from(current.unwrap_or(false));
|
||||
let mut selection = ListState::default();
|
||||
let hint = format!(
|
||||
"{}/{} select · {} open · {} quit",
|
||||
"{}/{} select · {} open · {} {}",
|
||||
bindings.label(Action::SelectorNext),
|
||||
bindings.label(Action::SelectorPrevious),
|
||||
bindings.label(Action::SelectorOpen),
|
||||
bindings.label(Action::SelectorClose),
|
||||
if current.is_some() { "cancel" } else { "quit" },
|
||||
);
|
||||
let providers = List::new(PROVIDERS.map(|(name, _)| name))
|
||||
.highlight_style(ui::SELECTED)
|
||||
@@ -3740,6 +3749,9 @@ fn choose_provider(
|
||||
.resolve(Context::Normal, key)
|
||||
.filter(|action| *action == Action::Quit)
|
||||
});
|
||||
if current.is_some() && action == Some(Action::SelectorClose) {
|
||||
return Ok(current);
|
||||
}
|
||||
if let std::ops::ControlFlow::Break(provider) =
|
||||
provider_selection(&mut selected, action)
|
||||
{
|
||||
@@ -3761,16 +3773,66 @@ fn main() -> io::Result<()> {
|
||||
let config = config::load(&config_path)?;
|
||||
ratatui::run(|terminal| {
|
||||
if !options.miruro {
|
||||
let Some(miruro) = choose_provider(terminal, &config.keys)? else {
|
||||
let Some(miruro) = choose_provider(terminal, &config.keys, None)? else {
|
||||
return Ok(());
|
||||
};
|
||||
options.miruro = miruro;
|
||||
}
|
||||
let state = video_state::State::open(&config_path)?;
|
||||
if options.miruro {
|
||||
miruro_ui::run(terminal, options, config_path, config, state)
|
||||
} else {
|
||||
App::with_state(options, config_path, config, state).run(terminal)
|
||||
let mut youtube: Option<App> = None;
|
||||
let mut miruro: Option<miruro_ui::Browser> = None;
|
||||
let mut initial = true;
|
||||
loop {
|
||||
let next = if options.miruro {
|
||||
if miruro.is_none() {
|
||||
miruro = Some(miruro_ui::Browser::new(
|
||||
options.clone(),
|
||||
config_path.clone(),
|
||||
config::load(&config_path)?,
|
||||
video_state::State::open(&config_path)?,
|
||||
));
|
||||
}
|
||||
miruro.as_mut().unwrap().run(terminal)?
|
||||
} else {
|
||||
let first = youtube.is_none();
|
||||
if first {
|
||||
youtube = Some(App::with_state(
|
||||
options.clone(),
|
||||
config_path.clone(),
|
||||
config::load(&config_path)?,
|
||||
video_state::State::open(&config_path)?,
|
||||
));
|
||||
}
|
||||
youtube.as_mut().unwrap().run(terminal, first)?
|
||||
};
|
||||
let Some(next) = next else {
|
||||
return Ok(());
|
||||
};
|
||||
if initial {
|
||||
options.query = None;
|
||||
initial = false;
|
||||
}
|
||||
if next != options.miruro {
|
||||
if next && miruro.is_none() {
|
||||
miruro = Some(miruro_ui::Browser::new(
|
||||
options.clone(),
|
||||
config_path.clone(),
|
||||
config::load(&config_path)?,
|
||||
video_state::State::open(&config_path)?,
|
||||
));
|
||||
} else if !next && youtube.is_none() {
|
||||
youtube = Some(App::with_state(
|
||||
options.clone(),
|
||||
config_path.clone(),
|
||||
config::load(&config_path)?,
|
||||
video_state::State::open(&config_path)?,
|
||||
));
|
||||
}
|
||||
std::mem::swap(
|
||||
&mut youtube.as_mut().unwrap().video_state,
|
||||
&mut miruro.as_mut().unwrap().state,
|
||||
);
|
||||
}
|
||||
options.miruro = next;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user