mirror of
https://github.com/narrrl/proton-stream.git
synced 2026-11-04 00:47:00 +01:00
feat(core,app,android,ios): keep a show in Continue watching after an episode ends
Continue watching listed only part-watched episodes, so finishing one -
the most ordinary moment to want the next - dropped the show from the
shelf. Title::continue_with now reads the episode touched last: a
part-watched one is resumed, a finished one offers the episode after it
("Next: S01E04"), and one reset to the start (what leaving the shelf
does) keeps the title off. A few seconds of an episode are passed over.
The phones computed their own shelf from episode records. The bridge now
exports the engine's choice as TitleRecord.continue_index, and Play on a
title lands there on every client.
Undo on the phones re-saved a watch state with a fresh time, which both
reordered the shelf and could not express "never played". A new
restore_watch_state puts the state back as it was read.
This commit is contained in:
1 parent
c6b0457c4d
commit
a306d02cf1
15 files changed
+225
-68
No files matched your search
@@ -509,6 +509,11 @@ pub struct TitleRecord {
|
||||
/// Every title of its franchise, in release order, its own key included;
|
||||
/// empty for a title that stands alone.
|
||||
pub franchise: Vec<String>,
|
||||
/// Where Continue watching picks this title up, as an index into its
|
||||
/// episodes in display order: the part-watched one, or the one after the
|
||||
/// episode finished last. `None` keeps it off the shelf. See
|
||||
/// `pstr_core::library::Title::continue_with`.
|
||||
pub continue_index: Option<u32>,
|
||||
}
|
||||
|
||||
/// Playback preferences that outlive one file, one title and one launch.
|
||||
@@ -1599,6 +1604,37 @@ impl AndroidEngine {
|
||||
.map(|state| state.map(watch_state_record))
|
||||
}
|
||||
|
||||
/// Put one file's watch state back exactly as [`Self::watch_state`] read
|
||||
/// it — what Undo does. Unlike [`Self::save_watch_state`] it keeps the
|
||||
/// original time, so an undone change sorts where it did before. `None`,
|
||||
/// a file that had never been played, becomes a reset older than anything,
|
||||
/// which every later state outranks.
|
||||
pub fn restore_watch_state(
|
||||
&self,
|
||||
share_id: String,
|
||||
link_id: String,
|
||||
state: Option<WatchStateRecord>,
|
||||
) -> Result<(), BridgeError> {
|
||||
let state = state.map_or(
|
||||
WatchState {
|
||||
position_secs: 0.0,
|
||||
duration_secs: None,
|
||||
watched: false,
|
||||
updated_at: 0,
|
||||
},
|
||||
|state| WatchState {
|
||||
position_secs: state.position_secs,
|
||||
duration_secs: state.duration_secs,
|
||||
watched: state.watched,
|
||||
updated_at: state.updated_at,
|
||||
},
|
||||
);
|
||||
self.catalog
|
||||
.lock()
|
||||
.set_watch_state(&share_id, &link_id, &state)
|
||||
.map_err(BridgeError::from_display)
|
||||
}
|
||||
|
||||
pub fn save_watch_state(
|
||||
&self,
|
||||
share_id: String,
|
||||
@@ -3203,6 +3239,10 @@ fn title_record(
|
||||
next_episode: None,
|
||||
next_airing_at: None,
|
||||
franchise: Vec::new(),
|
||||
continue_index: title.continue_with().and_then(|episode| {
|
||||
let at = title.position_of(&episode.node.share_id, &episode.node.link_id)?;
|
||||
u32::try_from(at).ok()
|
||||
}),
|
||||
seasons: title
|
||||
.seasons
|
||||
.iter()
|
||||
|
||||
Reference in new issue
Block a user