//! Common types for [media content](https://matrix.org/docs/spec/client_server/r0.6.1#id66). use ruma::{ api::client::r0::media::get_content_thumbnail::Method, events::{ room::{ message::{ AudioMessageEventContent, FileMessageEventContent, ImageMessageEventContent, LocationMessageEventContent, VideoMessageEventContent, }, EncryptedFile, }, sticker::StickerEventContent, }, MxcUri, UInt, }; const UNIQUE_SEPARATOR: &str = "_"; /// A trait to uniquely identify values of the same type. pub trait UniqueKey { /// A string that uniquely identifies `Self` compared to other values of /// the same type. fn unique_key(&self) -> String; } /// The requested format of a media file. #[derive(Clone, Debug)] pub enum MediaFormat { /// The file that was uploaded. File, /// A thumbnail of the file that was uploaded. Thumbnail(MediaThumbnailSize), } impl UniqueKey for MediaFormat { fn unique_key(&self) -> String { match self { Self::File => "file".into(), Self::Thumbnail(size) => size.unique_key(), } } } /// The requested size of a media thumbnail. #[derive(Clone, Debug)] pub struct MediaThumbnailSize { /// The desired resizing method. pub method: Method, /// The desired width of the thumbnail. The actual thumbnail may not match /// the size specified. pub width: UInt, /// The desired height of the thumbnail. The actual thumbnail may not match /// the size specified. pub height: UInt, } impl UniqueKey for MediaThumbnailSize { fn unique_key(&self) -> String { format!("{}{}{}x{}", self.method, UNIQUE_SEPARATOR, self.width, self.height) } } /// A request for media data. #[derive(Clone, Debug)] pub enum MediaType { /// A media content URI. Uri(MxcUri), /// An encrypted media content. Encrypted(Box), } impl UniqueKey for MediaType { fn unique_key(&self) -> String { match self { Self::Uri(uri) => uri.to_string(), Self::Encrypted(file) => file.url.to_string(), } } } /// A request for media data. #[derive(Clone, Debug)] pub struct MediaRequest { /// The type of the media file. pub media_type: MediaType, /// The requested format of the media data. pub format: MediaFormat, } impl UniqueKey for MediaRequest { fn unique_key(&self) -> String { format!("{}{}{}", self.media_type.unique_key(), UNIQUE_SEPARATOR, self.format.unique_key()) } } /// Trait for media event content. pub trait MediaEventContent { /// Get the type of the file for `Self`. /// /// Returns `None` if `Self` has no file. fn file(&self) -> Option; /// Get the type of the thumbnail for `Self`. /// /// Returns `None` if `Self` has no thumbnail. fn thumbnail(&self) -> Option; } impl MediaEventContent for StickerEventContent { fn file(&self) -> Option { Some(MediaType::Uri(self.url.clone())) } fn thumbnail(&self) -> Option { None } } impl MediaEventContent for AudioMessageEventContent { fn file(&self) -> Option { self.url .as_ref() .map(|uri| MediaType::Uri(uri.clone())) .or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone()))) } fn thumbnail(&self) -> Option { None } } impl MediaEventContent for FileMessageEventContent { fn file(&self) -> Option { self.url .as_ref() .map(|uri| MediaType::Uri(uri.clone())) .or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone()))) } fn thumbnail(&self) -> Option { self.info.as_ref().and_then(|info| { if let Some(uri) = info.thumbnail_url.as_ref() { Some(MediaType::Uri(uri.clone())) } else { info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone())) } }) } } impl MediaEventContent for ImageMessageEventContent { fn file(&self) -> Option { self.url .as_ref() .map(|uri| MediaType::Uri(uri.clone())) .or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone()))) } fn thumbnail(&self) -> Option { self.info .as_ref() .and_then(|info| { if let Some(uri) = info.thumbnail_url.as_ref() { Some(MediaType::Uri(uri.clone())) } else { info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone())) } }) .or_else(|| self.url.as_ref().map(|uri| MediaType::Uri(uri.clone()))) } } impl MediaEventContent for VideoMessageEventContent { fn file(&self) -> Option { self.url .as_ref() .map(|uri| MediaType::Uri(uri.clone())) .or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone()))) } fn thumbnail(&self) -> Option { self.info .as_ref() .and_then(|info| { if let Some(uri) = info.thumbnail_url.as_ref() { Some(MediaType::Uri(uri.clone())) } else { info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone())) } }) .or_else(|| self.url.as_ref().map(|uri| MediaType::Uri(uri.clone()))) } } impl MediaEventContent for LocationMessageEventContent { fn file(&self) -> Option { None } fn thumbnail(&self) -> Option { self.info.as_ref().and_then(|info| { if let Some(uri) = info.thumbnail_url.as_ref() { Some(MediaType::Uri(uri.clone())) } else { info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone())) } }) } }