use mineral_protocol::PlaybackOrigin;
use mineral_task::{ChannelFetchKind, Priority, TaskKind};
use super::{Advance, adopt_queued, decide_advance};
use crate::player::PlayerCore;
use crate::queue::advance_next;
use crate::state::State;
pub(crate) fn check_advance(player: &PlayerCore) {
let snap = player.audio_snapshot();
if snap.track_finished_seq <= player.last_seen_finished_seq() {
return;
}
player.set_last_seen_finished_seq(snap.track_finished_seq);
let (old, has_queued) =
player.with_state(|st| (st.current_song.clone(), st.prefetch.is_armed()));
let boundary_song = old.as_ref().map(|s| s.id.clone());
if let Some(old) = old {
let listen_ms = old.duration_ms.unwrap_or(snap.position_ms);
player.spawn_on_played(old.id.clone(), mineral_stats::FinishReason::Eof, listen_ms);
player
.notify()
.track_finished(&old, mineral_protocol::FinishReason::Eof);
}
let action = decide_advance( true, snap.playing, has_queued);
mineral_log::info!(
target: "player",
action = match action {
Advance::Adopt => "adopt",
Advance::Fallback => "fallback",
Advance::None => "none",
},
playing = snap.playing,
has_queued,
finished_seq = snap.track_finished_seq,
"gapless boundary"
);
if let Some(song) = boundary_song {
let result = match action {
Advance::Adopt => Some(mineral_stats::GaplessResult::Adopt),
Advance::Fallback => Some(mineral_stats::GaplessResult::Fallback),
Advance::None => None,
};
if let Some(result) = result {
player.inner.stats.event(mineral_stats::StatsEvent::System(
mineral_stats::SystemEvent::GaplessBoundary { song, result },
));
}
}
match action {
Advance::Adopt => {
player.with_state(|st| {
let _ = adopt_queued(st);
});
let (new, play_mode, playback_origin, media_info) = player.with_state(|st| {
(
st.current_song.clone(),
st.play_mode,
st.play_origin,
st.media_info.clone(),
)
});
if let Some(s) = new {
let context = player.take_play_context(&s.id);
if let Some(pending) = crate::pending_from_start(
s.clone(),
crate::stats_play_mode(play_mode),
s.duration_ms.and_then(|d| i64::try_from(d).ok()),
playback_origin.unwrap_or(PlaybackOrigin::Remote),
mineral_stats::PlayOrigin::AutoAdvance,
mineral_stats::Actor::System,
context,
) {
player.inner.stats.play_started(pending);
}
if let Some(info) = media_info {
player.enrich_from_media_info(
&info,
playback_origin.unwrap_or(PlaybackOrigin::Remote),
);
}
player.submit_task(
TaskKind::ChannelFetch(ChannelFetchKind::Lyrics { song_id: s.id }),
Priority::User,
);
}
player.replay_current_envelope();
player.spawn_save_session();
}
Advance::Fallback => {
drop(player.with_state(State::take_prefetch));
player.audio().clear_next();
let next = player.with_state(advance_next);
if let Some(next) = next {
player.play_song(
&next,
mineral_stats::PlayOrigin::AutoAdvance,
mineral_stats::Actor::System,
);
}
}
Advance::None => {}
}
}