reddit_rs/models/
media.rs

1use iri_string::types::{IriAbsoluteString, IriString};
2use serde::{Deserialize, Serialize};
3
4mod oembed;
5
6use crate::models::media::oembed::OEmbed;
7
8#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
9pub struct MediaEmbed {
10    content: String,
11    width: u16,
12    scrolling: bool,
13    media_domain_url: Option<IriString>,
14    height: u16,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
18#[serde(untagged)]
19pub enum Media {
20    OEmbed(OEmbed),
21    RedditVideo { reddit_video: RedditVideo },
22}
23
24#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
25#[serde(rename_all = "snake_case")]
26pub struct RedditVideo {
27    pub bitrate_kbps: u32,
28    pub fallback_url: IriAbsoluteString,
29    pub height: u32,
30    pub width: u32,
31    pub scrubber_media_url: IriAbsoluteString,
32    pub dash_url: IriAbsoluteString,
33    pub duration: u32,
34    pub hls_url: IriAbsoluteString,
35    pub is_gif: bool,
36    pub transcoding_status: TranscodingStatus,
37}
38
39#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
40pub struct MediaThumbnail {
41    #[serde(rename = "thumbnail_width")]
42    width: u16,
43    #[serde(rename = "thumbnail_height")]
44    height: u16,
45    #[serde(rename = "thumbnail_url")]
46    url: IriAbsoluteString,
47}
48
49#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
50#[serde(rename_all = "snake_case")]
51pub enum TranscodingStatus {
52    Completed,
53}
54
55#[cfg(test)]
56mod test_media {
57    #![allow(clippy::pedantic)]
58
59    use super::*;
60    use crate::models::media::oembed::{
61        streamable, OEmbedData, OEmbedProvider, OEmbedType, OEmbedVersion,
62    };
63
64    #[test]
65    fn test_youtube() {
66        let media = Media::OEmbed(OEmbed::YouTube(OEmbedData {
67            height: Default::default(),
68            width: Default::default(),
69            html: Default::default(),
70            provider: OEmbedProvider {
71                name: Default::default(),
72                url: "https://www.reddit.com/".parse().unwrap(),
73            },
74            version: OEmbedVersion::V1_0,
75            thumbnail: Some(MediaThumbnail {
76                width: Default::default(),
77                url: "https://www.reddit.com/".parse().unwrap(),
78                height: Default::default(),
79            }),
80            ty: OEmbedType::Video,
81            vendor_specific_data: oembed::youtube::YouTube {
82                title: Default::default(),
83                author_name: Default::default(),
84                author_url: "https://www.reddit.com/".parse().unwrap(),
85            },
86        }));
87
88        let _json = serde_json::to_string_pretty(&media).unwrap();
89    }
90
91    #[test]
92    fn test_streamable() {
93        let media = Media::OEmbed(OEmbed::Streamable(OEmbedData {
94            height: Default::default(),
95            width: Default::default(),
96            html: Default::default(),
97            provider: OEmbedProvider {
98                name: Default::default(),
99                url: "https://www.reddit.com/".parse().unwrap(),
100            },
101            version: OEmbedVersion::V1_0,
102            thumbnail: Some(MediaThumbnail {
103                width: Default::default(),
104                url: "https://www.reddit.com/".parse().unwrap(),
105                height: Default::default(),
106            }),
107            ty: OEmbedType::Video,
108            vendor_specific_data: streamable::Streamable {
109                title: Default::default(),
110                description: Default::default(),
111            },
112        }));
113
114        let json = serde_json::to_string_pretty(&media).unwrap();
115
116        // println!("{}", json);
117
118        let json = r#"
119        {
120            "oembed": {
121              "provider_url": "https://streamable.com",
122              "description": "Watch this video on Streamable.",
123              "title": "Streamable Video",
124              "thumbnail_width": 1280,
125              "height": 338,
126              "width": 600,
127              "html": "<iframe class=\"embedly-embed\" src=\"https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fstreamable.com%2Fo%2Fgixxf0&display_name=Streamable&url=https%3A%2F%2Fstreamable.com%2Fgixxf0&image=https%3A%2F%2Fcdn-cf-east.streamable.com%2Fimage%2Fgixxf0.jpg%3FExpires%3D1634216820%26Signature%3DdoMgebEgi-eHwDrMcGIUyMTfOSBbA5tjLo9PtT4D4tjPPL3oLGzOGEEaro3kGUhP6L-0PplxBbHiuNBoFGDiKMJv0KWMBQ4VEdLSIQ0wB78%7EPe4kYENxS3gDtYk%7EUjUktnu3fFLeTCLCYTFVNm7e1mEqpIrB0yB6b9RAQ9igkaa2jhpRHceh0yOvQgXe-a-yg4VaDMPHHE4XAYHwzhO68s7066cWtvgj-Uci1PA%7E5W5qt7FqFDPT3FAmLgGbKopfQq-y8mKfTHu7KOfWVQgwEuEnHGe9I10cVW7e%7EMyfO9PY5oDzczhH7ffGU1fnDRXTQ2GGjhdkV2joVOgQ4CuX2Q__%26Key-Pair-Id%3DAPKAIEYUVEN4EVB2OKEQ&key=ed8fa8699ce04833838e66ce79ba05f1&type=text%2Fhtml&schema=streamable\" width=\"600\" height=\"338\" scrolling=\"no\" title=\"Streamable embed\" frameborder=\"0\" allow=\"autoplay; fullscreen\" allowfullscreen=\"true\"></iframe>",
128              "version": "1.0",
129              "provider_name": "Streamable",
130              "thumbnail_url": "https://cdn-cf-east.streamable.com/image/gixxf0.jpg?Expires=1634216820&Signature=doMgebEgi-eHwDrMcGIUyMTfOSBbA5tjLo9PtT4D4tjPPL3oLGzOGEEaro3kGUhP6L-0PplxBbHiuNBoFGDiKMJv0KWMBQ4VEdLSIQ0wB78~Pe4kYENxS3gDtYk~UjUktnu3fFLeTCLCYTFVNm7e1mEqpIrB0yB6b9RAQ9igkaa2jhpRHceh0yOvQgXe-a-yg4VaDMPHHE4XAYHwzhO68s7066cWtvgj-Uci1PA~5W5qt7FqFDPT3FAmLgGbKopfQq-y8mKfTHu7KOfWVQgwEuEnHGe9I10cVW7e~MyfO9PY5oDzczhH7ffGU1fnDRXTQ2GGjhdkV2joVOgQ4CuX2Q__&Key-Pair-Id=APKAIEYUVEN4EVB2OKEQ",
131              "type": "video",
132              "thumbnail_height": 720
133            },
134            "type": "streamable.com"
135          }"#;
136
137        dbg!(serde_json::from_str::<Media>(json).unwrap());
138    }
139
140    #[test]
141    fn test_twitter() {
142        let json = r##"
143        {
144            "type": "twitter.com",
145            "oembed": {
146                "version": "1.0",
147                "url": "https://twitter.com/LordKebun/status/1447420243010281473",
148                "author_name": "Kebun",
149                "height": null,
150                "width": 350,
151                "html": "\u003Cblockquote class=\"twitter-video\"\u003E\u003Cp lang=\"en\" dir=\"ltr\"\u003ERate my Ramee RP Impersonation. \u003Ca href=\"https://t.co/vipSaqsrDe\"\u003Epic.twitter.com/vipSaqsrDe\u003C/a\u003E\u003C/p\u003E\u0026mdash; Kebun (@LordKebun) \u003Ca href=\"https://twitter.com/LordKebun/status/1447420243010281473?ref_src=twsrc%5Etfw\"\u003EOctober 11, 2021\u003C/a\u003E\u003C/blockquote\u003E\n\u003Cscript async src=\"https://platform.twitter.com/widgets.js\" charset=\"utf-8\"\u003E\u003C/script\u003E\n",
152                "author_url": "https://twitter.com/LordKebun",
153                "cache_age": 3153600000,
154                "type": "rich",
155                "provider_url": "https://twitter.com",
156                "provider_name": "Twitter"
157            }
158        }"##;
159
160        dbg!(serde_json::from_str::<Media>(json).unwrap());
161    }
162
163    #[test]
164    fn test_oembed_bandcamp() {
165        let json = r##"{
166            "type": "futurespiritualman.bandcamp.com",
167            "oembed": {
168              "provider_url": "http://bandcamp.com",
169              "description": "beaf by futurespiritualman, released 01 January 2021 1. b-horn ft._Lil Peter_&amp;_Frank.mp3 2. funk_part_2._ft_FUNKEYMAN_supreme.mp3 3. the_toop_ft._Lil_Peter.mp3 4. i_eat_rocks.mp3 5. dog_walker_ft._Gizzer_NP_.mp3 6. beefstew_ft._SuizideDeth.mp3 7. going_to_jail_part_II.mp3 8. breats_ft._Lil_Peter.mp3 9. my_truck_ft._BigK2000.mp3 10. balls2man.mp3 11. FIVE_thefourtyninerswinin2075.mp3 12. good_he.mp3 13. i_eat_rocks.mp3 14. truck_(_truck_truck_truck_truck_).mp3 15. my_truck_part_2._ft._Frank(version_1_).mp3 16. cum)lord__.mp3 17. joe.mp3 18. truck_4_(version2).mp3 19. i_love_youft.__Frank.mp3 20. RAP_ft._thelegendsupreme.mp3 21.",
170              "title": "beaf, by futurespiritualman",
171              "type": "rich",
172              "thumbnail_width": 700,
173              "height": 467,
174              "width": 350,
175              "html": "<iframe class=\"embedly-embed\" src=\"https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fbandcamp.com%2FEmbeddedPlayer%2Fv%3D2%2Falbum%3D1766047770%2Fsize%3Dlarge%2Flinkcol%3D0084B4%2Fnotracklist%3Dtrue%2Ftwittercard%3Dtrue%2F&display_name=BandCamp&url=https%3A%2F%2Ffuturespiritualman.bandcamp.com%2Falbum%2Fbeaf&image=https%3A%2F%2Ff4.bcbits.com%2Fimg%2Fa2778328046_5.jpg&key=ed8fa8699ce04833838e66ce79ba05f1&type=text%2Fhtml&schema=bandcamp\" width=\"350\" height=\"467\" scrolling=\"no\" title=\"BandCamp embed\" frameborder=\"0\" allow=\"autoplay; fullscreen\" allowfullscreen=\"true\"></iframe>",
176              "version": "1.0",
177              "provider_name": "BandCamp",
178              "thumbnail_url": "https://f4.bcbits.com/img/a2778328046_5.jpg",
179              "thumbnail_height": 700
180            }
181          }"##;
182
183        dbg!(serde_json::from_str::<Media>(json).unwrap());
184    }
185}