Skip to main content

rustigram_types/
file.rs

1use serde::{Deserialize, Serialize};
2
3/// One size of a photo or file thumbnail.
4#[derive(Debug, Clone, Serialize, Deserialize)]
5pub struct PhotoSize {
6    /// Telegram file identifier.
7    pub file_id: String,
8    /// Unique file identifier, stable across bots and time.
9    pub file_unique_id: String,
10    /// Photo width in pixels.
11    pub width: u32,
12    /// Photo height in pixels.
13    pub height: u32,
14    /// File size in bytes.
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub file_size: Option<u64>,
17}
18
19/// This object represents a file ready to be downloaded.
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct File {
22    /// Telegram file identifier.
23    pub file_id: String,
24    /// Unique file identifier, stable across bots and time.
25    pub file_unique_id: String,
26    /// File size in bytes.
27    #[serde(skip_serializing_if = "Option::is_none")]
28    pub file_size: Option<u64>,
29    /// Relative file path — use with
30    /// `https://api.telegram.org/file/bot<TOKEN>/<file_path>`.
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub file_path: Option<String>,
33}
34
35impl File {
36    /// Constructs the full download URL for this file.
37    #[must_use]
38    pub fn url(&self, token: &str) -> Option<String> {
39        self.file_path
40            .as_ref()
41            .map(|path| format!("https://api.telegram.org/file/bot{token}/{path}"))
42    }
43}
44
45/// Audio file to be treated as music.
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct Audio {
48    /// Telegram file identifier.
49    pub file_id: String,
50    /// Unique file identifier, stable across bots and time.
51    pub file_unique_id: String,
52    /// Duration of the audio in seconds.
53    pub duration: u32,
54    /// Performer of the audio as defined by the sender or audio tags.
55    #[serde(skip_serializing_if = "Option::is_none")]
56    pub performer: Option<String>,
57    /// Title of the audio as defined by the sender or audio tags.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub title: Option<String>,
60    /// Original filename as defined by the sender.
61    #[serde(skip_serializing_if = "Option::is_none")]
62    pub file_name: Option<String>,
63    /// MIME type of the audio.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub mime_type: Option<String>,
66    /// File size in bytes.
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub file_size: Option<u64>,
69    /// Thumbnail of the album cover.
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub thumbnail: Option<PhotoSize>,
72}
73
74/// General file (not photo, voice, audio or video).
75#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct Document {
77    /// Telegram file identifier.
78    pub file_id: String,
79    /// Unique file identifier, stable across bots and time.
80    pub file_unique_id: String,
81    /// Document thumbnail.
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub thumbnail: Option<PhotoSize>,
84    /// Original filename as defined by the sender.
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub file_name: Option<String>,
87    /// MIME type of the document.
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub mime_type: Option<String>,
90    /// File size in bytes.
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub file_size: Option<u64>,
93}
94
95/// Video file.
96#[derive(Debug, Clone, Serialize, Deserialize)]
97pub struct Video {
98    /// Telegram file identifier.
99    pub file_id: String,
100    /// Unique file identifier, stable across bots and time.
101    pub file_unique_id: String,
102    /// Video width in pixels.
103    pub width: u32,
104    /// Video height in pixels.
105    pub height: u32,
106    /// Duration of the video in seconds.
107    pub duration: u32,
108    /// Video thumbnail.
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub thumbnail: Option<PhotoSize>,
111    /// Cover image for the video.
112    #[serde(skip_serializing_if = "Option::is_none")]
113    pub cover: Option<Vec<PhotoSize>>,
114    /// Start timestamp for video chapters.
115    #[serde(skip_serializing_if = "Option::is_none")]
116    pub start_timestamp: Option<u32>,
117    /// Original filename.
118    #[serde(skip_serializing_if = "Option::is_none")]
119    pub file_name: Option<String>,
120    /// MIME type of the video.
121    #[serde(skip_serializing_if = "Option::is_none")]
122    pub mime_type: Option<String>,
123    /// File size in bytes.
124    #[serde(skip_serializing_if = "Option::is_none")]
125    pub file_size: Option<u64>,
126}
127
128/// Animation file (GIF or H.264/MPEG-4 AVC, no sound).
129#[derive(Debug, Clone, Serialize, Deserialize)]
130pub struct Animation {
131    /// Telegram file identifier.
132    pub file_id: String,
133    /// Unique file identifier, stable across bots and time.
134    pub file_unique_id: String,
135    /// Animation width in pixels.
136    pub width: u32,
137    /// Animation height in pixels.
138    pub height: u32,
139    /// Duration of the animation in seconds.
140    pub duration: u32,
141    /// Animation thumbnail.
142    #[serde(skip_serializing_if = "Option::is_none")]
143    pub thumbnail: Option<PhotoSize>,
144    /// Original filename as defined by the sender.
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub file_name: Option<String>,
147    /// MIME type of the animation.
148    #[serde(skip_serializing_if = "Option::is_none")]
149    pub mime_type: Option<String>,
150    /// File size in bytes.
151    #[serde(skip_serializing_if = "Option::is_none")]
152    pub file_size: Option<u64>,
153}
154
155/// Voice note (OGG/OPUS audio).
156#[derive(Debug, Clone, Serialize, Deserialize)]
157pub struct Voice {
158    /// Telegram file identifier.
159    pub file_id: String,
160    /// Unique file identifier, stable across bots and time.
161    pub file_unique_id: String,
162    /// Duration of the voice note in seconds.
163    pub duration: u32,
164    /// MIME type of the voice note.
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub mime_type: Option<String>,
167    /// File size in bytes.
168    #[serde(skip_serializing_if = "Option::is_none")]
169    pub file_size: Option<u64>,
170}
171
172/// Rounded-square MPEG4 video note.
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct VideoNote {
175    /// Telegram file identifier.
176    pub file_id: String,
177    /// Unique file identifier, stable across bots and time.
178    pub file_unique_id: String,
179    /// Video width and height (diameter of the circle).
180    pub length: u32,
181    /// Duration of the video in seconds.
182    pub duration: u32,
183    /// Video thumbnail.
184    #[serde(skip_serializing_if = "Option::is_none")]
185    pub thumbnail: Option<PhotoSize>,
186    /// File size in bytes.
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub file_size: Option<u64>,
189}
190
191/// Represents a file to be sent.
192#[derive(Debug, Clone)]
193pub enum InputFile {
194    /// Send an existing file by its Telegram `file_id`.
195    FileId(String),
196    /// Send a file from a URL (photo ≤5 MB, others ≤20 MB).
197    Url(String),
198    /// Upload new file bytes. The `filename` is sent in the Content-Disposition header.
199    Bytes {
200        /// Original filename sent in the Content-Disposition header.
201        filename: String,
202        /// Raw file bytes.
203        data: Vec<u8>,
204        /// MIME type of the file.
205        mime_type: String,
206    },
207    /// Reference an already-included multipart attachment by `attach://<name>`.
208    Attach(String),
209}
210
211impl InputFile {
212    /// Returns the string representation for JSON/query-string fields.
213    #[must_use]
214    pub fn as_str(&self) -> &str {
215        match self {
216            Self::FileId(id) => id,
217            Self::Url(url) => url,
218            Self::Attach(name) => name,
219            Self::Bytes { filename, .. } => filename,
220        }
221    }
222
223    /// Returns `true` if this variant needs multipart form upload.
224    #[must_use]
225    pub fn requires_multipart(&self) -> bool {
226        matches!(self, Self::Bytes { .. })
227    }
228}
229
230/// Encrypted passport file.
231#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct PassportFile {
233    /// Telegram file identifier.
234    pub file_id: String,
235    /// Unique file identifier, stable across bots and time.
236    pub file_unique_id: String,
237    /// File size in bytes.
238    pub file_size: u64,
239    /// Unix timestamp when the file was uploaded.
240    pub file_date: i64,
241}