revolt_models/v0/
embeds.rs

1use super::File;
2
3auto_derived!(
4    /// Image positioning and size
5    pub enum ImageSize {
6        /// Show large preview at the bottom of the embed
7        Large,
8        /// Show small preview to the side of the embed
9        Preview,
10    }
11
12    /// Image
13    pub struct Image {
14        /// URL to the original image
15        pub url: String,
16        /// Width of the image
17        pub width: usize,
18        /// Height of the image
19        pub height: usize,
20        /// Positioning and size
21        pub size: ImageSize,
22    }
23
24    /// Video
25    pub struct Video {
26        /// URL to the original video
27        pub url: String,
28        /// Width of the video
29        pub width: usize,
30        /// Height of the video
31        pub height: usize,
32    }
33
34    /// Type of remote Twitch content
35    pub enum TwitchType {
36        Channel,
37        Video,
38        Clip,
39    }
40
41    /// Type of remote Lightspeed.tv content
42    pub enum LightspeedType {
43        Channel,
44    }
45
46    /// Type of remote Bandcamp content
47    pub enum BandcampType {
48        Album,
49        Track,
50    }
51
52    /// Information about special remote content
53    #[serde(tag = "type")]
54    pub enum Special {
55        /// No remote content
56        None,
57        /// Content hint that this contains a GIF
58        ///
59        /// Use metadata to find video or image to play
60        GIF,
61        /// YouTube video
62        YouTube {
63            id: String,
64
65            #[serde(skip_serializing_if = "Option::is_none")]
66            timestamp: Option<String>,
67        },
68        /// Lightspeed.tv stream
69        Lightspeed {
70            content_type: LightspeedType,
71            id: String,
72        },
73        /// Twitch stream or clip
74        Twitch {
75            content_type: TwitchType,
76            id: String,
77        },
78        /// Spotify track
79        Spotify { content_type: String, id: String },
80        /// Soundcloud track
81        Soundcloud,
82        /// Bandcamp track
83        Bandcamp {
84            content_type: BandcampType,
85            id: String,
86        },
87        AppleMusic {
88            album_id: String,
89
90            #[serde(skip_serializing_if = "Option::is_none")]
91            track_id: Option<String>,
92        },
93        /// Streamable Video
94        Streamable { id: String },
95    }
96
97    /// Website metadata
98    pub struct WebsiteMetadata {
99        /// Direct URL to web page
100        #[serde(skip_serializing_if = "Option::is_none")]
101        pub url: Option<String>,
102        /// Original direct URL
103        #[serde(skip_serializing_if = "Option::is_none")]
104        pub original_url: Option<String>,
105        /// Remote content
106        #[serde(skip_serializing_if = "Option::is_none")]
107        pub special: Option<Special>,
108
109        /// Title of website
110        #[serde(skip_serializing_if = "Option::is_none")]
111        pub title: Option<String>,
112        /// Description of website
113        #[serde(skip_serializing_if = "Option::is_none")]
114        pub description: Option<String>,
115        /// Embedded image
116        #[serde(skip_serializing_if = "Option::is_none")]
117        pub image: Option<Image>,
118        /// Embedded video
119        #[serde(skip_serializing_if = "Option::is_none")]
120        pub video: Option<Video>,
121
122        /// Site name
123        #[serde(skip_serializing_if = "Option::is_none")]
124        pub site_name: Option<String>,
125        /// URL to site icon
126        #[serde(skip_serializing_if = "Option::is_none")]
127        pub icon_url: Option<String>,
128        /// CSS Colour
129        #[serde(skip_serializing_if = "Option::is_none")]
130        pub colour: Option<String>,
131    }
132
133    /// Text Embed
134    pub struct Text {
135        /// URL to icon
136        #[serde(skip_serializing_if = "Option::is_none")]
137        pub icon_url: Option<String>,
138        /// URL for title
139        #[serde(skip_serializing_if = "Option::is_none")]
140        pub url: Option<String>,
141        /// Title of text embed
142        #[serde(skip_serializing_if = "Option::is_none")]
143        pub title: Option<String>,
144        /// Description of text embed
145        #[serde(skip_serializing_if = "Option::is_none")]
146        pub description: Option<String>,
147        /// ID of uploaded autumn file
148        #[serde(skip_serializing_if = "Option::is_none")]
149        pub media: Option<File>,
150        /// CSS Colour
151        #[serde(skip_serializing_if = "Option::is_none")]
152        pub colour: Option<String>,
153    }
154
155    /// Embed
156    #[serde(tag = "type")]
157    #[derive(Default)]
158    pub enum Embed {
159        Website(WebsiteMetadata),
160        Image(Image),
161        Video(Video),
162        Text(Text),
163        #[default]
164        None,
165    }
166);
167
168impl WebsiteMetadata {
169    /// Truncate strings in metadata
170    pub fn truncate(&mut self) {
171        if let Some(s) = self.url.as_mut() {
172            s.truncate(256);
173        }
174
175        if let Some(s) = self.original_url.as_mut() {
176            s.truncate(256);
177        }
178
179        if let Some(s) = self.title.as_mut() {
180            s.truncate(100);
181        }
182
183        if let Some(s) = self.description.as_mut() {
184            s.truncate(1000);
185        }
186
187        if let Some(s) = self.site_name.as_mut() {
188            s.truncate(32);
189        }
190
191        if let Some(s) = self.icon_url.as_mut() {
192            s.truncate(256);
193        }
194
195        if let Some(s) = self.colour.as_mut() {
196            s.truncate(32);
197        }
198    }
199
200    /// Check if this is considered "empty"
201    pub fn is_empty(&self) -> bool {
202        (self.title.is_none() || self.title.as_ref().is_some_and(|f| f.is_empty()))
203            && (self.description.is_none()
204                || self.description.as_ref().is_some_and(|f| f.is_empty()))
205            && self.special.is_none()
206            && self.video.is_none()
207            && self.image.is_none()
208    }
209}