starweaver_model/media/
types.rs1use serde::{Deserialize, Serialize};
4
5#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
7#[serde(rename_all = "snake_case")]
8pub enum MediaKind {
9 Png,
11 Jpeg,
13 Gif,
15 Webp,
17 Mp4,
19 Webm,
21 Unknown,
23}
24
25impl MediaKind {
26 #[must_use]
28 pub const fn media_type(self) -> Option<&'static str> {
29 match self {
30 Self::Png => Some("image/png"),
31 Self::Jpeg => Some("image/jpeg"),
32 Self::Gif => Some("image/gif"),
33 Self::Webp => Some("image/webp"),
34 Self::Mp4 => Some("video/mp4"),
35 Self::Webm => Some("video/webm"),
36 Self::Unknown => None,
37 }
38 }
39
40 #[must_use]
42 pub const fn can_be_animated(self) -> bool {
43 matches!(self, Self::Gif | Self::Webp)
44 }
45
46 #[must_use]
48 pub const fn is_image(self) -> bool {
49 matches!(self, Self::Png | Self::Jpeg | Self::Gif | Self::Webp)
50 }
51
52 #[must_use]
54 pub const fn is_video(self) -> bool {
55 matches!(self, Self::Mp4 | Self::Webm)
56 }
57}
58
59#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
61pub struct ImageDimensions {
62 pub width: u32,
64 pub height: u32,
66}
67
68#[allow(clippy::struct_excessive_bools)]
70#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
71pub struct MediaPolicy {
72 #[serde(default, skip_serializing_if = "Option::is_none")]
74 pub max_inline_base64_bytes: Option<usize>,
75 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub max_image_dimension: Option<u32>,
78 #[serde(default, skip_serializing_if = "Option::is_none")]
80 pub max_images: Option<usize>,
81 #[serde(default, skip_serializing_if = "Option::is_none")]
83 pub max_videos: Option<usize>,
84 pub allow_gif: bool,
86 pub allow_webp: bool,
88 pub allow_images: bool,
90 pub allow_videos: bool,
92 pub allow_documents: bool,
94}
95
96impl Default for MediaPolicy {
97 fn default() -> Self {
98 Self {
99 max_inline_base64_bytes: None,
100 max_image_dimension: None,
101 max_images: None,
102 max_videos: None,
103 allow_gif: true,
104 allow_webp: true,
105 allow_images: true,
106 allow_videos: true,
107 allow_documents: true,
108 }
109 }
110}
111
112#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
114pub struct ParsedDataUrl {
115 pub media_type: String,
117 pub data: Vec<u8>,
119}
120
121#[must_use]
123pub fn detect_media_kind(bytes: &[u8]) -> MediaKind {
124 if bytes.starts_with(b"\x89PNG\r\n\x1a\n") {
125 return MediaKind::Png;
126 }
127 if bytes.starts_with(b"\xff\xd8\xff") {
128 return MediaKind::Jpeg;
129 }
130 if bytes.starts_with(b"GIF87a") || bytes.starts_with(b"GIF89a") {
131 return MediaKind::Gif;
132 }
133 if bytes.len() >= 12 && bytes.starts_with(b"RIFF") && &bytes[8..12] == b"WEBP" {
134 return MediaKind::Webp;
135 }
136 if bytes.len() >= 12 && &bytes[4..8] == b"ftyp" {
137 return MediaKind::Mp4;
138 }
139 if bytes.starts_with(b"\x1a\x45\xdf\xa3") {
140 return MediaKind::Webm;
141 }
142 MediaKind::Unknown
143}