aboutsummaryrefslogtreecommitdiff
path: root/src/app.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/app.rs')
-rw-r--r--src/app.rs157
1 files changed, 91 insertions, 66 deletions
diff --git a/src/app.rs b/src/app.rs
index 7aa5abd..066980c 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -12,7 +12,7 @@ use crate::{
subtitle_view::{SubtitleView, SubtitleViewMsg, SubtitleViewOutput},
tracks::{SUBTITLE_TRACKS, StreamIndex, SubtitleCue},
transcript::{Transcript, TranscriptMsg, TranscriptOutput},
- util::OptionTracker,
+ util::{OptionTracker, Tracker},
};
pub struct App {
@@ -26,13 +26,14 @@ pub struct App {
subtitle_selection_dialog: Controller<SubtitleSelectionDialog>,
primary_stream_ix: Option<StreamIndex>,
- primary_last_cue_ix: OptionTracker<usize>,
+ primary_cue: Tracker<Option<String>>,
+ primary_last_cue_ix: Tracker<Option<usize>>,
+ secondary_cue: Tracker<Option<String>>,
secondary_stream_ix: Option<StreamIndex>,
- secondary_last_cue_ix: OptionTracker<usize>,
+ secondary_last_cue_ix: Tracker<Option<usize>>,
// for auto-pausing
autopaused: bool,
- primary_cue_active: bool,
hovering_primary_cue: bool,
}
@@ -162,12 +163,13 @@ impl SimpleComponent for App {
subtitle_selection_dialog,
primary_stream_ix: None,
- primary_last_cue_ix: OptionTracker::new(None),
+ primary_cue: Tracker::new(None),
+ primary_last_cue_ix: Tracker::new(None),
secondary_stream_ix: None,
- secondary_last_cue_ix: OptionTracker::new(None),
+ secondary_cue: Tracker::new(None),
+ secondary_last_cue_ix: Tracker::new(None),
autopaused: false,
- primary_cue_active: false,
hovering_primary_cue: false,
};
@@ -177,9 +179,6 @@ impl SimpleComponent for App {
}
fn update(&mut self, message: Self::Input, _sender: ComponentSender<Self>) {
- self.primary_last_cue_ix.reset();
- self.secondary_last_cue_ix.reset();
-
match message {
AppMsg::NewCue(stream_index, cue) => {
self.transcript
@@ -203,20 +202,41 @@ impl SimpleComponent for App {
}
AppMsg::PositionUpdate(pos) => {
if let Some(stream_ix) = self.primary_stream_ix {
- let cue =
- Self::get_cue_and_update_ix(stream_ix, pos, &mut self.primary_last_cue_ix);
- let cue_is_some = cue.is_some();
-
- // beginning of new subtitle
- if self.primary_last_cue_ix.is_dirty()
- || (!self.primary_cue_active && cue_is_some)
- {
+ // sometimes we get a few position update messages after
+ // auto-pausing; this prevents us from immediately un-autopausing
+ // again
+ if self.autopaused {
+ return;
+ }
+
+ let cue_was_some = self.primary_cue.get().is_some();
+
+ Self::update_cue(
+ stream_ix,
+ pos,
+ &mut self.primary_cue,
+ &mut self.primary_last_cue_ix,
+ );
+
+ if self.primary_cue.is_dirty() {
+ // last cue just ended -> auto-pause
+ if cue_was_some && self.hovering_primary_cue {
+ self.player.sender().send(PlayerMsg::Pause).unwrap();
+ self.autopaused = true;
+ return;
+ }
+
self.subtitle_view
.sender()
- .send(SubtitleViewMsg::SetPrimaryCue(cue))
+ .send(SubtitleViewMsg::SetPrimaryCue(
+ self.primary_cue.get().clone(),
+ ))
.unwrap();
- self.primary_cue_active = cue_is_some;
+ self.primary_cue.reset();
+ }
+
+ if self.primary_last_cue_ix.is_dirty() {
if let Some(ix) = self.primary_last_cue_ix.get() {
self.transcript
.sender()
@@ -226,33 +246,24 @@ impl SimpleComponent for App {
self.primary_last_cue_ix.reset();
}
-
- // end of current subtitle
- if self.primary_cue_active && !cue_is_some && !self.autopaused {
- if self.hovering_primary_cue {
- self.player.sender().send(PlayerMsg::Pause).unwrap();
- self.autopaused = true;
- } else {
- self.subtitle_view
- .sender()
- .send(SubtitleViewMsg::SetPrimaryCue(None))
- .unwrap();
- self.primary_cue_active = false;
- }
- }
}
if let Some(stream_ix) = self.secondary_stream_ix {
- if !self.autopaused {
+ Self::update_cue(
+ stream_ix,
+ pos,
+ &mut self.secondary_cue,
+ &mut self.secondary_last_cue_ix,
+ );
+
+ if !self.autopaused && self.secondary_cue.is_dirty() {
self.subtitle_view
.sender()
.send(SubtitleViewMsg::SetSecondaryCue(
- Self::get_cue_and_update_ix(
- stream_ix,
- pos,
- &mut self.secondary_last_cue_ix,
- ),
+ self.secondary_cue.get().clone(),
))
.unwrap();
+
+ self.secondary_cue.reset();
}
}
}
@@ -302,50 +313,64 @@ impl SimpleComponent for App {
}
impl App {
- fn get_cue_and_update_ix(
+ fn update_cue(
stream_ix: StreamIndex,
position: gst::ClockTime,
- last_cue_ix: &mut OptionTracker<usize>,
- ) -> Option<String> {
+ cue: &mut Tracker<Option<String>>,
+ last_cue_ix: &mut Tracker<Option<usize>>,
+ ) {
let lock = SUBTITLE_TRACKS.read();
- let track = lock.get(&stream_ix)?;
+ let track = lock.get(&stream_ix).unwrap();
// try to find current cue quickly (should usually succeed during playback)
if let Some(ix) = last_cue_ix.get() {
- let last_cue = track.cues.get(*ix)?;
+ let last_cue = track.cues.get(*ix).unwrap();
if last_cue.start <= position && position <= last_cue.end {
- return Some(last_cue.text.clone());
- }
- let next_cue = track.cues.get(ix + 1)?;
- if last_cue.end < position && position < next_cue.start {
- return None;
- }
- if next_cue.start <= position && position <= next_cue.end {
- last_cue_ix.set(Some(ix + 1));
- return Some(next_cue.text.clone());
+ // still at current cue
+ return;
+ } else if let Some(next_cue) = track.cues.get(ix + 1) {
+ if last_cue.end < position && position < next_cue.start {
+ // strictly between cues
+ cue.set(None);
+ return;
+ }
+ if next_cue.start <= position && position <= next_cue.end {
+ // already in next cue (this happens when one cue immediately
+ // follows the previous one)
+ cue.set(Some(next_cue.text.clone()));
+ last_cue_ix.set(Some(ix + 1));
+ return;
+ }
}
}
// if we are before the first subtitle, no need to look further
- if position < track.cues.first()?.start {
+ if track.cues.is_empty() || position < track.cues.first().unwrap().start {
+ cue.set(None);
last_cue_ix.set(None);
- return None;
+ return;
}
// otherwise, search the whole track (e.g. after seeking)
- let (ix, cue) = track
+ match track
.cues
.iter()
.enumerate()
.rev()
- .find(|(_ix, cue)| cue.start <= position)?;
-
- last_cue_ix.set(Some(ix));
-
- if position <= cue.end {
- Some(cue.text.clone())
- } else {
- None
- }
+ .find(|(_ix, cue)| cue.start <= position)
+ {
+ Some((ix, new_cue)) => {
+ last_cue_ix.set(Some(ix));
+ if position <= new_cue.end {
+ cue.set(Some(new_cue.text.clone()));
+ } else {
+ cue.set(None);
+ }
+ }
+ None => {
+ cue.set(None);
+ last_cue_ix.set(None);
+ }
+ };
}
}