use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DeviceInfo {
pub name: String,
pub ip: std::net::IpAddr,
pub port: u16,
pub model: Option<String>,
pub uuid: Option<String>,
}
impl DeviceInfo {
pub async fn connect(&self) -> crate::Result<crate::CastClient> {
crate::CastClient::connect(&self.ip.to_string(), self.port).await
}
}
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
pub struct Volume {
pub level: f32,
pub muted: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[non_exhaustive]
pub enum StreamType {
None,
Buffered,
Live,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum PlayerState {
Idle,
Playing,
Paused,
Buffering,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum IdleReason {
Cancelled,
Interrupted,
Finished,
Error,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MediaInfo {
pub content_id: String,
pub content_type: String,
pub stream_type: StreamType,
pub duration: Option<f64>,
pub metadata: Option<MediaMetadata>,
}
impl MediaInfo {
#[must_use]
pub fn new(content_id: impl Into<String>, content_type: impl Into<String>) -> Self {
Self {
content_id: content_id.into(),
content_type: content_type.into(),
stream_type: StreamType::Buffered,
duration: None,
metadata: None,
}
}
pub fn stream_type(mut self, stream_type: StreamType) -> Self {
self.stream_type = stream_type;
self
}
pub fn duration(mut self, duration: f64) -> Self {
self.duration = Some(duration);
self
}
pub fn maybe_duration(self, duration: Option<f64>) -> Self {
match duration {
Some(d) => self.duration(d),
None => self,
}
}
pub fn metadata(mut self, metadata: MediaMetadata) -> Self {
self.metadata = Some(metadata);
self
}
pub fn maybe_metadata(self, metadata: Option<MediaMetadata>) -> Self {
match metadata {
Some(m) => self.metadata(m),
None => self,
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum MediaMetadata {
Generic {
title: Option<String>,
subtitle: Option<String>,
images: Vec<Image>,
},
Movie {
title: Option<String>,
subtitle: Option<String>,
studio: Option<String>,
images: Vec<Image>,
},
TvShow {
series_title: Option<String>,
episode_title: Option<String>,
season: Option<u32>,
episode: Option<u32>,
images: Vec<Image>,
},
MusicTrack {
title: Option<String>,
artist: Option<String>,
album_name: Option<String>,
composer: Option<String>,
track_number: Option<u32>,
disc_number: Option<u32>,
images: Vec<Image>,
},
Photo {
title: Option<String>,
artist: Option<String>,
location: Option<String>,
latitude: Option<f64>,
longitude: Option<f64>,
width: Option<u32>,
height: Option<u32>,
images: Vec<Image>,
},
AudiobookChapter {
book_title: Option<String>,
chapter_title: Option<String>,
chapter_number: Option<u32>,
subtitle: Option<String>,
images: Vec<Image>,
},
}
#[derive(Debug, Clone, PartialEq)]
pub struct Image {
pub url: String,
pub width: Option<u32>,
pub height: Option<u32>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct MediaStatus {
pub media_session_id: i32,
pub player_state: PlayerState,
pub idle_reason: Option<IdleReason>,
pub current_time: f64,
pub duration: Option<f64>,
pub volume: Volume,
pub media: Option<MediaInfo>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ReceiverStatus {
pub volume: Volume,
pub applications: Vec<Application>,
pub is_active_input: bool,
pub is_stand_by: bool,
}
#[derive(Debug, Clone, PartialEq)]
pub struct Application {
pub app_id: String,
pub display_name: String,
pub session_id: String,
pub transport_id: String,
pub namespaces: Vec<String>,
pub status_text: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum CastApp {
DefaultMediaReceiver,
Backdrop,
YouTube,
Custom(String),
}
impl CastApp {
pub fn app_id(&self) -> &str {
match self {
CastApp::DefaultMediaReceiver => crate::channel::ns::APP_DEFAULT_MEDIA_RECEIVER,
CastApp::Backdrop => crate::channel::ns::APP_BACKDROP,
CastApp::YouTube => crate::channel::ns::APP_YOUTUBE,
CastApp::Custom(id) => id,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
#[non_exhaustive]
pub enum RepeatMode {
RepeatOff,
RepeatAll,
RepeatSingle,
RepeatAllAndShuffle,
}
#[derive(Debug, Clone, PartialEq)]
pub struct QueueItem {
pub media: MediaInfo,
pub autoplay: bool,
pub start_time: f64,
}
impl std::fmt::Display for PlayerState {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
PlayerState::Idle => write!(f, "idle"),
PlayerState::Playing => write!(f, "playing"),
PlayerState::Paused => write!(f, "paused"),
PlayerState::Buffering => write!(f, "buffering"),
}
}
}
impl std::fmt::Display for IdleReason {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IdleReason::Cancelled => write!(f, "cancelled"),
IdleReason::Interrupted => write!(f, "interrupted"),
IdleReason::Finished => write!(f, "finished"),
IdleReason::Error => write!(f, "error"),
}
}
}
impl std::fmt::Display for StreamType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
StreamType::None => write!(f, "none"),
StreamType::Buffered => write!(f, "buffered"),
StreamType::Live => write!(f, "live"),
}
}
}
impl std::fmt::Display for CastApp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
CastApp::DefaultMediaReceiver => write!(f, "Default Media Receiver"),
CastApp::Backdrop => write!(f, "Backdrop"),
CastApp::YouTube => write!(f, "YouTube"),
CastApp::Custom(id) => write!(f, "Custom({id})"),
}
}
}
impl Volume {
#[must_use]
pub fn new(level: f32) -> Self {
Self { level: level.clamp(0.0, 1.0), muted: false }
}
#[must_use]
pub fn muted() -> Self {
Self { level: 0.0, muted: true }
}
}
impl MediaInfo {
#[must_use]
pub fn movie(
content_id: impl Into<String>,
content_type: impl Into<String>,
title: impl Into<String>,
) -> Self {
Self {
content_id: content_id.into(),
content_type: content_type.into(),
stream_type: StreamType::Buffered,
duration: None,
metadata: Some(MediaMetadata::Movie {
title: Some(title.into()),
subtitle: None,
studio: None,
images: vec![],
}),
}
}
#[must_use]
pub fn live(content_id: impl Into<String>, content_type: impl Into<String>) -> Self {
Self {
content_id: content_id.into(),
content_type: content_type.into(),
stream_type: StreamType::Live,
duration: None,
metadata: None,
}
}
}