refactor: delegate Miruro playback resolution to Terebi
This commit is contained in:
+16
-47
@@ -265,7 +265,7 @@ impl Screen {
|
||||
self.rows = videos.iter().map(|video| {
|
||||
let identity = Identity::from_key(&video.id).expect("provider-scoped collection");
|
||||
let title = safe(&video.title);
|
||||
let metadata = format!("{title}\n\nEpisode {} · Miruro ID {}\n\nStored offline episode metadata. Enter resolves a fresh direct Sun source; no catalog slug is reconstructed from this title.", identity.episode, identity.media_id);
|
||||
let metadata = format!("{title}\n\nEpisode {} · Miruro ID {}\n\nStored offline episode metadata. Enter sends the episode URL to Terebi, which resolves sources and playback metadata.", identity.episode, identity.media_id);
|
||||
DisplayRow { key: Some(video.id.clone()), title, details: video.publication_date.as_deref().map(safe).unwrap_or_default(), metadata }
|
||||
}).collect();
|
||||
}
|
||||
@@ -317,7 +317,6 @@ struct Browser {
|
||||
enum Intent {
|
||||
Catalog,
|
||||
Series(String),
|
||||
Source(String),
|
||||
}
|
||||
|
||||
enum LibraryModal {
|
||||
@@ -526,12 +525,20 @@ impl Browser {
|
||||
self.push(Screen::new(Content::Series { media, data: None }));
|
||||
self.load_series();
|
||||
} else if let Some(video) = self.screen().selected_video() {
|
||||
if Identity::from_key(&video.id).is_err() {
|
||||
return;
|
||||
self.invalidate();
|
||||
self.screen_mut().error = None;
|
||||
let result = self.state.progress_file(&video).and_then(|progress_file| {
|
||||
// Dropping the launcher cancels only its CLI child, not the native player.
|
||||
self.player = None;
|
||||
PlayerLaunch::start(&video.id, &self.options.player, &progress_file)
|
||||
});
|
||||
match result {
|
||||
Ok(player) => {
|
||||
self.player = Some(player);
|
||||
self.status = format!("Opening {} in Terebi…", safe(&video.title));
|
||||
}
|
||||
Err(error) => self.fail(error),
|
||||
}
|
||||
let id = video.id.clone();
|
||||
self.request(Request::Source(video), Intent::Source(id));
|
||||
self.status = "Resolving fresh direct Sun source…".into();
|
||||
}
|
||||
}
|
||||
fn fail(&mut self, error: impl std::fmt::Display) {
|
||||
@@ -595,34 +602,6 @@ impl Browser {
|
||||
self.status.clear();
|
||||
}
|
||||
}
|
||||
(Intent::Source(id), Ok(Response::Source(video, source))) => {
|
||||
if video.id != id || self.screen().selected_key() != Some(id.as_str()) {
|
||||
return;
|
||||
}
|
||||
if source.identity.key() != id {
|
||||
self.fail(io::Error::other(
|
||||
"Miruro source identity did not match the selected episode",
|
||||
));
|
||||
return;
|
||||
}
|
||||
match self.state.miruro_session(&video, &source).and_then(
|
||||
|(source_file, progress_file)| {
|
||||
// Dropping the launcher cancels only its CLI child, not the native player.
|
||||
self.player = None;
|
||||
PlayerLaunch::start_source(
|
||||
&source_file,
|
||||
&self.options.player,
|
||||
&progress_file,
|
||||
)
|
||||
},
|
||||
) {
|
||||
Ok(player) => {
|
||||
self.player = Some(player);
|
||||
self.status = format!("Opening {} in Terebi…", safe(&video.title));
|
||||
}
|
||||
Err(error) => self.fail(error),
|
||||
}
|
||||
}
|
||||
(_, Err(error)) => self.fail(error),
|
||||
_ => self.fail(io::Error::other(
|
||||
"Miruro response did not match the current request",
|
||||
@@ -910,12 +889,6 @@ impl Browser {
|
||||
screen.clamp();
|
||||
screen.rebuild_display();
|
||||
}
|
||||
// Progress may remove the originating currently-watching row during resolution.
|
||||
if let Some(Intent::Source(id)) = &self.intent
|
||||
&& self.screen().selected_key() != Some(id.as_str())
|
||||
{
|
||||
self.invalidate();
|
||||
}
|
||||
}
|
||||
fn save(&mut self, kind: CollectionKind) {
|
||||
let Some(video) = self.screen().selected_video() else {
|
||||
@@ -1064,10 +1037,6 @@ impl Browser {
|
||||
}
|
||||
}
|
||||
fn select(&mut self, action: Action) {
|
||||
if matches!(self.intent, Some(Intent::Source(_))) {
|
||||
self.invalidate();
|
||||
self.status.clear();
|
||||
}
|
||||
let screen = self.screen_mut();
|
||||
let last = screen.len().saturating_sub(1);
|
||||
let selected = screen.selection.selected().unwrap_or(0);
|
||||
@@ -1292,7 +1261,7 @@ impl Browser {
|
||||
) {
|
||||
"Open series"
|
||||
} else {
|
||||
"Play episode (fresh source)"
|
||||
"Play episode in Terebi"
|
||||
},
|
||||
),
|
||||
(Action::VideoNext, "Next title/episode"),
|
||||
@@ -1804,7 +1773,7 @@ impl Browser {
|
||||
let mut lines = vec![
|
||||
Line::from("Miruro catalog → series → actual episodes").bold(),
|
||||
Line::from(
|
||||
"No provider/track fallback; fresh direct ssub/Sun HLS + VTT on every play.",
|
||||
"Terebi resolves episode URLs, sources, subtitles and playback metadata.",
|
||||
),
|
||||
Line::from("✓ is acknowledged playback progress, never CLI completion."),
|
||||
Line::default(),
|
||||
|
||||
Reference in New Issue
Block a user