diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs
index 6a64a18f..4a5583f3 100644
--- a/matrix_sdk/src/client.rs
+++ b/matrix_sdk/src/client.rs
@@ -45,7 +45,7 @@ use matrix_sdk_base::{
deserialized_responses::SyncResponse,
events::AnyMessageEventContent,
identifiers::MxcUri,
- media::{MediaFormat, MediaRequest, MediaType},
+ media::{MediaEventContent, MediaFormat, MediaRequest, MediaThumbnailSize, MediaType},
BaseClient, BaseClientConfig, SendAccessToken, Session, Store,
};
use mime::{self, Mime};
@@ -2503,7 +2503,7 @@ impl Client {
let content = {
let mut cursor = Cursor::new(content);
let mut reader =
- AttachmentDecryptor::new(&mut cursor, file.clone().into())?;
+ AttachmentDecryptor::new(&mut cursor, file.as_ref().clone().into())?;
let mut decrypted = Vec::new();
reader.read_to_end(&mut decrypted)?;
@@ -2557,6 +2557,120 @@ impl Client {
pub async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()> {
Ok(self.base_client.store().remove_media_content_for_uri(&uri).await?)
}
+
+ /// Get the file of the given media event content.
+ ///
+ /// If the content is encrypted and encryption is enabled, the content will
+ /// be decrypted.
+ ///
+ /// Returns `Ok(None)` if the event content has no file.
+ ///
+ /// This is a convenience method that calls the
+ /// [`get_media_content`](#method.get_media_content) method.
+ ///
+ /// # Arguments
+ ///
+ /// * `event_content` - The media event content.
+ ///
+ /// * `use_cache` - If we should use the media cache for this file.
+ pub async fn get_file(
+ &self,
+ event_content: impl MediaEventContent,
+ use_cache: bool,
+ ) -> Result>> {
+ if let Some(media_type) = event_content.file() {
+ Ok(Some(
+ self.get_media_content(
+ &MediaRequest { media_type, format: MediaFormat::File },
+ use_cache,
+ )
+ .await?,
+ ))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Remove the file of the given media event content from the cache.
+ ///
+ /// This is a convenience method that calls the
+ /// [`remove_media_content`](#method.remove_media_content) method.
+ ///
+ /// # Arguments
+ ///
+ /// * `event_content` - The media event content.
+ pub async fn remove_file(&self, event_content: impl MediaEventContent) -> Result<()> {
+ if let Some(media_type) = event_content.file() {
+ self.remove_media_content(&MediaRequest { media_type, format: MediaFormat::File })
+ .await?
+ }
+
+ Ok(())
+ }
+
+ /// Get a thumbnail of the given media event content.
+ ///
+ /// If the content is encrypted and encryption is enabled, the content will
+ /// be decrypted.
+ ///
+ /// Returns `Ok(None)` if the event content has no thumbnail.
+ ///
+ /// This is a convenience method that calls the
+ /// [`get_media_content`](#method.get_media_content) method.
+ ///
+ /// # Arguments
+ ///
+ /// * `event_content` - The media event content.
+ ///
+ /// * `size` - The _desired_ size of the thumbnail. The actual thumbnail may
+ /// not match the size specified.
+ ///
+ /// * `use_cache` - If we should use the media cache for this thumbnail.
+ pub async fn get_thumbnail(
+ &self,
+ event_content: impl MediaEventContent,
+ size: MediaThumbnailSize,
+ use_cache: bool,
+ ) -> Result >> {
+ if let Some(media_type) = event_content.thumbnail() {
+ Ok(Some(
+ self.get_media_content(
+ &MediaRequest { media_type, format: MediaFormat::Thumbnail(size) },
+ use_cache,
+ )
+ .await?,
+ ))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Remove the thumbnail of the given media event content from the cache.
+ ///
+ /// This is a convenience method that calls the
+ /// [`remove_media_content`](#method.remove_media_content) method.
+ ///
+ /// # Arguments
+ ///
+ /// * `event_content` - The media event content.
+ ///
+ /// * `size` - The _desired_ size of the thumbnail. Must match the size
+ /// requested with [`get_thumbnail`](#method.get_thumbnail).
+ pub async fn remove_thumbnail(
+ &self,
+ event_content: impl MediaEventContent,
+ size: MediaThumbnailSize,
+ ) -> Result<()> {
+ if let Some(media_type) = event_content.file() {
+ self.remove_media_content(&MediaRequest {
+ media_type,
+ format: MediaFormat::Thumbnail(size),
+ })
+ .await?
+ }
+
+ Ok(())
+ }
}
#[cfg(test)]
diff --git a/matrix_sdk_base/src/media.rs b/matrix_sdk_base/src/media.rs
index 3e8f0939..9d075e63 100644
--- a/matrix_sdk_base/src/media.rs
+++ b/matrix_sdk_base/src/media.rs
@@ -1,8 +1,19 @@
//! Common types for [media content](https://matrix.org/docs/spec/client_server/r0.6.1#id66).
use matrix_sdk_common::{
- api::r0::media::get_content_thumbnail::Method, events::room::EncryptedFile,
- identifiers::MxcUri, UInt,
+ api::r0::media::get_content_thumbnail::Method,
+ events::{
+ room::{
+ message::{
+ AudioMessageEventContent, FileMessageEventContent, ImageMessageEventContent,
+ LocationMessageEventContent, VideoMessageEventContent,
+ },
+ EncryptedFile,
+ },
+ sticker::StickerEventContent,
+ },
+ identifiers::MxcUri,
+ UInt,
};
const UNIQUE_SEPARATOR: &str = "_";
@@ -61,7 +72,7 @@ pub enum MediaType {
Uri(MxcUri),
/// An encrypted media content.
- Encrypted(EncryptedFile),
+ Encrypted(Box),
}
impl UniqueKey for MediaType {
@@ -88,3 +99,118 @@ impl UniqueKey for MediaRequest {
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()))
+ }
+ })
+ }
+}