Handle Player critical errors

This commit is contained in:
Vladimir Borisov 2026-03-12 17:28:44 +02:00
parent 72f881447a
commit 0b882f3f9b
No known key found for this signature in database
GPG key ID: F9A584BE4FCB6603
3 changed files with 63 additions and 15 deletions

View file

@ -41,9 +41,17 @@ impl PlayerProprChange {
} }
} }
} }
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
struct PlayerEndedError {
message: String,
critical: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)] #[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq)]
pub struct PlayerEnded { pub struct PlayerEnded {
reason: String, reason: String,
#[serde(skip_serializing_if = "Option::is_none")]
error: Option<PlayerEndedError>,
} }
impl PlayerEnded { impl PlayerEnded {
fn string_from_end_reason(data: EndFileReason) -> String { fn string_from_end_reason(data: EndFileReason) -> String {
@ -53,9 +61,24 @@ impl PlayerEnded {
_ => "other".to_string(), _ => "other".to_string(),
} }
} }
pub fn from_end_reason(data: EndFileReason) -> Self { pub fn from_end_reason(data: EndFileReason, error: &str) -> Self {
Self { Self {
reason: Self::string_from_end_reason(data), reason: Self::string_from_end_reason(data),
error: if data == mpv_end_file_reason::Error {
if error.is_empty() {
Some(PlayerEndedError {
message: "Unknown error".to_string(),
critical: true,
})
} else {
Some(PlayerEndedError {
message: error.to_string(),
critical: true,
})
}
} else {
None
},
} }
} }
} }

View file

@ -59,26 +59,42 @@ fn propr_change_tokens() {
#[test] #[test]
fn ended_tokens() { fn ended_tokens() {
let error_tokens: [Token; 12] = [
Token::Struct {
name: "PlayerEnded",
len: 2,
},
Token::Str("reason"),
Token::Str("error"),
Token::Str("error"),
Token::Some,
Token::Struct {
name: "PlayerEndedError",
len: 2,
},
Token::Str("message"),
Token::Str("Unknown error"),
Token::Str("critical"),
Token::Bool(true),
Token::StructEnd,
Token::StructEnd,
];
let tokens: [Token; 4] = [ let tokens: [Token; 4] = [
Token::Struct { Token::Struct {
name: "PlayerEnded", name: "PlayerEnded",
len: 1, len: 1,
}, },
Token::Str("reason"), Token::Str("reason"),
Token::None, Token::Str("quit"),
Token::StructEnd, Token::StructEnd,
]; ];
let mut typed_tokens = tokens.clone();
typed_tokens[2] = Token::Str("error");
assert_tokens( assert_tokens(
&PlayerEnded::from_end_reason(mpv_end_file_reason::Error), &PlayerEnded::from_end_reason(mpv_end_file_reason::Error, ""),
&typed_tokens, &error_tokens,
); );
let mut typed_tokens = tokens.clone();
typed_tokens[2] = Token::Str("quit");
assert_tokens( assert_tokens(
&PlayerEnded::from_end_reason(mpv_end_file_reason::Quit), &PlayerEnded::from_end_reason(mpv_end_file_reason::Quit, ""),
&typed_tokens, &tokens,
); );
} }

View file

@ -103,11 +103,20 @@ fn create_event_thread(
} }
// -1.0 means to block and wait for an event. // -1.0 means to block and wait for an event.
let event = match event_context.wait_event(-1.) { let (event, error) = match event_context.wait_event(-1.) {
Some(Ok(event)) => event, Some(Ok(event)) => (event, ""),
Some(Err(error)) => { Some(Err(error)) => {
eprintln!("Event errored: {error:?}"); if let libmpv2::Error::Raw(e) = error {
continue; (
Event::EndFile(
libmpv2_sys::mpv_end_file_reason_MPV_END_FILE_REASON_ERROR,
),
libmpv2_sys::mpv_error_str(e),
)
} else {
eprintln!("Unhandled event error: {error:?}");
continue;
}
} }
// dummy event received (may be created on a wake up call or on timeout) // dummy event received (may be created on a wake up call or on timeout)
None => continue, None => continue,
@ -124,7 +133,7 @@ fn create_event_thread(
), ),
Event::EndFile(reason) => PlayerResponse( Event::EndFile(reason) => PlayerResponse(
"mpv-event-ended", "mpv-event-ended",
PlayerEvent::End(PlayerEnded::from_end_reason(reason)), PlayerEvent::End(PlayerEnded::from_end_reason(reason, error)),
), ),
Event::Shutdown => { Event::Shutdown => {
break; break;