2024-01-16 20:18:27 +01:00
|
|
|
use std::{
|
|
|
|
fmt::{Debug, Display},
|
|
|
|
sync::{Arc, Mutex, RwLock},
|
|
|
|
};
|
|
|
|
|
2024-09-26 21:45:43 +02:00
|
|
|
pub use mers_lib;
|
|
|
|
|
2024-01-16 20:18:27 +01:00
|
|
|
use mers_lib::{
|
2024-10-11 21:57:32 +02:00
|
|
|
data::{self, function::Function, object::ObjectFieldsMap, Data, MersData, MersType, Type},
|
|
|
|
info::DisplayInfo,
|
2024-01-16 20:18:27 +01:00
|
|
|
prelude_extend_config::Config,
|
|
|
|
};
|
|
|
|
use musicdb_lib::{
|
|
|
|
data::{
|
|
|
|
album::Album,
|
|
|
|
artist::Artist,
|
|
|
|
database::Database,
|
2024-03-30 22:13:59 +01:00
|
|
|
queue::{Queue, QueueContent, QueueFolder},
|
2024-01-16 20:18:27 +01:00
|
|
|
song::Song,
|
|
|
|
},
|
|
|
|
server::Command,
|
|
|
|
};
|
|
|
|
|
|
|
|
pub fn add(
|
2024-01-20 01:19:19 +01:00
|
|
|
mut cfg: Config,
|
2024-01-16 20:18:27 +01:00
|
|
|
db: &Arc<Mutex<Database>>,
|
|
|
|
cmd: &Arc<impl Fn(Command) + Sync + Send + 'static>,
|
2024-01-20 01:19:19 +01:00
|
|
|
after_db_cmd: &Arc<Mutex<Option<Box<dyn FnMut(Command) + Send + Sync + 'static>>>>,
|
2024-01-16 20:18:27 +01:00
|
|
|
) -> Config {
|
2024-01-20 01:19:19 +01:00
|
|
|
/// handle commands received from server (for handler functions)
|
|
|
|
/// `T` can be used to return generated data to avoid calculating something twice if one event may call multiple handlers.
|
|
|
|
fn handle<T>(
|
|
|
|
handler: &Arc<RwLock<Data>>,
|
|
|
|
gen: impl FnOnce() -> (Data, T),
|
|
|
|
) -> Option<(T, Data)> {
|
|
|
|
if let Some(func) = handler
|
|
|
|
.read()
|
|
|
|
.unwrap()
|
|
|
|
.get()
|
|
|
|
.as_any()
|
|
|
|
.downcast_ref::<Function>()
|
|
|
|
{
|
|
|
|
let (data, t) = gen();
|
2024-09-26 21:45:43 +02:00
|
|
|
Some((t, func.run_immut(data).ok()?))
|
2024-01-20 01:19:19 +01:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let handler_resume = Arc::new(RwLock::new(Data::empty_tuple()));
|
|
|
|
let handler_pause = Arc::new(RwLock::new(Data::empty_tuple()));
|
|
|
|
let handler_next_song = Arc::new(RwLock::new(Data::empty_tuple()));
|
|
|
|
let handler_queue_changed = Arc::new(RwLock::new(Data::empty_tuple()));
|
|
|
|
let handler_library_changed = Arc::new(RwLock::new(Data::empty_tuple()));
|
|
|
|
let handler_notification_received = Arc::new(RwLock::new(Data::empty_tuple()));
|
|
|
|
{
|
|
|
|
*after_db_cmd.lock().unwrap() = Some({
|
|
|
|
let handler_resume = Arc::clone(&handler_resume);
|
|
|
|
let handler_pause = Arc::clone(&handler_pause);
|
|
|
|
let handler_next_song = Arc::clone(&handler_next_song);
|
|
|
|
let handler_queue_changed = Arc::clone(&handler_queue_changed);
|
|
|
|
let handler_library_changed = Arc::clone(&handler_library_changed);
|
|
|
|
let handler_notification_received = Arc::clone(&handler_notification_received);
|
|
|
|
Box::new(move |cmd| match cmd {
|
|
|
|
Command::Resume => {
|
|
|
|
handle(&handler_resume, move || (Data::empty_tuple(), ()));
|
2024-01-17 15:04:41 +01:00
|
|
|
}
|
2024-01-20 01:19:19 +01:00
|
|
|
Command::Pause | Command::Stop => {
|
|
|
|
handle(&handler_pause, move || (Data::empty_tuple(), ()));
|
2024-01-17 15:04:41 +01:00
|
|
|
}
|
2024-01-20 01:19:19 +01:00
|
|
|
Command::NextSong => {
|
|
|
|
handle(&handler_next_song, move || (Data::empty_tuple(), ()));
|
|
|
|
handle(&handler_queue_changed, move || (Data::empty_tuple(), ()));
|
|
|
|
}
|
|
|
|
Command::SyncDatabase(..) => {
|
|
|
|
handle(&handler_library_changed, move || (Data::empty_tuple(), ()));
|
|
|
|
}
|
|
|
|
Command::QueueUpdate(..)
|
|
|
|
| Command::QueueAdd(..)
|
|
|
|
| Command::QueueInsert(..)
|
|
|
|
| Command::QueueRemove(..)
|
2024-04-01 00:54:00 +02:00
|
|
|
| Command::QueueMove(..)
|
|
|
|
| Command::QueueMoveInto(..)
|
2024-01-20 01:19:19 +01:00
|
|
|
| Command::QueueGoto(..)
|
2024-03-30 22:13:59 +01:00
|
|
|
| Command::QueueShuffle(..)
|
|
|
|
| Command::QueueSetShuffle(..)
|
|
|
|
| Command::QueueUnshuffle(..) => {
|
2024-01-20 01:19:19 +01:00
|
|
|
handle(&handler_queue_changed, move || (Data::empty_tuple(), ()));
|
|
|
|
}
|
|
|
|
Command::AddSong(_)
|
|
|
|
| Command::AddAlbum(_)
|
|
|
|
| Command::AddArtist(_)
|
|
|
|
| Command::AddCover(_)
|
|
|
|
| Command::ModifySong(_)
|
|
|
|
| Command::ModifyAlbum(_)
|
|
|
|
| Command::ModifyArtist(_)
|
|
|
|
| Command::RemoveSong(_)
|
|
|
|
| Command::RemoveAlbum(_)
|
|
|
|
| Command::RemoveArtist(_) => {
|
|
|
|
handle(&handler_library_changed, move || (Data::empty_tuple(), ()));
|
|
|
|
}
|
|
|
|
Command::SetSongDuration(..) => {
|
|
|
|
handle(&handler_library_changed, move || (Data::empty_tuple(), ()));
|
|
|
|
}
|
|
|
|
Command::TagSongFlagSet(..)
|
|
|
|
| Command::TagSongFlagUnset(..)
|
|
|
|
| Command::TagAlbumFlagSet(..)
|
|
|
|
| Command::TagAlbumFlagUnset(..)
|
|
|
|
| Command::TagArtistFlagSet(..)
|
|
|
|
| Command::TagArtistFlagUnset(..)
|
|
|
|
| Command::TagSongPropertySet(..)
|
|
|
|
| Command::TagSongPropertyUnset(..)
|
|
|
|
| Command::TagAlbumPropertySet(..)
|
|
|
|
| Command::TagAlbumPropertyUnset(..)
|
|
|
|
| Command::TagArtistPropertySet(..)
|
|
|
|
| Command::TagArtistPropertyUnset(..) => {
|
|
|
|
handle(&handler_library_changed, move || (Data::empty_tuple(), ()));
|
|
|
|
}
|
|
|
|
Command::InitComplete => (),
|
|
|
|
Command::Save => (),
|
|
|
|
Command::ErrorInfo(title, body) => {
|
|
|
|
handle(&handler_notification_received, move || {
|
|
|
|
(
|
|
|
|
Data::new(data::tuple::Tuple(vec![
|
|
|
|
Data::new(data::string::String(title)),
|
|
|
|
Data::new(data::string::String(body)),
|
|
|
|
])),
|
|
|
|
(),
|
|
|
|
)
|
|
|
|
});
|
|
|
|
}
|
|
|
|
})
|
|
|
|
});
|
|
|
|
}
|
|
|
|
// MusicDb type
|
|
|
|
cfg = cfg
|
|
|
|
.with_list()
|
2024-09-26 21:45:43 +02:00
|
|
|
.add_type(MusicDbIdT.to_string(), Ok(Arc::new(Type::new(MusicDbIdT))));
|
2024-01-20 01:19:19 +01:00
|
|
|
// handler setters
|
|
|
|
for (name, handler, in_type) in [
|
|
|
|
("resume", handler_resume, Type::empty_tuple()),
|
|
|
|
("pause", handler_pause, Type::empty_tuple()),
|
|
|
|
("next_song", handler_next_song, Type::empty_tuple()),
|
|
|
|
(
|
|
|
|
"library_changed",
|
|
|
|
handler_library_changed,
|
|
|
|
Type::empty_tuple(),
|
|
|
|
),
|
|
|
|
("queue_changed", handler_queue_changed, Type::empty_tuple()),
|
|
|
|
(
|
|
|
|
"notification_received",
|
|
|
|
handler_notification_received,
|
|
|
|
Type::new(data::tuple::TupleT(vec![
|
|
|
|
Type::new(data::string::StringT),
|
|
|
|
Type::new(data::string::StringT),
|
|
|
|
])),
|
|
|
|
),
|
|
|
|
] {
|
|
|
|
cfg = cfg.add_var(
|
|
|
|
format!("handle_event_{name}"),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
move |a, i| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.types.iter().all(|a| {
|
|
|
|
Type::newm(vec![Arc::clone(a)]).is_zero_tuple()
|
|
|
|
|| a.as_any()
|
|
|
|
.downcast_ref::<data::function::FunctionT>()
|
2024-09-26 21:45:43 +02:00
|
|
|
.is_some_and(|a| a.o(&in_type).is_ok_and(|opt| opt.is_zero_tuple()))
|
2024-01-20 01:19:19 +01:00
|
|
|
}) {
|
2024-01-17 15:04:41 +01:00
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
2024-10-11 21:57:32 +02:00
|
|
|
Err(
|
|
|
|
format!("Handler function must be `{} -> ()`", in_type.with_info(i))
|
|
|
|
.into(),
|
|
|
|
)
|
2024-01-17 15:04:41 +01:00
|
|
|
}
|
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
move |a, _| {
|
|
|
|
*handler.write().unwrap() = a;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
|
|
|
},
|
2024-01-17 15:04:41 +01:00
|
|
|
),
|
2024-01-20 01:19:19 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
// actions
|
|
|
|
cfg.add_var(
|
|
|
|
"send_server_notification".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&data::string::StringT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `String`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |a, _| {
|
|
|
|
cmd(Command::ErrorInfo(
|
|
|
|
String::new(),
|
|
|
|
a.get()
|
|
|
|
.as_any()
|
|
|
|
.downcast_ref::<data::string::String>()
|
|
|
|
.unwrap()
|
|
|
|
.0
|
|
|
|
.clone(),
|
|
|
|
));
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"resume".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |_, _| {
|
|
|
|
cmd(Command::Resume);
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"pause".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |_, _| {
|
|
|
|
cmd(Command::Pause);
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
2024-09-26 21:45:43 +02:00
|
|
|
"stop".to_owned(),
|
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |_, _| {
|
|
|
|
cmd(Command::Stop);
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"next_song".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |_, _| {
|
|
|
|
cmd(Command::NextSong);
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_playing".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(data::bool::bool_type())
|
2024-01-20 01:19:19 +01:00
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-09-26 21:45:43 +02:00
|
|
|
move |_, _| Ok(Data::new(data::bool::Bool(db.lock().unwrap().playing)))
|
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"queue_get_current_song".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::newm(vec![
|
|
|
|
Arc::new(MusicDbIdT),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-09-26 21:45:43 +02:00
|
|
|
move |_, _| {
|
|
|
|
Ok(match db.lock().unwrap().queue.get_current_song() {
|
|
|
|
Some(id) => Data::new(MusicDbId(*id)),
|
|
|
|
None => Data::empty_tuple(),
|
|
|
|
})
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"queue_get_next_song".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::newm(vec![
|
|
|
|
Arc::new(MusicDbIdT),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-09-26 21:45:43 +02:00
|
|
|
move |_, _| {
|
|
|
|
Ok(match db.lock().unwrap().queue.get_next_song() {
|
|
|
|
Some(id) => Data::new(MusicDbId(*id)),
|
|
|
|
None => Data::empty_tuple(),
|
|
|
|
})
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"queue_get_elem".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, i| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT(
|
2024-10-11 21:57:32 +02:00
|
|
|
Type::new(data::int::IntT(data::int::INT_MIN, data::int::INT_MAX)),
|
2024-09-26 21:45:43 +02:00
|
|
|
)) {
|
2024-10-11 21:57:32 +02:00
|
|
|
Ok(gen_queue_elem_type_or_empty_tuple(i.display_info()))
|
2024-01-20 01:19:19 +01:00
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `List<Int>`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-10-11 21:57:32 +02:00
|
|
|
move |a, i| {
|
2024-01-20 01:19:19 +01:00
|
|
|
let a = int_list_to_usize_vec(&a);
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(
|
|
|
|
if let Some(elem) = db.lock().unwrap().queue.get_item_at_index(&a, 0) {
|
2024-10-11 21:57:32 +02:00
|
|
|
gen_queue_elem(elem, i.display_info())
|
2024-09-26 21:45:43 +02:00
|
|
|
} else {
|
|
|
|
Data::empty_tuple()
|
|
|
|
},
|
|
|
|
)
|
2024-01-17 15:04:41 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"queue_goto".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&mers_lib::program::configs::with_list::ListT(
|
2024-10-11 21:57:32 +02:00
|
|
|
Type::new(data::int::IntT(data::int::INT_MIN, data::int::INT_MAX)),
|
2024-09-26 21:45:43 +02:00
|
|
|
)) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `List<Int>`.").into())
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-01-20 01:19:19 +01:00
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |a, _| {
|
|
|
|
cmd(Command::QueueGoto(int_list_to_usize_vec(&a)));
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"queue_clear".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_included_in(&Type::empty_tuple()) {
|
|
|
|
Ok(Type::empty_tuple())
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let cmd = Arc::clone(cmd);
|
|
|
|
move |_, _| {
|
|
|
|
cmd(Command::QueueUpdate(
|
|
|
|
vec![],
|
2024-03-30 22:13:59 +01:00
|
|
|
QueueContent::Folder(QueueFolder::default()).into(),
|
2024-01-20 01:19:19 +01:00
|
|
|
));
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::empty_tuple())
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-01-20 01:19:19 +01:00
|
|
|
},
|
|
|
|
),
|
|
|
|
)
|
2024-09-26 21:45:43 +02:00
|
|
|
// TODO: `queue_add`, which takes any queue element as defined in `gen_queue_elem_type`
|
|
|
|
// .add_var(
|
|
|
|
// "queue_add_song".to_owned(),
|
|
|
|
// Function::new_generic(
|
|
|
|
// |a| {
|
|
|
|
// if a.is_included_in_single(&data::tuple::TupleT(vec![
|
|
|
|
// Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
// data::int::IntT,
|
|
|
|
// ))),
|
|
|
|
// Type::new(MusicDbIdT),
|
|
|
|
// ])) {
|
|
|
|
// Ok(Type::empty_tuple())
|
|
|
|
// } else {
|
|
|
|
// Err(format!("Function argument must be `(List<Int>, MusicDbId)`.").into())
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// let cmd = Arc::clone(cmd);
|
|
|
|
// move |a, _| {
|
|
|
|
// let a = a.get();
|
|
|
|
// let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
|
|
|
|
// let path = int_list_to_usize_vec(&a[0]);
|
|
|
|
// let song_id = a[1].get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
|
|
|
// cmd(Command::QueueAdd(
|
|
|
|
// path,
|
|
|
|
// vec![QueueContent::Song(song_id).into()],
|
|
|
|
// ));
|
|
|
|
// Ok(Data::empty_tuple())
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// ),
|
|
|
|
// )
|
|
|
|
// .add_var(
|
|
|
|
// "queue_add_loop".to_owned(),
|
|
|
|
// Function::new_generic(
|
|
|
|
// |a| {
|
|
|
|
// if a.is_included_in_single(&data::tuple::TupleT(vec![
|
|
|
|
// Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
// data::int::IntT,
|
|
|
|
// ))),
|
|
|
|
// Type::new(data::int::IntT),
|
|
|
|
// ])) {
|
|
|
|
// Ok(Type::empty_tuple())
|
|
|
|
// } else {
|
|
|
|
// Err(format!("Function argument must be `(List<Int>, Int)`.").into())
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// let cmd = Arc::clone(cmd);
|
|
|
|
// move |a, _| {
|
|
|
|
// let a = a.get();
|
|
|
|
// let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
|
|
|
|
// let path = int_list_to_usize_vec(&a[0]);
|
|
|
|
// let repeat_count = a[1]
|
|
|
|
// .get()
|
|
|
|
// .as_any()
|
|
|
|
// .downcast_ref::<data::int::Int>()
|
|
|
|
// .unwrap()
|
|
|
|
// .0;
|
|
|
|
// cmd(Command::QueueAdd(
|
|
|
|
// path,
|
|
|
|
// vec![QueueContent::Loop(
|
|
|
|
// repeat_count.max(0) as _,
|
|
|
|
// 0,
|
|
|
|
// Box::new(QueueContent::Folder(QueueFolder::default()).into()),
|
|
|
|
// )
|
|
|
|
// .into()],
|
|
|
|
// ));
|
|
|
|
// Ok(Data::empty_tuple())
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// ),
|
|
|
|
// )
|
|
|
|
// .add_var(
|
|
|
|
// "queue_add_folder".to_owned(),
|
|
|
|
// Function::new_generic(
|
|
|
|
// |a| {
|
|
|
|
// if a.is_included_in_single(&data::tuple::TupleT(vec![
|
|
|
|
// Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
// data::int::IntT,
|
|
|
|
// ))),
|
|
|
|
// Type::new(data::string::StringT),
|
|
|
|
// ])) {
|
|
|
|
// Ok(Type::empty_tuple())
|
|
|
|
// } else {
|
|
|
|
// Err(format!("Function argument must be `(List<Int>, String)`.").into())
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// {
|
|
|
|
// let cmd = Arc::clone(cmd);
|
|
|
|
// move |a, _| {
|
|
|
|
// let a = a.get();
|
|
|
|
// let a = &a.as_any().downcast_ref::<data::tuple::Tuple>().unwrap().0;
|
|
|
|
// let path = int_list_to_usize_vec(&a[0]);
|
|
|
|
// let name = a[1]
|
|
|
|
// .get()
|
|
|
|
// .as_any()
|
|
|
|
// .downcast_ref::<data::string::String>()
|
|
|
|
// .unwrap()
|
|
|
|
// .0
|
|
|
|
// .clone();
|
|
|
|
// cmd(Command::QueueAdd(
|
|
|
|
// path,
|
|
|
|
// vec![QueueContent::Folder(QueueFolder {
|
|
|
|
// index: 0,
|
|
|
|
// content: vec![],
|
|
|
|
// name,
|
|
|
|
// order: None,
|
|
|
|
// })
|
|
|
|
// .into()],
|
|
|
|
// ));
|
|
|
|
// Ok(Data::empty_tuple())
|
|
|
|
// }
|
|
|
|
// },
|
|
|
|
// ),
|
|
|
|
// )
|
2024-01-20 01:19:19 +01:00
|
|
|
.add_var(
|
|
|
|
"all_songs".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, i| {
|
2024-01-20 01:19:19 +01:00
|
|
|
if a.is_zero_tuple() {
|
|
|
|
Ok(Type::new(mers_lib::program::configs::with_list::ListT(
|
2024-10-11 21:57:32 +02:00
|
|
|
Type::new(gen_song_type(i.display_info())),
|
2024-01-20 01:19:19 +01:00
|
|
|
)))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `()`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-10-11 21:57:32 +02:00
|
|
|
move |_, i| {
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(Data::new(mers_lib::program::configs::with_list::List(
|
2024-01-20 01:19:19 +01:00
|
|
|
db.lock()
|
|
|
|
.unwrap()
|
|
|
|
.songs()
|
|
|
|
.values()
|
2024-10-11 21:57:32 +02:00
|
|
|
.map(|s| Arc::new(RwLock::new(gen_song(s, i.display_info()))))
|
2024-01-20 01:19:19 +01:00
|
|
|
.collect(),
|
2024-09-26 21:45:43 +02:00
|
|
|
)))
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_song".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, i| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&MusicDbIdT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::newm(vec![
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(gen_song_type(i.display_info())),
|
2024-01-20 01:19:19 +01:00
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `MusicDbId`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-10-11 21:57:32 +02:00
|
|
|
move |a, i| {
|
2024-01-20 01:19:19 +01:00
|
|
|
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(match db.lock().unwrap().get_song(&id) {
|
2024-10-11 21:57:32 +02:00
|
|
|
Some(song) => gen_song(song, i.display_info()),
|
2024-01-20 01:19:19 +01:00
|
|
|
None => Data::empty_tuple(),
|
2024-09-26 21:45:43 +02:00
|
|
|
})
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_album".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, i| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&MusicDbIdT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::newm(vec![
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(gen_album_type(i.display_info())),
|
2024-01-20 01:19:19 +01:00
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `MusicDbId`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-10-11 21:57:32 +02:00
|
|
|
move |a, i| {
|
2024-01-20 01:19:19 +01:00
|
|
|
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(match db.lock().unwrap().albums().get(&id) {
|
2024-10-11 21:57:32 +02:00
|
|
|
Some(album) => gen_album(album, i.display_info()),
|
2024-01-20 01:19:19 +01:00
|
|
|
None => Data::empty_tuple(),
|
2024-09-26 21:45:43 +02:00
|
|
|
})
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_artist".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, i| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&MusicDbIdT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::newm(vec![
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(gen_artist_type(i.display_info())),
|
2024-01-20 01:19:19 +01:00
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `MusicDbId`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
2024-10-11 21:57:32 +02:00
|
|
|
move |a, i| {
|
2024-01-20 01:19:19 +01:00
|
|
|
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(match db.lock().unwrap().artists().get(&id) {
|
2024-10-11 21:57:32 +02:00
|
|
|
Some(artist) => gen_artist(artist, i.display_info()),
|
2024-01-20 01:19:19 +01:00
|
|
|
None => Data::empty_tuple(),
|
2024-09-26 21:45:43 +02:00
|
|
|
})
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_song_tags".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&MusicDbIdT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::newm(vec![
|
|
|
|
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
data::string::StringT,
|
|
|
|
))),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `MusicDbId`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
|
|
|
move |a, _| {
|
|
|
|
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(match db.lock().unwrap().get_song(&id) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Some(song) => Data::new(mers_lib::program::configs::with_list::List(
|
|
|
|
song.general
|
|
|
|
.tags
|
|
|
|
.iter()
|
|
|
|
.map(|t| {
|
|
|
|
Arc::new(RwLock::new(Data::new(data::string::String(
|
|
|
|
t.clone(),
|
|
|
|
))))
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
)),
|
|
|
|
None => Data::empty_tuple(),
|
2024-09-26 21:45:43 +02:00
|
|
|
})
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_album_tags".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&MusicDbIdT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::newm(vec![
|
|
|
|
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
data::string::StringT,
|
|
|
|
))),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `MusicDbId`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
|
|
|
move |a, _| {
|
|
|
|
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(match db.lock().unwrap().albums().get(&id) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Some(album) => Data::new(mers_lib::program::configs::with_list::List(
|
|
|
|
album
|
|
|
|
.general
|
|
|
|
.tags
|
|
|
|
.iter()
|
|
|
|
.map(|t| {
|
|
|
|
Arc::new(RwLock::new(Data::new(data::string::String(
|
|
|
|
t.clone(),
|
|
|
|
))))
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
)),
|
|
|
|
None => Data::empty_tuple(),
|
2024-09-26 21:45:43 +02:00
|
|
|
})
|
2024-01-20 01:19:19 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
|
|
|
.add_var(
|
|
|
|
"get_artist_tags".to_owned(),
|
2024-09-26 21:45:43 +02:00
|
|
|
Function::new_generic(
|
2024-10-11 21:57:32 +02:00
|
|
|
|a, _| {
|
2024-09-26 21:45:43 +02:00
|
|
|
if a.is_included_in_single(&MusicDbIdT) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Ok(Type::newm(vec![
|
|
|
|
Arc::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
data::string::StringT,
|
|
|
|
))),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]))
|
|
|
|
} else {
|
|
|
|
Err(format!("Function argument must be `MusicDbId`.").into())
|
|
|
|
}
|
|
|
|
},
|
|
|
|
{
|
|
|
|
let db = Arc::clone(db);
|
|
|
|
move |a, _| {
|
|
|
|
let id = a.get().as_any().downcast_ref::<MusicDbId>().unwrap().0;
|
2024-09-26 21:45:43 +02:00
|
|
|
Ok(match db.lock().unwrap().artists().get(&id) {
|
2024-01-20 01:19:19 +01:00
|
|
|
Some(artist) => Data::new(mers_lib::program::configs::with_list::List(
|
|
|
|
artist
|
|
|
|
.general
|
|
|
|
.tags
|
|
|
|
.iter()
|
|
|
|
.map(|t| {
|
|
|
|
Arc::new(RwLock::new(Data::new(data::string::String(
|
|
|
|
t.clone(),
|
|
|
|
))))
|
|
|
|
})
|
|
|
|
.collect(),
|
|
|
|
)),
|
|
|
|
None => Data::empty_tuple(),
|
2024-09-26 21:45:43 +02:00
|
|
|
})
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
},
|
2024-01-20 01:19:19 +01:00
|
|
|
),
|
|
|
|
)
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
|
|
|
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_song_type(i: DisplayInfo) -> data::object::ObjectT {
|
|
|
|
data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("id"),
|
|
|
|
Type::new(MusicDbIdT),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("title"),
|
|
|
|
Type::new(data::string::StringT),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("album"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::newm(vec![
|
|
|
|
Arc::new(MusicDbIdT),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("artist"),
|
|
|
|
Type::new(MusicDbIdT),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("cover"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::newm(vec![
|
|
|
|
Arc::new(MusicDbIdT),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]),
|
|
|
|
),
|
2024-09-26 21:45:43 +02:00
|
|
|
])
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_song(song: &Song, i: DisplayInfo) -> Data {
|
|
|
|
Data::new(data::object::Object::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("id"),
|
|
|
|
Data::new(MusicDbId(song.id)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("title"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(data::string::String(song.title.clone())),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("album"),
|
2024-01-16 20:18:27 +01:00
|
|
|
if let Some(album) = song.album {
|
|
|
|
Data::new(MusicDbId(album))
|
|
|
|
} else {
|
|
|
|
Data::empty_tuple()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("artist"),
|
|
|
|
Data::new(MusicDbId(song.artist)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("cover"),
|
2024-01-16 20:18:27 +01:00
|
|
|
if let Some(cover) = song.cover {
|
|
|
|
Data::new(MusicDbId(cover))
|
|
|
|
} else {
|
|
|
|
Data::empty_tuple()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
]))
|
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_album_type(i: DisplayInfo) -> data::object::ObjectT {
|
|
|
|
data::object::ObjectT::new(vec![
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("id"),
|
|
|
|
Type::new(MusicDbIdT),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("name"),
|
|
|
|
Type::new(data::string::StringT),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("artist"),
|
|
|
|
Type::new(MusicDbIdT),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("cover"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::newm(vec![
|
|
|
|
Arc::new(MusicDbIdT),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("songs"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
MusicDbIdT,
|
|
|
|
))),
|
|
|
|
),
|
2024-09-26 21:45:43 +02:00
|
|
|
])
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_album(album: &Album, i: DisplayInfo) -> Data {
|
|
|
|
Data::new(data::object::Object::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("id"),
|
|
|
|
Data::new(MusicDbId(album.id)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("name"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(data::string::String(album.name.clone())),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("artist"),
|
|
|
|
Data::new(MusicDbId(album.artist)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("cover"),
|
2024-01-16 20:18:27 +01:00
|
|
|
if let Some(cover) = album.cover {
|
|
|
|
Data::new(MusicDbId(cover))
|
|
|
|
} else {
|
|
|
|
Data::empty_tuple()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("songs"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(mers_lib::program::configs::with_list::List(
|
|
|
|
album
|
|
|
|
.songs
|
|
|
|
.iter()
|
|
|
|
.map(|id| Arc::new(RwLock::new(Data::new(MusicDbId(*id)))))
|
|
|
|
.collect(),
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
]))
|
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_artist_type(i: DisplayInfo) -> data::object::ObjectT {
|
|
|
|
data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("id"),
|
|
|
|
Type::new(MusicDbIdT),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("name"),
|
|
|
|
Type::new(data::string::StringT),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("cover"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::newm(vec![
|
|
|
|
Arc::new(MusicDbIdT),
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
|
|
|
]),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("albums"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
MusicDbIdT,
|
|
|
|
))),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("singles"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::new(mers_lib::program::configs::with_list::ListT(Type::new(
|
|
|
|
MusicDbIdT,
|
|
|
|
))),
|
|
|
|
),
|
2024-09-26 21:45:43 +02:00
|
|
|
])
|
2024-01-16 20:18:27 +01:00
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_artist(artist: &Artist, i: DisplayInfo) -> Data {
|
|
|
|
Data::new(data::object::Object::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("id"),
|
|
|
|
Data::new(MusicDbId(artist.id)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("name"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(data::string::String(artist.name.clone())),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("cover"),
|
2024-01-16 20:18:27 +01:00
|
|
|
if let Some(cover) = artist.cover {
|
|
|
|
Data::new(MusicDbId(cover))
|
|
|
|
} else {
|
|
|
|
Data::empty_tuple()
|
|
|
|
},
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("albums"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(mers_lib::program::configs::with_list::List(
|
|
|
|
artist
|
|
|
|
.albums
|
|
|
|
.iter()
|
|
|
|
.map(|id| Arc::new(RwLock::new(Data::new(MusicDbId(*id)))))
|
|
|
|
.collect(),
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("singles"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(mers_lib::program::configs::with_list::List(
|
|
|
|
artist
|
|
|
|
.singles
|
|
|
|
.iter()
|
|
|
|
.map(|id| Arc::new(RwLock::new(Data::new(MusicDbId(*id)))))
|
|
|
|
.collect(),
|
|
|
|
)),
|
|
|
|
),
|
|
|
|
]))
|
|
|
|
}
|
|
|
|
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_queue_elem_type_or_empty_tuple(i: DisplayInfo) -> Type {
|
2024-01-16 20:18:27 +01:00
|
|
|
Type::newm(vec![
|
|
|
|
Arc::new(data::tuple::TupleT(vec![])),
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("enabled"),
|
|
|
|
data::bool::bool_type(),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("song"),
|
|
|
|
Type::new(MusicDbIdT),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
])),
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("enabled"),
|
|
|
|
data::bool::bool_type(),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("loop"),
|
|
|
|
Type::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("total"),
|
|
|
|
Type::new(data::int::IntT(data::int::INT_MIN, data::int::INT_MAX)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("done"),
|
|
|
|
Type::new(data::int::IntT(data::int::INT_MIN, data::int::INT_MAX)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
])),
|
|
|
|
),
|
|
|
|
])),
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("enabled"),
|
|
|
|
data::bool::bool_type(),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("random"),
|
|
|
|
Type::empty_tuple(),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
])),
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("enabled"),
|
|
|
|
data::bool::bool_type(),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("folder"),
|
|
|
|
Type::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("index"),
|
|
|
|
Type::new(data::int::IntT(data::int::INT_MIN, data::int::INT_MAX)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("length"),
|
|
|
|
Type::new(data::int::IntT(data::int::INT_MIN, data::int::INT_MAX)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("name"),
|
|
|
|
Type::new(data::string::StringT),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
])),
|
|
|
|
),
|
|
|
|
])),
|
2024-10-11 21:57:32 +02:00
|
|
|
Arc::new(data::object::ObjectT::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("enabled"),
|
|
|
|
data::bool::bool_type(),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("shuffle"),
|
|
|
|
Type::empty_tuple(),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
])),
|
|
|
|
])
|
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn gen_queue_elem(queue_elem: &Queue, i: DisplayInfo) -> Data {
|
|
|
|
Data::new(data::object::Object::new(vec![
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("enabled"),
|
2024-01-16 20:18:27 +01:00
|
|
|
Data::new(data::bool::Bool(queue_elem.enabled())),
|
|
|
|
),
|
|
|
|
match queue_elem.content() {
|
2024-10-11 21:57:32 +02:00
|
|
|
QueueContent::Song(id) => (
|
|
|
|
i.object_fields.get_or_add_field("song"),
|
|
|
|
Data::new(MusicDbId(*id)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
QueueContent::Loop(total, done, _inner) => (
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("loop"),
|
|
|
|
Data::new(data::object::Object::new(vec![
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("total"),
|
|
|
|
Data::new(data::int::Int(*total as _)),
|
|
|
|
),
|
|
|
|
(
|
|
|
|
i.object_fields.get_or_add_field("done"),
|
|
|
|
Data::new(data::int::Int(*done as _)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
])),
|
|
|
|
),
|
2024-03-30 22:13:59 +01:00
|
|
|
QueueContent::Folder(folder) => (
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("folder"),
|
|
|
|
Data::new(data::object::Object::new(vec![
|
2024-03-30 22:13:59 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("index"),
|
2024-03-30 22:13:59 +01:00
|
|
|
Data::new(data::int::Int(folder.index as _)),
|
|
|
|
),
|
2024-01-16 20:18:27 +01:00
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("length"),
|
2024-03-30 22:13:59 +01:00
|
|
|
Data::new(data::int::Int(folder.content.len() as _)),
|
2024-01-16 20:18:27 +01:00
|
|
|
),
|
|
|
|
(
|
2024-10-11 21:57:32 +02:00
|
|
|
i.object_fields.get_or_add_field("name"),
|
2024-03-30 22:13:59 +01:00
|
|
|
Data::new(data::string::String(folder.name.clone())),
|
2024-01-16 20:18:27 +01:00
|
|
|
),
|
|
|
|
])),
|
|
|
|
),
|
|
|
|
},
|
|
|
|
]))
|
|
|
|
}
|
|
|
|
|
|
|
|
fn int_list_to_usize_vec(a: &Data) -> Vec<usize> {
|
|
|
|
a.get()
|
|
|
|
.as_any()
|
|
|
|
.downcast_ref::<mers_lib::program::configs::with_list::List>()
|
|
|
|
.unwrap()
|
|
|
|
.0
|
|
|
|
.iter()
|
|
|
|
.map(|v| {
|
|
|
|
v.read()
|
|
|
|
.unwrap()
|
|
|
|
.get()
|
|
|
|
.as_any()
|
|
|
|
.downcast_ref::<data::int::Int>()
|
|
|
|
.unwrap()
|
|
|
|
.0
|
|
|
|
.abs() as usize
|
|
|
|
})
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct MusicDbId(u64);
|
|
|
|
|
|
|
|
#[derive(Clone, Copy)]
|
|
|
|
pub struct MusicDbIdT;
|
|
|
|
|
|
|
|
impl MersData for MusicDbId {
|
|
|
|
fn as_type(&self) -> Type {
|
|
|
|
Type::new(MusicDbIdT)
|
|
|
|
}
|
2024-10-11 21:57:32 +02:00
|
|
|
fn display(
|
|
|
|
&self,
|
|
|
|
_info: &mers_lib::info::DisplayInfo<'_>,
|
|
|
|
f: &mut std::fmt::Formatter,
|
|
|
|
) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", self)
|
|
|
|
}
|
2024-01-16 20:18:27 +01:00
|
|
|
fn is_eq(&self, other: &dyn MersData) -> bool {
|
|
|
|
if let Some(other) = other.as_any().downcast_ref::<Self>() {
|
|
|
|
self.0 == other.0
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn clone(&self) -> Box<dyn MersData> {
|
|
|
|
Box::new(*self)
|
|
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
fn mut_any(&mut self) -> &mut dyn std::any::Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
fn to_any(self) -> Box<dyn std::any::Any> {
|
|
|
|
Box::new(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl MersType for MusicDbIdT {
|
2024-10-11 21:57:32 +02:00
|
|
|
fn display(
|
|
|
|
&self,
|
|
|
|
_info: &mers_lib::info::DisplayInfo<'_>,
|
|
|
|
f: &mut std::fmt::Formatter,
|
|
|
|
) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", self)
|
|
|
|
}
|
2024-01-16 20:18:27 +01:00
|
|
|
fn is_same_type_as(&self, other: &dyn MersType) -> bool {
|
|
|
|
other.as_any().is::<Self>()
|
|
|
|
}
|
2024-09-26 21:45:43 +02:00
|
|
|
fn is_included_in(&self, target: &dyn MersType) -> bool {
|
2024-01-16 20:18:27 +01:00
|
|
|
target.as_any().is::<Self>()
|
|
|
|
}
|
|
|
|
fn subtypes(&self, acc: &mut Type) {
|
|
|
|
acc.add(Arc::new(*self))
|
|
|
|
}
|
|
|
|
fn as_any(&self) -> &dyn std::any::Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
fn mut_any(&mut self) -> &mut dyn std::any::Any {
|
|
|
|
self
|
|
|
|
}
|
|
|
|
fn to_any(self) -> Box<dyn std::any::Any> {
|
|
|
|
Box::new(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for MusicDbId {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", self.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Debug for MusicDbId {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{self}")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Display for MusicDbIdT {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "MusicDbId")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
impl Debug for MusicDbIdT {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{self}")
|
|
|
|
}
|
|
|
|
}
|