Skip to main content

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            creator_name: Option<String>,
65            creator_url: Option<String>,
66
67            #[serde(skip_serializing_if = "Option::is_none")]
68            timestamp: Option<String>,
69        },
70        /// Lightspeed.tv stream
71        Lightspeed {
72            content_type: LightspeedType,
73            id: String,
74        },
75        /// Twitch stream or clip
76        Twitch {
77            content_type: TwitchType,
78            id: String,
79        },
80        /// Spotify track
81        Spotify { content_type: String, id: String },
82        /// Soundcloud track
83        Soundcloud,
84        /// Bandcamp track
85        Bandcamp {
86            content_type: BandcampType,
87            id: String,
88        },
89        AppleMusic {
90            album_id: String,
91
92            #[serde(skip_serializing_if = "Option::is_none")]
93            track_id: Option<String>,
94        },
95        /// Streamable Video
96        Streamable { id: String },
97    }
98
99    /// Website metadata
100    pub struct WebsiteMetadata {
101        /// Direct URL to web page
102        #[serde(skip_serializing_if = "Option::is_none")]
103        pub url: Option<String>,
104        /// Original direct URL
105        #[serde(skip_serializing_if = "Option::is_none")]
106        pub original_url: Option<String>,
107        /// Remote content
108        #[serde(skip_serializing_if = "Option::is_none")]
109        pub special: Option<Special>,
110
111        /// Title of website
112        #[serde(skip_serializing_if = "Option::is_none")]
113        pub title: Option<String>,
114        /// Description of website
115        #[serde(skip_serializing_if = "Option::is_none")]
116        pub description: Option<String>,
117        /// Embedded image
118        #[serde(skip_serializing_if = "Option::is_none")]
119        pub image: Option<Image>,
120        /// Embedded video
121        #[serde(skip_serializing_if = "Option::is_none")]
122        pub video: Option<Video>,
123
124        /// Site name
125        #[serde(skip_serializing_if = "Option::is_none")]
126        pub site_name: Option<String>,
127        /// URL to site icon
128        #[serde(skip_serializing_if = "Option::is_none")]
129        pub icon_url: Option<String>,
130        /// CSS Colour
131        #[serde(skip_serializing_if = "Option::is_none")]
132        pub colour: Option<String>,
133    }
134
135    /// Text Embed
136    pub struct Text {
137        /// URL to icon
138        #[serde(skip_serializing_if = "Option::is_none")]
139        pub icon_url: Option<String>,
140        /// URL for title
141        #[serde(skip_serializing_if = "Option::is_none")]
142        pub url: Option<String>,
143        /// Title of text embed
144        #[serde(skip_serializing_if = "Option::is_none")]
145        pub title: Option<String>,
146        /// Description of text embed
147        #[serde(skip_serializing_if = "Option::is_none")]
148        pub description: Option<String>,
149        /// ID of uploaded autumn file
150        #[serde(skip_serializing_if = "Option::is_none")]
151        pub media: Option<File>,
152        /// CSS Colour
153        #[serde(skip_serializing_if = "Option::is_none")]
154        pub colour: Option<String>,
155    }
156
157    /// Embed
158    #[serde(tag = "type")]
159    #[derive(Default)]
160    pub enum Embed {
161        Website(WebsiteMetadata),
162        Image(Image),
163        Video(Video),
164        Text(Text),
165        #[default]
166        None,
167    }
168);
169
170impl WebsiteMetadata {
171    /// Truncate strings in metadata
172    pub fn truncate(&mut self) {
173        if let Some(s) = self.url.as_mut() {
174            s.truncate(256);
175        }
176
177        if let Some(s) = self.original_url.as_mut() {
178            s.truncate(256);
179        }
180
181        if let Some(s) = self.title.as_mut() {
182            s.truncate(100);
183        }
184
185        if let Some(s) = self.description.as_mut() {
186            s.truncate(1000);
187        }
188
189        if let Some(s) = self.site_name.as_mut() {
190            s.truncate(32);
191        }
192
193        if let Some(s) = self.icon_url.as_mut() {
194            s.truncate(256);
195        }
196
197        if let Some(s) = self.colour.as_mut() {
198            s.truncate(32);
199        }
200    }
201
202    /// Check if this is considered "empty"
203    pub fn is_empty(&self) -> bool {
204        (self.title.is_none() || self.title.as_ref().is_some_and(|f| f.is_empty()))
205            && (self.description.is_none()
206                || self.description.as_ref().is_some_and(|f| f.is_empty()))
207            && self.special.is_none()
208            && self.video.is_none()
209            && self.image.is_none()
210    }
211}