use dioxus::prelude::*;
use hooks::PlayerController;
use reader::models::Track;
use server::source::ActiveSource;
use std::future::Future;
use tracing::Instrument;
pub const RADIO_ICON: &str = "fa-solid fa-tower-broadcast";
pub fn radio_label() -> String {
i18n::t("start_radio").to_string()
}
fn radio_supported(active_source: &Signal<ActiveSource>) -> bool {
active_source.read().capabilities().radio
}
fn spawn_radio<F>(seed: String, fut: F, mut ctrl: PlayerController)
where
F: Future<Output = Result<Vec<Track>, server::source::SourceError>> + 'static,
{
spawn(
async move {
match fut.await {
Ok(tracks) if !tracks.is_empty() => ctrl.play_queue_linear(tracks),
Ok(_) => tracing::debug!(seed = %seed, "radio returned empty queue"),
Err(e) => tracing::warn!(seed = %seed, error = %e, "radio failed"),
}
}
.instrument(tracing::info_span!("radio.start")),
);
}
pub fn play_track_radio(track: Track, source: ActiveSource, ctrl: PlayerController) {
let seed = track.id.key().into_owned();
let fetch = seed.clone();
spawn_radio(seed, async move { source.start_radio(&fetch).await }, ctrl);
}
pub fn play_playlist_radio(playlist_id: String, source: ActiveSource, ctrl: PlayerController) {
let seed = playlist_id.clone();
spawn_radio(
seed,
async move { source.start_playlist_radio(&playlist_id).await },
ctrl,
);
}
pub fn track_radio_handler(track: Track) -> Option<EventHandler<()>> {
let ctrl = consume_context::<PlayerController>();
let active_source = consume_context::<Signal<ActiveSource>>();
radio_supported(&active_source).then(|| {
EventHandler::new(move |_| {
let src = active_source.peek().clone();
play_track_radio(track.clone(), src, ctrl)
})
})
}
pub fn playlist_radio_handler(playlist_id: String) -> Option<EventHandler<()>> {
let ctrl = consume_context::<PlayerController>();
let active_source = consume_context::<Signal<ActiveSource>>();
radio_supported(&active_source).then(|| {
EventHandler::new(move |_| {
let src = active_source.peek().clone();
play_playlist_radio(playlist_id.clone(), src, ctrl)
})
})
}