2019-06-19 00:30:16 +02:00
|
|
|
use log::{debug, warn};
|
2017-05-24 00:13:23 +02:00
|
|
|
use serde_json::{self, Value};
|
|
|
|
use std::collections::HashMap;
|
2017-05-22 18:31:20 +02:00
|
|
|
use std::io::BufReader;
|
2017-05-24 00:13:23 +02:00
|
|
|
use std::io::prelude::*;
|
|
|
|
use std::iter::Iterator;
|
2017-06-01 19:30:52 +02:00
|
|
|
use super::*;
|
2017-05-22 18:31:20 +02:00
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct PlaylistEntry {
|
|
|
|
pub id: usize,
|
|
|
|
pub filename: String,
|
|
|
|
pub title: String,
|
|
|
|
pub current: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub trait TypeHandler: Sized {
|
2017-05-31 19:32:46 +02:00
|
|
|
fn get_value(value: Value) -> Result<Self, Error>;
|
2017-05-22 18:31:20 +02:00
|
|
|
fn as_string(&self) -> String;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeHandler for String {
|
2017-05-31 19:32:46 +02:00
|
|
|
fn get_value(value: Value) -> Result<String, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
if let Value::Object(map) = value {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
if let Value::String(ref s) = map["data"] {
|
|
|
|
Ok(s.to_string())
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::ValueDoesNotContainString))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_string(&self) -> String {
|
|
|
|
self.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeHandler for bool {
|
2017-05-31 19:32:46 +02:00
|
|
|
fn get_value(value: Value) -> Result<bool, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
if let Value::Object(map) = value {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
if let Value::Bool(ref b) = map["data"] {
|
|
|
|
Ok(*b)
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::ValueDoesNotContainBool))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
fn as_string(&self) -> String {
|
|
|
|
if *self {
|
|
|
|
"true".to_string()
|
|
|
|
} else {
|
|
|
|
"false".to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeHandler for f64 {
|
2017-05-31 19:32:46 +02:00
|
|
|
fn get_value(value: Value) -> Result<f64, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
if let Value::Object(map) = value {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
if let Value::Number(ref num) = map["data"] {
|
|
|
|
Ok(num.as_f64().unwrap())
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::ValueDoesNotContainF64))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_string(&self) -> String {
|
|
|
|
self.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeHandler for usize {
|
2017-05-31 19:32:46 +02:00
|
|
|
fn get_value(value: Value) -> Result<usize, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
if let Value::Object(map) = value {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
if let Value::Number(ref num) = map["data"] {
|
|
|
|
Ok(num.as_u64().unwrap() as usize)
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::ValueDoesNotContainUsize))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_string(&self) -> String {
|
|
|
|
self.to_string()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-06 23:08:27 +02:00
|
|
|
impl TypeHandler for HashMap<String, MpvDataType> {
|
|
|
|
fn get_value(value: Value) -> Result<HashMap<String, MpvDataType>, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
if let Value::Object(map) = value {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
if let Value::Object(ref inner_map) = map["data"] {
|
2017-06-06 23:08:27 +02:00
|
|
|
Ok(json_map_to_hashmap(inner_map))
|
2017-05-22 18:31:20 +02:00
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::ValueDoesNotContainHashMap))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_string(&self) -> String {
|
|
|
|
format!("{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TypeHandler for Vec<PlaylistEntry> {
|
2017-05-31 19:32:46 +02:00
|
|
|
fn get_value(value: Value) -> Result<Vec<PlaylistEntry>, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
if let Value::Object(map) = value {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
if let Value::Array(ref playlist_vec) = map["data"] {
|
2017-06-06 23:08:27 +02:00
|
|
|
Ok(json_array_to_playlist(playlist_vec))
|
2017-05-22 18:31:20 +02:00
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::ValueDoesNotContainPlaylist))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn as_string(&self) -> String {
|
|
|
|
format!("{:?}", self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-31 19:32:46 +02:00
|
|
|
pub fn get_mpv_property<T: TypeHandler>(instance: &Mpv, property: &str) -> Result<T, Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
let ipc_string = format!("{{ \"command\": [\"get_property\",\"{}\"] }}\n", property);
|
|
|
|
|
2017-05-29 17:54:12 +02:00
|
|
|
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> {
|
2017-05-22 18:31:20 +02:00
|
|
|
let ipc_string = format!("{{ \"command\": [\"get_property\",\"{}\"] }}\n", property);
|
2017-05-29 17:54:12 +02:00
|
|
|
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
|
2017-05-22 18:31:20 +02:00
|
|
|
Ok(val) => {
|
|
|
|
if let Value::Object(map) = val {
|
|
|
|
if let Value::String(ref error) = map["error"] {
|
|
|
|
if error == "success" && map.contains_key("data") {
|
|
|
|
match map["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)),
|
2017-05-31 19:32:46 +02:00
|
|
|
_ => Err(Error(ErrorCode::UnsupportedType)),
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-06-01 19:30:52 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedValue))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
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-06-17 13:03:27 +02:00
|
|
|
pub fn set_mpv_property<T: TypeHandler>(
|
|
|
|
instance: &Mpv,
|
|
|
|
property: &str,
|
|
|
|
value: T,
|
|
|
|
) -> Result<(), Error> {
|
|
|
|
let ipc_string = format!(
|
|
|
|
"{{ \"command\": [\"set_property\", \"{}\", {}] }}\n",
|
|
|
|
property,
|
|
|
|
value.as_string()
|
|
|
|
);
|
2017-05-29 17:54:12 +02:00
|
|
|
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
|
2017-05-22 18:31:20 +02:00
|
|
|
Ok(_) => Ok(()),
|
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 run_mpv_command(instance: &Mpv, command: &str, args: &[&str]) -> Result<(), Error> {
|
2017-05-22 18:31:20 +02:00
|
|
|
let mut ipc_string = format!("{{ \"command\": [\"{}\"", command);
|
|
|
|
if args.len() > 0 {
|
2017-05-31 19:32:46 +02:00
|
|
|
for arg in args {
|
2017-05-22 18:31:20 +02:00
|
|
|
ipc_string.push_str(&format!(", \"{}\"", arg));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ipc_string.push_str("] }\n");
|
|
|
|
ipc_string = ipc_string;
|
2017-05-29 17:54:12 +02:00
|
|
|
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
|
2017-05-22 18:31:20 +02:00
|
|
|
Ok(feedback) => {
|
|
|
|
if let Value::String(ref error) = feedback["error"] {
|
|
|
|
if error == "success" {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedResult))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-18 18:32:33 +02:00
|
|
|
pub fn observe_mpv_property(instance: &Mpv, id: &isize, property: &str) -> Result<(), Error> {
|
2017-06-17 13:03:27 +02:00
|
|
|
let ipc_string = format!(
|
|
|
|
"{{ \"command\": [\"observe_property\", {}, \"{}\"] }}\n",
|
|
|
|
id,
|
|
|
|
property
|
|
|
|
);
|
2017-05-29 17:54:12 +02:00
|
|
|
match serde_json::from_str::<Value>(&send_command_sync(instance, &ipc_string)) {
|
2017-05-24 00:13:23 +02:00
|
|
|
Ok(feedback) => {
|
|
|
|
if let Value::String(ref error) = feedback["error"] {
|
|
|
|
if error == "success" {
|
|
|
|
Ok(())
|
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::MpvError(error.to_string())))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
2017-05-24 00:13:23 +02:00
|
|
|
} else {
|
2017-05-31 19:32:46 +02:00
|
|
|
Err(Error(ErrorCode::UnexpectedResult))
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-19 00:30:16 +02:00
|
|
|
fn try_convert_property(name: &str, id: isize, data: MpvDataType) -> Event {
|
|
|
|
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);
|
|
|
|
Property::Unknown { name: name.to_string(), id, data }
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Event::PropertyChange(property)
|
|
|
|
}
|
|
|
|
|
2017-06-17 13:03:27 +02:00
|
|
|
pub fn listen(instance: &mut Mpv) -> Result<Event, Error> {
|
2017-05-29 17:54:12 +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 = response.trim_end().to_string();
|
2019-06-18 18:34:23 +02:00
|
|
|
debug!("Event: {}", response);
|
2017-05-29 17:54:12 +02:00
|
|
|
match serde_json::from_str::<Value>(&response) {
|
|
|
|
Ok(e) => {
|
|
|
|
if let Value::String(ref name) = e["event"] {
|
2017-06-06 23:08:27 +02:00
|
|
|
let event: Event;
|
|
|
|
match name.as_str() {
|
|
|
|
"shutdown" => {
|
|
|
|
event = Event::Shutdown;
|
|
|
|
}
|
|
|
|
"start-file" => {
|
|
|
|
event = Event::StartFile;
|
|
|
|
}
|
|
|
|
"file-loaded" => {
|
|
|
|
event = Event::FileLoaded;
|
|
|
|
}
|
|
|
|
"seek" => {
|
|
|
|
event = Event::Seek;
|
|
|
|
}
|
|
|
|
"playback-restart" => {
|
|
|
|
event = Event::PlaybackRestart;
|
|
|
|
}
|
|
|
|
"idle" => {
|
|
|
|
event = Event::Idle;
|
|
|
|
}
|
|
|
|
"tick" => {
|
|
|
|
event = Event::Tick;
|
|
|
|
}
|
|
|
|
"video-reconfig" => {
|
|
|
|
event = Event::VideoReconfig;
|
|
|
|
}
|
|
|
|
"audio-reconfig" => {
|
|
|
|
event = Event::AudioReconfig;
|
|
|
|
}
|
|
|
|
"tracks-changed" => {
|
|
|
|
event = Event::TracksChanged;
|
|
|
|
}
|
|
|
|
"track-switched" => {
|
|
|
|
event = Event::TrackSwitched;
|
|
|
|
}
|
|
|
|
"pause" => {
|
|
|
|
event = Event::Pause;
|
|
|
|
}
|
|
|
|
"unpause" => {
|
|
|
|
event = Event::Unpause;
|
|
|
|
}
|
|
|
|
"metadata-update" => {
|
|
|
|
event = Event::MetadataUpdate;
|
|
|
|
}
|
|
|
|
"chapter-change" => {
|
|
|
|
event = Event::ChapterChange;
|
|
|
|
}
|
|
|
|
"end-file" => {
|
|
|
|
event = Event::EndFile;
|
|
|
|
}
|
|
|
|
"property-change" => {
|
|
|
|
let name: String;
|
2019-06-18 18:32:33 +02:00
|
|
|
let id: isize;
|
2017-06-06 23:08:27 +02:00
|
|
|
let data: MpvDataType;
|
|
|
|
|
|
|
|
if let Value::String(ref n) = e["name"] {
|
|
|
|
name = n.to_string();
|
|
|
|
} else {
|
|
|
|
return Err(Error(ErrorCode::JsonContainsUnexptectedType));
|
|
|
|
}
|
|
|
|
|
|
|
|
if let Value::Number(ref n) = e["id"] {
|
2019-06-18 18:32:33 +02:00
|
|
|
id = n.as_i64().unwrap() as isize;
|
2017-06-06 23:08:27 +02:00
|
|
|
} else {
|
2019-06-18 18:32:33 +02:00
|
|
|
id = 0;
|
2017-06-06 23:08:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
match e["data"] {
|
|
|
|
Value::String(ref n) => {
|
|
|
|
data = MpvDataType::String(n.to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Array(ref a) => {
|
|
|
|
if name == "playlist".to_string() {
|
|
|
|
data =
|
|
|
|
MpvDataType::Playlist(Playlist(json_array_to_playlist(a)));
|
|
|
|
} else {
|
|
|
|
data = MpvDataType::Array(json_array_to_vec(a));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Bool(ref b) => {
|
|
|
|
data = MpvDataType::Bool(*b);
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Number(ref n) => {
|
|
|
|
if n.is_u64() {
|
|
|
|
data = MpvDataType::Usize(n.as_u64().unwrap() as usize);
|
|
|
|
} else if n.is_f64() {
|
|
|
|
data = MpvDataType::Double(n.as_f64().unwrap());
|
|
|
|
} else {
|
|
|
|
return Err(Error(ErrorCode::JsonContainsUnexptectedType));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Object(ref m) => {
|
|
|
|
data = MpvDataType::HashMap(json_map_to_hashmap(m));
|
|
|
|
}
|
|
|
|
|
2017-06-17 13:03:27 +02:00
|
|
|
Value::Null => {
|
|
|
|
data = MpvDataType::Null;
|
2017-06-06 23:08:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-19 00:30:16 +02:00
|
|
|
event = try_convert_property(name.as_ref(), id, data);
|
2017-06-06 23:08:27 +02:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
event = Event::Unimplemented;
|
|
|
|
}
|
2017-06-01 19:30:52 +02:00
|
|
|
};
|
2017-06-17 13:03:27 +02:00
|
|
|
return Ok(event);
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
|
|
|
}
|
2017-06-06 23:08:27 +02:00
|
|
|
Err(why) => return Err(Error(ErrorCode::JsonParseError(why.to_string()))),
|
2017-05-22 18:31:20 +02:00
|
|
|
}
|
2017-06-17 13:03:27 +02:00
|
|
|
unreachable!();
|
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-06-17 13:03:27 +02:00
|
|
|
// let mut stream = &instance.0;
|
|
|
|
// let mut buffer = [0; 32];
|
|
|
|
// stream.read(&mut buffer[..]).unwrap();
|
|
|
|
// String::from_utf8_lossy(&buffer).into_owned()
|
2017-05-31 19:32:46 +02:00
|
|
|
}
|
|
|
|
|
2017-05-29 17:54:12 +02:00
|
|
|
fn send_command_sync(instance: &Mpv, command: &str) -> String {
|
2017-06-17 13:03:27 +02:00
|
|
|
let mut stream = &instance.stream;
|
2017-05-29 17:54:12 +02:00
|
|
|
match stream.write_all(command.as_bytes()) {
|
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(_) => {
|
2019-06-18 18:34:23 +02:00
|
|
|
debug!("Command: {}", command.trim_end());
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-06 23:08:27 +02:00
|
|
|
|
|
|
|
fn json_map_to_hashmap(map: &serde_json::map::Map<String, Value>) -> HashMap<String, MpvDataType> {
|
|
|
|
let mut output_map: HashMap<String, MpvDataType> = HashMap::new();
|
|
|
|
for (ref key, ref value) in map.iter() {
|
|
|
|
match **value {
|
|
|
|
Value::Array(ref array) => {
|
2017-06-17 13:03:27 +02:00
|
|
|
output_map.insert(
|
|
|
|
key.to_string(),
|
|
|
|
MpvDataType::Array(json_array_to_vec(array)),
|
|
|
|
);
|
2017-06-06 23:08:27 +02:00
|
|
|
}
|
|
|
|
Value::Bool(ref b) => {
|
|
|
|
output_map.insert(key.to_string(), MpvDataType::Bool(*b));
|
|
|
|
}
|
|
|
|
Value::Number(ref n) => {
|
|
|
|
if n.is_u64() {
|
2017-06-17 13:03:27 +02:00
|
|
|
output_map.insert(
|
|
|
|
key.to_string(),
|
|
|
|
MpvDataType::Usize(n.as_u64().unwrap() as usize),
|
|
|
|
);
|
2017-06-06 23:08:27 +02:00
|
|
|
} else if n.is_f64() {
|
|
|
|
output_map.insert(key.to_string(), MpvDataType::Double(n.as_f64().unwrap()));
|
|
|
|
} else {
|
|
|
|
panic!("unimplemented number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Value::String(ref s) => {
|
|
|
|
output_map.insert(key.to_string(), MpvDataType::String(s.to_string()));
|
|
|
|
}
|
|
|
|
Value::Object(ref m) => {
|
2017-06-17 13:03:27 +02:00
|
|
|
output_map.insert(
|
|
|
|
key.to_string(),
|
|
|
|
MpvDataType::HashMap(json_map_to_hashmap(m)),
|
|
|
|
);
|
2017-06-06 23:08:27 +02:00
|
|
|
}
|
|
|
|
Value::Null => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
output_map
|
|
|
|
}
|
|
|
|
|
|
|
|
fn json_array_to_vec(array: &Vec<Value>) -> Vec<MpvDataType> {
|
|
|
|
let mut output: Vec<MpvDataType> = Vec::new();
|
|
|
|
if array.len() > 0 {
|
|
|
|
match array[0] {
|
|
|
|
Value::Array(_) => {
|
|
|
|
for entry in array {
|
|
|
|
if let Value::Array(ref a) = *entry {
|
|
|
|
output.push(MpvDataType::Array(json_array_to_vec(a)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Bool(_) => {
|
|
|
|
for entry in array {
|
|
|
|
if let Value::Bool(ref b) = *entry {
|
|
|
|
output.push(MpvDataType::Bool(*b));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Number(_) => {
|
|
|
|
for entry in array {
|
|
|
|
if let Value::Number(ref n) = *entry {
|
|
|
|
if n.is_u64() {
|
|
|
|
output.push(MpvDataType::Usize(n.as_u64().unwrap() as usize));
|
|
|
|
} else if n.is_f64() {
|
|
|
|
output.push(MpvDataType::Double(n.as_f64().unwrap()));
|
|
|
|
} else {
|
|
|
|
panic!("unimplemented number");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Object(_) => {
|
|
|
|
for entry in array {
|
|
|
|
if let Value::Object(ref map) = *entry {
|
|
|
|
output.push(MpvDataType::HashMap(json_map_to_hashmap(map)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::String(_) => {
|
|
|
|
for entry in array {
|
|
|
|
if let Value::String(ref s) = *entry {
|
|
|
|
output.push(MpvDataType::String(s.to_string()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Value::Null => {
|
|
|
|
unimplemented!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
output
|
|
|
|
}
|
|
|
|
|
|
|
|
fn json_array_to_playlist(array: &Vec<Value>) -> Vec<PlaylistEntry> {
|
|
|
|
let mut output: Vec<PlaylistEntry> = Vec::new();
|
|
|
|
for (id, entry) in array.iter().enumerate() {
|
|
|
|
let mut filename: String = String::new();
|
|
|
|
let mut title: String = String::new();
|
|
|
|
let mut current: bool = false;
|
|
|
|
if let Value::String(ref f) = entry["filename"] {
|
|
|
|
filename = f.to_string();
|
|
|
|
}
|
|
|
|
if let Value::String(ref t) = entry["title"] {
|
|
|
|
title = t.to_string();
|
|
|
|
}
|
|
|
|
if let Value::Bool(ref b) = entry["current"] {
|
|
|
|
current = *b;
|
|
|
|
}
|
|
|
|
output.push(PlaylistEntry {
|
2017-06-17 13:03:27 +02:00
|
|
|
id,
|
|
|
|
filename,
|
|
|
|
title,
|
|
|
|
current,
|
|
|
|
});
|
2017-06-06 23:08:27 +02:00
|
|
|
}
|
|
|
|
output
|
2019-06-18 17:34:20 +02:00
|
|
|
}
|