Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic JSON metadata #21

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ mdns-sd = "0.6.1"
protobuf-codegen = "=3.2.0"

[features]
thread_safe = []
thread_safe = []
json_metadata = []
18 changes: 18 additions & 0 deletions src/cast/proxies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,17 @@ pub mod heartbeat {
pub mod media {
use serde::{Deserialize, Serialize};

#[cfg(not(feature = "json_metadata"))]
pub const METADATA_GENERIC: u32 = 0;
#[cfg(not(feature = "json_metadata"))]
pub const METADATA_MOVIE: u32 = 1;
#[cfg(not(feature = "json_metadata"))]
pub const METADATA_TV_SHOW: u32 = 2;
#[cfg(not(feature = "json_metadata"))]
pub const METADATA_MUSIC: u32 = 3;
#[cfg(not(feature = "json_metadata"))]
pub const METADATA_PHOTO: u32 = 4;

#[derive(Serialize, Debug)]
pub struct GetStatusRequest {
#[serde(rename = "requestId")]
Expand Down Expand Up @@ -104,12 +115,17 @@ pub mod media {
pub stream_type: String,
#[serde(rename = "contentType")]
pub content_type: String,
#[cfg(not(feature = "json_metadata"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<Metadata>,
#[cfg(feature = "json_metadata")]
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
pub duration: Option<f32>,
}

#[cfg(not(feature = "json_metadata"))]
#[derive(Serialize, Deserialize, Debug)]
pub struct Metadata {
#[serde(rename = "metadataType")]
Expand Down Expand Up @@ -178,6 +194,7 @@ pub mod media {
pub height: Option<u32>,
}

#[cfg(not(feature = "json_metadata"))]
impl Metadata {
pub fn new(metadata_type: u32) -> Metadata {
Metadata {
Expand Down Expand Up @@ -207,6 +224,7 @@ pub mod media {
}
}

#[cfg(not(feature = "json_metadata"))]
#[derive(Serialize, Deserialize, Debug)]
pub struct Image {
pub url: String,
Expand Down
118 changes: 96 additions & 22 deletions src/channels/media.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ impl ToString for StreamType {
}

/// Generic, movie, TV show, music track, or photo metadata.
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub enum Metadata {
Generic(GenericMediaMetadata),
Expand All @@ -75,6 +76,7 @@ pub enum Metadata {
/// Generic media metadata.
///
/// See also the [`GenericMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#GenericMediaMetadata).
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub struct GenericMediaMetadata {
/// Descriptive title of the content.
Expand All @@ -90,6 +92,7 @@ pub struct GenericMediaMetadata {
/// Movie media metadata.
///
/// See also the [`MovieMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#MovieMediaMetadata).
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub struct MovieMediaMetadata {
/// Title of the movie.
Expand All @@ -107,12 +110,13 @@ pub struct MovieMediaMetadata {
/// TV show media metadata.
///
/// See also the [`TvShowMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#TvShowMediaMetadata).
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub struct TvShowMediaMetadata {
/// Title of the TV series.
pub series_title: Option<String>,
/// Title of the episode.
pub episode_title: Option<String>,
/// Subtitle of the TV series.
pub subtitle: Option<String>,
/// Season number of the TV show.
pub season: Option<u32>,
/// Episode number (in the season) of the episode.
Expand All @@ -126,6 +130,7 @@ pub struct TvShowMediaMetadata {
/// Music track media metadata.
///
/// See also the [`MusicTrackMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#MusicTrackMediaMetadata).
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub struct MusicTrackMediaMetadata {
/// Album or collection from which the track is taken.
Expand All @@ -151,6 +156,7 @@ pub struct MusicTrackMediaMetadata {
/// Photo media metadata.
///
/// See also the [`PhotoMediaMetadata` Cast reference](https://developers.google.com/cast/docs/reference/messages#PhotoMediaMetadata).
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub struct PhotoMediaMetadata {
/// Title of the photograph.
Expand All @@ -175,6 +181,7 @@ pub struct PhotoMediaMetadata {
/// of images.
///
/// See also the [`Image` Cast reference](https://developers.google.com/cast/docs/reference/messages#Image).
#[cfg(not(feature = "json_metadata"))]
#[derive(Clone, Debug)]
pub struct Image {
/// URL of the image.
Expand All @@ -183,6 +190,7 @@ pub struct Image {
pub dimensions: Option<(u32, u32)>,
}

#[cfg(not(feature = "json_metadata"))]
impl Image {
pub fn new(url: String) -> Image {
Image {
Expand All @@ -198,6 +206,13 @@ impl Image {
height: self.dimensions.map(|d| d.1),
}
}

fn decode(image: &proxies::media::Image) -> Self {
Self {
url: image.url.clone(),
dimensions: image.width.zip(image.height),
}
}
}

/// Describes possible player states.
Expand Down Expand Up @@ -312,8 +327,12 @@ pub struct Media {
pub stream_type: StreamType,
/// MIME content type of the media being played.
pub content_type: String,
#[cfg(not(feature = "json_metadata"))]
/// Generic, movie, TV show, music track, or photo metadata.
pub metadata: Option<Metadata>,
#[cfg(feature = "json_metadata")]
/// Any valid JSON metadata
pub metadata: Option<serde_json::Value>,
/// Duration of the currently playing stream in seconds.
pub duration: Option<f32>,
}
Expand Down Expand Up @@ -512,6 +531,7 @@ where
{
let request_id = self.message_manager.generate_request_id();

#[cfg(not(feature = "json_metadata"))]
let metadata = media.metadata.as_ref().map(|m| match *m {
Metadata::Generic(ref x) => proxies::media::Metadata {
title: x.title.clone(),
Expand All @@ -530,7 +550,7 @@ where
},
Metadata::TvShow(ref x) => proxies::media::Metadata {
series_title: x.series_title.clone(),
subtitle: x.episode_title.clone(),
subtitle: x.subtitle.clone(),
season: x.season,
episode: x.episode,
images: x.images.iter().map(|i| i.encode()).collect(),
Expand Down Expand Up @@ -562,6 +582,9 @@ where
},
});

#[cfg(feature = "json_metadata")]
let metadata = media.metadata.clone();

let payload = serde_json::to_string(&proxies::media::MediaRequest {
request_id,
session_id: session_id.into().to_string(),
Expand Down Expand Up @@ -826,27 +849,78 @@ where
MESSAGE_TYPE_MEDIA_STATUS => {
let reply: proxies::media::StatusReply = serde_json::value::from_value(reply)?;

let statuses_entries = reply.status.iter().map(|x| {
StatusEntry {
media_session_id: x.media_session_id,
media: x.media.as_ref().map(|m| {
Media {
content_id: m.content_id.to_string(),
stream_type: StreamType::from_str(m.stream_type.as_ref()).unwrap(),
content_type: m.content_type.to_string(),
metadata: None, // TODO
duration: m.duration,
let statuses_entries = reply.status.iter().map(|x| StatusEntry {
media_session_id: x.media_session_id,
media: x.media.as_ref().map(|m| Media {
content_id: m.content_id.to_string(),
stream_type: StreamType::from_str(m.stream_type.as_ref()).unwrap(),
content_type: m.content_type.to_string(),
#[cfg(not(feature = "json_metadata"))]
metadata: m.metadata.as_ref().and_then(|m| match m.metadata_type {
proxies::media::METADATA_GENERIC => {
Some(Metadata::Generic(GenericMediaMetadata {
title: m.title.clone(),
subtitle: m.subtitle.clone(),
images: m.images.iter().map(|i| Image::decode(i)).collect(),
release_date: m.release_date.clone(),
}))
}
proxies::media::METADATA_MOVIE => {
Some(Metadata::Movie(MovieMediaMetadata {
title: m.title.clone(),
subtitle: m.subtitle.clone(),
studio: m.studio.clone(),
images: m.images.iter().map(|i| Image::decode(i)).collect(),
release_date: m.release_date.clone(),
}))
}
proxies::media::METADATA_TV_SHOW => {
Some(Metadata::TvShow(TvShowMediaMetadata {
series_title: m.series_title.clone(),
subtitle: m.subtitle.clone(),
season: m.season,
episode: m.episode,
images: m.images.iter().map(|i| Image::decode(i)).collect(),
original_air_date: m.original_air_date.clone(),
}))
}
proxies::media::METADATA_MUSIC => {
Some(Metadata::MusicTrack(MusicTrackMediaMetadata {
album_name: m.album_name.clone(),
title: m.title.clone(),
album_artist: m.album_artist.clone(),
artist: m.artist.clone(),
composer: m.composer.clone(),
track_number: m.track_number,
disc_number: m.disc_number,
images: m.images.iter().map(|i| Image::decode(i)).collect(),
release_date: m.release_date.clone(),
}))
}
proxies::media::METADATA_PHOTO => {
Some(Metadata::Photo(PhotoMediaMetadata {
title: m.title.clone(),
artist: m.artist.clone(),
location: m.location.clone(),
latitude_longitude: m.latitude.zip(m.longitude),
dimensions: m.width.zip(m.height),
creation_date_time: m.creation_date_time.clone(),
}))
}
_ => None,
}),
playback_rate: x.playback_rate,
player_state: PlayerState::from_str(x.player_state.as_ref()).unwrap(),
idle_reason: x
.idle_reason
.as_ref()
.map(|reason| IdleReason::from_str(reason).unwrap()),
current_time: x.current_time,
supported_media_commands: x.supported_media_commands,
}
#[cfg(feature = "json_metadata")]
metadata: m.metadata.clone(),
duration: m.duration,
}),
playback_rate: x.playback_rate,
player_state: PlayerState::from_str(x.player_state.as_ref()).unwrap(),
idle_reason: x
.idle_reason
.as_ref()
.map(|reason| IdleReason::from_str(reason).unwrap()),
current_time: x.current_time,
supported_media_commands: x.supported_media_commands,
});

MediaResponse::Status(Status {
Expand Down