use std::ffi::CString;
use apple_cf::cg::{CGRect, CGSize};
use crate::{ffi, MediaPlayerError};
pub struct Artwork {
pub(crate) ptr: *mut core::ffi::c_void,
}
unsafe impl Send for Artwork {}
unsafe impl Sync for Artwork {}
impl Clone for Artwork {
fn clone(&self) -> Self {
let ptr = unsafe { ffi::mp_object_retain(self.ptr) };
Self { ptr }
}
}
impl std::fmt::Debug for Artwork {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Artwork").field("ptr", &self.ptr).finish()
}
}
impl Artwork {
pub fn from_path(path: &str) -> Result<Self, MediaPlayerError> {
let c_path = CString::new(path)
.map_err(|error| MediaPlayerError::InvalidArgument(error.to_string()))?;
let ptr = unsafe { ffi::mp_artwork_new_from_path(c_path.as_ptr()) };
if ptr.is_null() {
Err(MediaPlayerError::Framework(format!(
"failed to load artwork from path: {path}"
)))
} else {
Ok(Self { ptr })
}
}
pub fn from_path_with_size(path: &str, bounds_size: CGSize) -> Result<Self, MediaPlayerError> {
let c_path = CString::new(path)
.map_err(|error| MediaPlayerError::InvalidArgument(error.to_string()))?;
let ptr = unsafe {
ffi::mp_artwork_new_from_path_with_size(
c_path.as_ptr(),
bounds_size.width,
bounds_size.height,
)
};
if ptr.is_null() {
Err(MediaPlayerError::Framework(format!(
"failed to load artwork from path: {path}"
)))
} else {
Ok(Self { ptr })
}
}
#[must_use]
pub fn bounds(&self) -> Option<CGRect> {
let mut origin_x = 0.0;
let mut origin_y = 0.0;
let mut width = 0.0;
let mut height = 0.0;
let ok = unsafe {
ffi::mp_artwork_copy_bounds(
self.ptr,
&mut origin_x,
&mut origin_y,
&mut width,
&mut height,
) != 0
};
ok.then_some(CGRect {
x: origin_x,
y: origin_y,
width,
height,
})
}
}
impl Drop for Artwork {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::mp_artwork_release(self.ptr) }
}
}
}
pub struct AnimatedArtwork {
pub(crate) ptr: *mut core::ffi::c_void,
}
unsafe impl Send for AnimatedArtwork {}
unsafe impl Sync for AnimatedArtwork {}
impl Clone for AnimatedArtwork {
fn clone(&self) -> Self {
let ptr = unsafe { ffi::mp_object_retain(self.ptr) };
Self { ptr }
}
}
impl std::fmt::Debug for AnimatedArtwork {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("AnimatedArtwork")
.field("ptr", &self.ptr)
.finish()
}
}
impl AnimatedArtwork {
pub fn from_files(
artwork_id: &str,
preview_image_path: &str,
video_asset_path: &str,
) -> Result<Self, MediaPlayerError> {
let artwork_id = CString::new(artwork_id)
.map_err(|error| MediaPlayerError::InvalidArgument(error.to_string()))?;
let preview_image_path = CString::new(preview_image_path)
.map_err(|error| MediaPlayerError::InvalidArgument(error.to_string()))?;
let video_asset_path = CString::new(video_asset_path)
.map_err(|error| MediaPlayerError::InvalidArgument(error.to_string()))?;
let ptr = unsafe {
ffi::mp_animated_artwork_new_from_files(
artwork_id.as_ptr(),
preview_image_path.as_ptr(),
video_asset_path.as_ptr(),
)
};
if ptr.is_null() {
Err(MediaPlayerError::Framework(
"failed to create MPMediaItemAnimatedArtwork from local files".to_string(),
))
} else {
Ok(Self { ptr })
}
}
}
impl Drop for AnimatedArtwork {
fn drop(&mut self) {
if !self.ptr.is_null() {
unsafe { ffi::mp_animated_artwork_release(self.ptr) }
}
}
}