use std::sync::atomic::Ordering;
use lunar_lib::{
database::{Db, TransactionError},
id::Id,
iterator_ext::IteratorExtensions,
};
use selene_core::{database::Library, library::collectable::Collectable};
use selene_plugin_sdk::{self as sdk, define_stable_logger};
use crate::{
LoopMode, ShuffleMode,
decoder::DecoderCommandExt,
library_db,
local_session::{LocalSessionEventExt, LocalSessionHandle},
playlist::Playable,
session::SessionRunnerExt,
};
pub trait PluginCollectableExt {
fn into_collectable(self) -> Collectable;
fn into_playable(self, db: &Db<Library>) -> Result<Playable, TransactionError>;
}
impl PluginCollectableExt for sdk::local_session::Collectable {
fn into_collectable(self) -> Collectable {
self.match_owned(
|id| Collectable::Track(Id::from(id)),
|id| Collectable::Artist(Id::from(id)),
|id| Collectable::Album(Id::from(id)),
)
}
fn into_playable(self, db: &Db<Library>) -> Result<Playable, TransactionError> {
Playable::from_collectable(self.into_collectable(), db)
}
}
impl From<sdk::local_session::ShuffleMode> for ShuffleMode {
fn from(value: sdk::local_session::ShuffleMode) -> Self {
match value {
sdk::local_session::ShuffleMode::None => ShuffleMode::None,
sdk::local_session::ShuffleMode::CollectionsOnly => ShuffleMode::CollectionsOnly,
sdk::local_session::ShuffleMode::TracksOnly => ShuffleMode::TracksOnly,
sdk::local_session::ShuffleMode::CollectionsAndTracks => {
ShuffleMode::CollectionsAndTracks
}
sdk::local_session::ShuffleMode::Full => ShuffleMode::Full,
}
}
}
impl From<ShuffleMode> for sdk::local_session::ShuffleMode {
fn from(value: ShuffleMode) -> Self {
match value {
ShuffleMode::None => sdk::local_session::ShuffleMode::None,
ShuffleMode::CollectionsOnly => sdk::local_session::ShuffleMode::CollectionsOnly,
ShuffleMode::TracksOnly => sdk::local_session::ShuffleMode::TracksOnly,
ShuffleMode::CollectionsAndTracks => {
sdk::local_session::ShuffleMode::CollectionsAndTracks
}
ShuffleMode::Full => sdk::local_session::ShuffleMode::Full,
}
}
}
impl From<sdk::local_session::LoopMode> for LoopMode {
fn from(value: sdk::local_session::LoopMode) -> Self {
match value {
sdk::local_session::LoopMode::None => LoopMode::None,
sdk::local_session::LoopMode::Loop => LoopMode::Loop,
sdk::local_session::LoopMode::LoopAndReshuffle => LoopMode::LoopAndReshuffle,
sdk::local_session::LoopMode::RepeatTrack => LoopMode::RepeatTrack,
}
}
}
impl From<LoopMode> for sdk::local_session::LoopMode {
fn from(value: LoopMode) -> Self {
match value {
LoopMode::None => sdk::local_session::LoopMode::None,
LoopMode::Loop => sdk::local_session::LoopMode::Loop,
LoopMode::LoopAndReshuffle => sdk::local_session::LoopMode::LoopAndReshuffle,
LoopMode::RepeatTrack => sdk::local_session::LoopMode::RepeatTrack,
}
}
}
impl sdk::local_session::StableLocalSessionHandle for LocalSessionHandle {
extern "C" fn play(&self, collectables: sdk::Vec<sdk::local_session::Collectable>) {
let playables = {
collectables
.into_iter()
.flat_map(|p| p.into_playable(library_db()))
.collect()
};
self.session_runner.play(playables).unwrap().unwrap();
}
extern "C" fn stop(&self) {
self.session_runner.stop().unwrap().unwrap();
}
extern "C" fn set_is_playing(&self, is_playing: bool) -> bool {
self.session_runner
.set_is_playing(is_playing)
.unwrap()
.unwrap()
}
extern "C" fn toggle_is_playing(&self) -> bool {
self.session_runner.toggle_playing().unwrap().unwrap()
}
extern "C" fn previous(&self) -> sdk::Option<u32> {
self.session_runner.previous().unwrap().unwrap().into()
}
extern "C" fn next(&self) -> sdk::Option<u32> {
self.session_runner.next().unwrap().unwrap().into()
}
extern "C" fn seek(&self, seconds: f64, increment: bool) -> sdk::Option<f64> {
self.session_runner
.seek(seconds, increment)
.unwrap()
.unwrap()
.into()
}
extern "C" fn get_time(&self) -> selene_plugin_sdk::Option<f64> {
self.decoder_runner.get_time().unwrap().into()
}
extern "C" fn playlist_set_shuffle_mode(&self, shuffle_mode: sdk::local_session::ShuffleMode) {
self.session_runner
.set_shuffle_mode(shuffle_mode.into())
.unwrap()
.unwrap();
}
extern "C" fn playlist_get_shuffle_mode(
&self,
) -> selene_plugin_sdk::local_session::ShuffleMode {
self.session_runner.get_shuffle_mode().unwrap().into()
}
extern "C" fn playlist_set_loop_mode(&self, loop_mode: sdk::local_session::LoopMode) {
self.session_runner.set_loop_mode(loop_mode.into()).unwrap();
}
extern "C" fn playlist_get_loop_mode(&self) -> selene_plugin_sdk::local_session::LoopMode {
self.session_runner.get_loop_mode().unwrap().into()
}
extern "C" fn playlist_set(&self, collectables: sdk::Vec<sdk::local_session::Collectable>) {
let db = library_db();
self.session_runner
.playlist_set(
collectables
.into_iter()
.map(|c| sdk::local_session::Collectable::into_playable(c, db))
.try_to_vec()
.expect("Plugins should return valid IDs"),
)
.unwrap()
.unwrap();
}
extern "C" fn playlist_extend(&self, collectables: sdk::Vec<sdk::local_session::Collectable>) {
let db = library_db();
self.session_runner
.playlist_extend(
collectables
.into_iter()
.map(|c| sdk::local_session::Collectable::into_playable(c, db))
.try_to_vec()
.expect("Plugins should return valid IDs"),
)
.unwrap()
.unwrap();
}
extern "C" fn playlist_clear(&self) {
self.session_runner.playlist_clear().unwrap().unwrap();
}
extern "C" fn queue_set(&self, collectables: sdk::Vec<sdk::local_session::Collectable>) {
let db = library_db();
self.session_runner
.queue_set(
collectables
.into_iter()
.map(|c| sdk::local_session::Collectable::into_playable(c, db))
.try_to_vec()
.expect("Plugins should return valid IDs"),
)
.unwrap()
.unwrap();
}
extern "C" fn queue_extend(&self, collectables: sdk::Vec<sdk::local_session::Collectable>) {
let db = library_db();
self.session_runner
.queue_extend(
collectables
.into_iter()
.map(|c| sdk::local_session::Collectable::into_playable(c, db))
.try_to_vec()
.expect("Plugins should return valid IDs"),
)
.unwrap()
.unwrap();
}
extern "C" fn queue_clear(&self) {
self.session_runner.queue_clear().unwrap().unwrap();
}
extern "C" fn queue_shuffle(&self) {
self.session_runner.queue_shuffle().unwrap().unwrap();
}
extern "C" fn tracklist_seek(&self, index: i32, increment: bool) -> sdk::Option<u32> {
self.session_runner
.tracklist_seek(index, increment)
.unwrap()
.unwrap()
.into()
}
extern "C" fn volume_set(&self, volume: f32) -> f32 {
let volume = volume.clamp(0.0, 1.0);
self.volume.store(volume.to_bits(), Ordering::Relaxed);
self.session.event_runner.volume_changed(volume).unwrap();
volume
}
extern "C" fn volume_get(&self) -> f32 {
f32::from_bits(self.volume.load(Ordering::Relaxed))
}
}
define_stable_logger!();