rustigram_types/story.rs
1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
4/// A Telegram Story posted by a user or channel.
5pub struct Story {
6 /// The chat that posted the story.
7 pub chat: crate::chat::Chat,
8 /// Unique identifier of the story in that chat.
9 pub id: i64,
10}
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13/// The position and size of a story area overlay.
14pub struct StoryAreaPosition {
15 /// Horizontal position as a percentage of the story width (0–100).
16 pub x_percentage: f64,
17 /// Vertical position as a percentage of the story height (0–100).
18 pub y_percentage: f64,
19 /// Width of the area as a percentage of the story width (0–100).
20 pub width_percentage: f64,
21 /// Height of the area as a percentage of the story height (0–100).
22 pub height_percentage: f64,
23 /// Rotation angle of the area in degrees (0–360).
24 pub rotation_angle: f64,
25 /// Corner radius of the area as a percentage of the shorter side (0–100).
26 pub corner_radius_percentage: f64,
27}
28
29/// The type of interactive area overlaid on a story.
30#[derive(Debug, Clone, Serialize, Deserialize)]
31#[serde(tag = "type", rename_all = "snake_case")]
32pub enum StoryAreaType {
33 /// An area pointing to a geographic location.
34 Location {
35 /// The geographic location.
36 location: crate::chat::Location,
37 /// Optional human-readable address.
38 #[serde(skip_serializing_if = "Option::is_none")]
39 address: Option<LocationAddress>,
40 },
41 /// An area for a suggested emoji reaction.
42 SuggestedReaction {
43 /// The reaction type.
44 reaction_type: crate::message::ReactionType,
45 /// `true` to display a dark background for the reaction.
46 #[serde(skip_serializing_if = "Option::is_none")]
47 is_dark: Option<bool>,
48 /// `true` to mirror the reaction emoji.
49 #[serde(skip_serializing_if = "Option::is_none")]
50 is_flipped: Option<bool>,
51 },
52 /// An area that links to a URL.
53 Link {
54 /// The URL to open.
55 url: String,
56 },
57 /// An area showing weather information.
58 Weather {
59 /// Temperature in Celsius.
60 temperature: f64,
61 /// Weather emoji.
62 emoji: String,
63 /// Background color as an ARGB integer.
64 background_color: i32,
65 },
66 /// An area highlighting a unique gift.
67 UniqueGift {
68 /// Name of the unique gift.
69 name: String,
70 },
71}
72
73/// A human-readable address associated with a location.
74#[derive(Debug, Clone, Serialize, Deserialize)]
75pub struct LocationAddress {
76 /// Two-letter ISO 3166-1 alpha-2 country code.
77 pub country_code: String,
78 /// State or region name.
79 #[serde(skip_serializing_if = "Option::is_none")]
80 pub state: Option<String>,
81 /// City name.
82 #[serde(skip_serializing_if = "Option::is_none")]
83 pub city: Option<String>,
84 /// Street name and number.
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub street: Option<String>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90/// An interactive area overlaid on a story frame.
91///
92/// Areas can represent locations, reactions, links, weather widgets, or
93/// unique gift labels. Used when posting stories via the Business API.
94pub struct StoryArea {
95 /// Position and size of the area.
96 pub position: StoryAreaPosition,
97 /// Type and content of the area.
98 #[serde(rename = "type")]
99 pub kind: StoryAreaType,
100}
101
102// ─── InputStoryContent ────────────────────────────────────────────────────────
103
104/// A photo to post as a story.
105#[derive(Debug, Clone, Serialize, Deserialize)]
106pub struct InputStoryContentPhoto {
107 /// The photo to post.
108 ///
109 /// Must be 1080×1920 pixels, ≤10 MB.
110 /// Pass a `file_id`, HTTP URL, or `"attach://<name>"` for a multipart upload.
111 pub photo: String,
112}
113
114/// A video to post as a story.
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct InputStoryContentVideo {
117 /// The video to post.
118 ///
119 /// Must be 720×1280, streamable H.265, with key frames every second, ≤30 MB.
120 /// Pass a `file_id`, HTTP URL, or `"attach://<name>"` for a multipart upload.
121 pub video: String,
122 /// Precise duration of the video in seconds (0–60).
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub duration: Option<f64>,
125 /// Timestamp in seconds of the frame to use as the static cover. Defaults to `0.0`.
126 #[serde(skip_serializing_if = "Option::is_none")]
127 pub cover_frame_timestamp: Option<f64>,
128 /// Pass `true` if the video has no sound.
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub is_animation: Option<bool>,
131}
132
133/// The content of a story to post or edit.
134///
135/// Pass to [`postStory`](https://core.telegram.org/bots/api#poststory) and
136/// [`editStory`](https://core.telegram.org/bots/api#editstory) as a
137/// `serde_json::Value` — use `serde_json::to_value(&content)`.
138#[derive(Debug, Clone, Serialize, Deserialize)]
139#[serde(tag = "type", rename_all = "snake_case")]
140pub enum InputStoryContent {
141 /// A photo story.
142 Photo(InputStoryContentPhoto),
143 /// A video story.
144 Video(InputStoryContentVideo),
145}