2024-04-16 22:48:27 +02:00
|
|
|
use crate::message_parser::TypeHandler;
|
|
|
|
|
|
|
|
use self::message_parser::extract_mpv_response_data;
|
|
|
|
use self::message_parser::json_array_to_playlist;
|
|
|
|
use self::message_parser::json_array_to_vec;
|
|
|
|
use self::message_parser::json_map_to_hashmap;
|
|
|
|
|
2019-06-19 00:51:11 +02:00
|
|
|
use super::*;
|
2019-06-19 00:30:16 +02:00
|
|
|
use log::{debug, warn};
|
2023-08-02 11:15:37 +02:00
|
|
|
use serde_json::json;
|
2024-04-16 22:48:27 +02:00
|
|
|
use serde_json::Value;
|
|
|
|
use std::io::BufRead;
|
2019-06-19 00:51:11 +02:00
|
|
|
use std::io::BufReader;
|
2024-04-16 22:48:27 +02:00
|
|
|
use std::io::Write;
|
2017-05-22 18:31:20 +02:00
|
|
|
|
2017-05-31 19:32:46 +02:00
|
|
|
pub fn get_mpv_property<T: TypeHandler>(instance: &Mpv, property: &str) -> Result<T, Error> {
|
2023-08-02 11:15:37 +02:00
|
|
|
let ipc_string = json!({"command": ["get_property", property]});
|
|
|
|
match serde_json::from_str::<Value>(&send_command_sync(instance, ipc_string)) {
|
2017-05-22 18:31:20 +02:00
|
|
|
Ok(val) => T::get_value(val),
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(why) => Err(Error(ErrorCode::JsonParseError(why.to_string()))),
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-31 19:32:46 +02:00
|
|
|
pub fn get_mpv_property_string(instance: &Mpv, property: &str) -> Result<String, Error> {
|
2023-08-02 11:15:37 +02:00
|
|
|
let ipc_string = json!({"command": ["get_property", property]});
|
|
|
|
let val = serde_json::from_str::<Value>(&send_command_sync(instance, ipc_string))
|
2022-07-19 20:54:44 +02:00
|
|
|
.map_err(|why| Error(ErrorCode::JsonParseError(why.to_string())))?;
|
|
|
|
|
2024-04-16 22:48:27 +02:00
|
|
|
let data = extract_mpv_response_data(&val)?;
|
2022-07-19 20:59:33 +02:00
|
|
|
|
|
|
|
match data {
|
|
|
|
Value::Bool(b) => Ok(b.to_string()),
|
|
|
|
Value::Number(ref n) => Ok(n.to_string()),
|
|
|
|
Value::String(ref s) => Ok(s.to_string()),
|
|
|
|
Value::Array(ref array) => Ok(format!("{:?}", array)),
|
|
|
|
Value::Object(ref map) => Ok(format!("{:?}", map)),
|
|
|
|
Value::Null => Err(Error(ErrorCode::MissingValue)),
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-16 22:48:27 +02:00
|
|
|
fn validate_mpv_response(response: &str) -> Result<(), Error> {
|
|
|
|
serde_json::from_str::<Value>(response)
|
|
|
|
.map_err(|why| Error(ErrorCode::JsonParseError(why.to_string())))
|
|
|
|
.and_then(|value| extract_mpv_response_data(&value).map(|_| ()))
|
|
|
|
}
|
|
|
|
|
2023-08-02 11:15:37 +02:00
|
|
|
pub fn set_mpv_property(instance: &Mpv, property: &str, value: Value) -> Result<(), Error> {
|
|
|
|
let ipc_string = json!({
|
|
|
|
"command": ["set_property", property, value]
|
|
|
|
});
|
|
|
|
|
2024-04-16 22:48:27 +02:00
|
|
|
let response = &send_command_sync(instance, ipc_string);
|
|
|
|
validate_mpv_response(response)
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
|
2017-05-31 19:32:46 +02:00
|
|
|
pub fn run_mpv_command(instance: &Mpv, command: &str, args: &[&str]) -> Result<(), Error> {
|
2023-08-02 11:15:37 +02:00
|
|
|
let mut ipc_string = json!({
|
|
|
|
"command": [command]
|
|
|
|
});
|
|
|
|
if let Value::Array(args_array) = &mut ipc_string["command"] {
|
|
|
|
for arg in args {
|
|
|
|
args_array.push(json!(arg));
|
|
|
|
}
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
2024-04-16 22:48:27 +02:00
|
|
|
|
|
|
|
let response = &send_command_sync(instance, ipc_string);
|
|
|
|
validate_mpv_response(response)
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
|
2022-07-10 20:59:52 +02:00
|
|
|
pub fn observe_mpv_property(instance: &Mpv, id: &isize, property: &str) -> Result<(), Error> {
|
2023-08-02 11:15:37 +02:00
|
|
|
let ipc_string = json!({
|
|
|
|
"command": ["observe_property", id, property]
|
|
|
|
});
|
2024-04-16 22:48:27 +02:00
|
|
|
|
|
|
|
let response = &send_command_sync(instance, ipc_string);
|
|
|
|
validate_mpv_response(response)
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
|
2022-07-10 20:59:52 +02:00
|
|
|
pub fn unobserve_mpv_property(instance: &Mpv, id: &isize) -> Result<(), Error> {
|
2023-08-02 11:15:37 +02:00
|
|
|
let ipc_string = json!({
|
|
|
|
"command": ["unobserve_property", id]
|
|
|
|
});
|
2024-04-16 22:48:27 +02:00
|
|
|
|
|
|
|
let response = &send_command_sync(instance, ipc_string);
|
|
|
|
validate_mpv_response(response)
|
2022-07-10 15:16:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fn try_convert_property(name: &str, id: usize, data: MpvDataType) -> Event {
|
2019-06-19 00:30:16 +02:00
|
|
|
let property = match name {
|
|
|
|
"path" => match data {
|
|
|
|
MpvDataType::String(value) => Property::Path(Some(value)),
|
|
|
|
MpvDataType::Null => Property::Path(None),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
"pause" => match data {
|
|
|
|
MpvDataType::Bool(value) => Property::Pause(value),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
"playback-time" => match data {
|
|
|
|
MpvDataType::Double(value) => Property::PlaybackTime(Some(value)),
|
|
|
|
MpvDataType::Null => Property::PlaybackTime(None),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
"duration" => match data {
|
|
|
|
MpvDataType::Double(value) => Property::Duration(Some(value)),
|
|
|
|
MpvDataType::Null => Property::Duration(None),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
"metadata" => match data {
|
|
|
|
MpvDataType::HashMap(value) => Property::Metadata(Some(value)),
|
|
|
|
MpvDataType::Null => Property::Metadata(None),
|
|
|
|
_ => unimplemented!(),
|
|
|
|
},
|
|
|
|
_ => {
|
|
|
|
warn!("Property {} not implemented", name);
|
2019-06-19 00:51:11 +02:00
|
|
|
Property::Unknown {
|
|
|
|
name: name.to_string(),
|
|
|
|
data,
|
|
|
|
}
|
2019-06-19 00:30:16 +02:00
|
|
|
}
|
|
|
|
};
|
2019-06-24 20:11:58 +02:00
|
|
|
Event::PropertyChange { id, property }
|
2019-06-19 00:30:16 +02:00
|
|
|
}
|
|
|
|
|
2017-06-17 13:03:27 +02:00
|
|
|
pub fn listen(instance: &mut Mpv) -> Result<Event, Error> {
|
2022-07-19 21:27:02 +02:00
|
|
|
let mut e;
|
|
|
|
// sometimes we get responses unrelated to events, so we read a new line until we receive one
|
|
|
|
// with an event field
|
|
|
|
let name = loop {
|
|
|
|
let mut response = String::new();
|
|
|
|
instance.reader.read_line(&mut response).unwrap();
|
|
|
|
response = response.trim_end().to_string();
|
|
|
|
debug!("Event: {}", response);
|
|
|
|
|
|
|
|
e = serde_json::from_str::<Value>(&response)
|
|
|
|
.map_err(|why| Error(ErrorCode::JsonParseError(why.to_string())))?;
|
|
|
|
|
|
|
|
match e["event"] {
|
|
|
|
Value::String(ref name) => break name,
|
|
|
|
_ => {
|
|
|
|
// It was not an event - try again
|
|
|
|
debug!("Bad response: {:?}", response)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
2022-07-19 20:34:11 +02:00
|
|
|
|
2022-07-19 21:27:02 +02:00
|
|
|
let event = match name.as_str() {
|
|
|
|
"shutdown" => Event::Shutdown,
|
|
|
|
"start-file" => Event::StartFile,
|
|
|
|
"file-loaded" => Event::FileLoaded,
|
|
|
|
"seek" => Event::Seek,
|
|
|
|
"playback-restart" => Event::PlaybackRestart,
|
|
|
|
"idle" => Event::Idle,
|
|
|
|
"tick" => Event::Tick,
|
|
|
|
"video-reconfig" => Event::VideoReconfig,
|
|
|
|
"audio-reconfig" => Event::AudioReconfig,
|
|
|
|
"tracks-changed" => Event::TracksChanged,
|
|
|
|
"track-switched" => Event::TrackSwitched,
|
|
|
|
"pause" => Event::Pause,
|
|
|
|
"unpause" => Event::Unpause,
|
|
|
|
"metadata-update" => Event::MetadataUpdate,
|
|
|
|
"chapter-change" => Event::ChapterChange,
|
|
|
|
"end-file" => Event::EndFile,
|
|
|
|
"property-change" => {
|
|
|
|
let name = match e["name"] {
|
|
|
|
Value::String(ref n) => Ok(n.to_string()),
|
|
|
|
_ => Err(Error(ErrorCode::JsonContainsUnexptectedType)),
|
|
|
|
}?;
|
|
|
|
|
|
|
|
let id: usize = match e["id"] {
|
|
|
|
Value::Number(ref n) => n.as_u64().unwrap() as usize,
|
|
|
|
_ => 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
let data: MpvDataType = match e["data"] {
|
|
|
|
Value::String(ref n) => MpvDataType::String(n.to_string()),
|
|
|
|
|
|
|
|
Value::Array(ref a) => {
|
|
|
|
if name == "playlist".to_string() {
|
|
|
|
MpvDataType::Playlist(Playlist(json_array_to_playlist(a)))
|
|
|
|
} else {
|
|
|
|
MpvDataType::Array(json_array_to_vec(a))
|
2022-07-19 20:34:11 +02:00
|
|
|
}
|
2022-07-19 21:27:02 +02:00
|
|
|
}
|
2022-07-19 20:34:11 +02:00
|
|
|
|
2022-07-19 21:27:02 +02:00
|
|
|
Value::Bool(b) => MpvDataType::Bool(b),
|
2017-06-06 23:08:27 +02:00
|
|
|
|
2022-07-19 21:27:02 +02:00
|
|
|
Value::Number(ref n) => {
|
|
|
|
if n.is_u64() {
|
|
|
|
MpvDataType::Usize(n.as_u64().unwrap() as usize)
|
|
|
|
} else if n.is_f64() {
|
|
|
|
MpvDataType::Double(n.as_f64().unwrap())
|
|
|
|
} else {
|
|
|
|
return Err(Error(ErrorCode::JsonContainsUnexptectedType));
|
2022-07-19 20:34:11 +02:00
|
|
|
}
|
2022-07-19 21:27:02 +02:00
|
|
|
}
|
2017-06-06 23:08:27 +02:00
|
|
|
|
2022-07-19 21:27:02 +02:00
|
|
|
Value::Object(ref m) => MpvDataType::HashMap(json_map_to_hashmap(m)),
|
2017-06-06 23:08:27 +02:00
|
|
|
|
2022-07-19 21:27:02 +02:00
|
|
|
Value::Null => MpvDataType::Null,
|
|
|
|
};
|
2022-07-19 20:34:11 +02:00
|
|
|
|
2022-07-19 21:27:02 +02:00
|
|
|
try_convert_property(name.as_ref(), id, data)
|
|
|
|
}
|
2023-07-30 23:14:20 +03:00
|
|
|
"client-message" => {
|
|
|
|
let args = match e["args"] {
|
|
|
|
Value::Array(ref a) => json_array_to_vec(a)
|
|
|
|
.iter()
|
|
|
|
.map(|arg| match arg {
|
|
|
|
MpvDataType::String(s) => Ok(s.to_owned()),
|
|
|
|
_ => Err(Error(ErrorCode::JsonContainsUnexptectedType)),
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>, _>>(),
|
|
|
|
_ => return Err(Error(ErrorCode::JsonContainsUnexptectedType)),
|
|
|
|
}?;
|
|
|
|
Event::ClientMessage { args }
|
|
|
|
}
|
2022-07-19 21:27:02 +02:00
|
|
|
_ => Event::Unimplemented,
|
|
|
|
};
|
|
|
|
Ok(event)
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
|
2017-06-17 13:03:27 +02:00
|
|
|
pub fn listen_raw(instance: &mut Mpv) -> String {
|
2017-05-31 19:32:46 +02:00
|
|
|
let mut response = String::new();
|
2017-06-17 13:03:27 +02:00
|
|
|
instance.reader.read_line(&mut response).unwrap();
|
2019-06-18 17:32:42 +02:00
|
|
|
response.trim_end().to_string()
|
2017-05-31 19:32:46 +02:00
|
|
|
}
|
|
|
|
|
2023-08-02 11:15:37 +02:00
|
|
|
fn send_command_sync(instance: &Mpv, command: Value) -> String {
|
|
|
|
let stream = &instance.stream;
|
|
|
|
match serde_json::to_writer(stream, &command) {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(why) => panic!("Error: Could not write to socket: {}", why),
|
2017-05-29 17:54:12 +02:00
|
|
|
Ok(_) => {
|
2023-08-02 11:15:37 +02:00
|
|
|
let mut stream = stream;
|
|
|
|
stream.write_all(b"\n").unwrap();
|
2017-05-29 17:54:12 +02:00
|
|
|
let mut response = String::new();
|
|
|
|
{
|
|
|
|
let mut reader = BufReader::new(stream);
|
|
|
|
while !response.contains("\"error\":") {
|
|
|
|
response.clear();
|
|
|
|
reader.read_line(&mut response).unwrap();
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
2019-06-18 18:34:23 +02:00
|
|
|
debug!("Response: {}", response.trim_end());
|
2017-05-29 17:54:12 +02:00
|
|
|
response
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|