ytextract/video/
related.rs1use crate::youtube::{
4 self,
5 next::{
6 CompactMovieRenderer, CompactPlaylistRenderer, CompactRadioRenderer, CompactVideoRenderer,
7 },
8 parse_length,
9};
10
11use std::fmt::Debug;
12
13#[derive(Clone)]
15pub struct Video(pub(super) CompactVideoRenderer, pub(super) crate::Client);
16
17impl Video {
18 pub fn id(&self) -> super::Id {
20 self.0.video_id
21 }
22
23 pub fn title(&self) -> &str {
25 &self.0.title
26 }
27
28 pub fn thumbnails(&self) -> impl Iterator<Item = &crate::Thumbnail> {
30 self.0.thumbnail.thumbnails.iter()
31 }
32
33 pub fn views(&self) -> Option<u64> {
35 let s: &str = match self.0.view_count_text.as_ref()? {
36 crate::youtube::Text::SimpleText(simple) => {
38 simple
39 .simple_text
40 .split_once(' ')
41 .expect("No space in view_count_text")
42 .0
43 }
44 crate::youtube::Text::Runs(runs) => &runs.runs[0].text,
46 };
47
48 Some(s.replace(',', "").parse().expect("Views were not parsable"))
49 }
50
51 pub fn length(&self) -> Option<std::time::Duration> {
53 self.0.length_text.as_deref().map(parse_length)
54 }
55
56 pub fn channel(&self) -> Channel<'_> {
58 Channel {
59 id: Some(
60 self.0.short_byline_text.runs[0]
61 .navigation_endpoint
62 .browse_endpoint
63 .browse_id,
64 ),
65 name: &self.0.short_byline_text.runs[0].text,
66 badges: &self.0.owner_badges,
67 client: &self.1,
68 }
69 }
70
71 pub async fn upgrade(&self) -> crate::Result<crate::Video> {
73 self.1.video(self.id()).await
74 }
75
76 pub async fn streams(&self) -> crate::Result<impl Iterator<Item = crate::Stream>> {
78 self.1.streams(self.id()).await
79 }
80}
81
82impl std::fmt::Debug for Video {
83 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84 f.debug_struct("Video")
85 .field("id", &self.id())
86 .field("title", &self.title())
87 .field("thumbnails", &self.thumbnails().collect::<Vec<_>>())
88 .field("views", &self.views())
89 .field("length", &self.length())
90 .field("channel", &self.channel())
91 .finish()
92 }
93}
94
95impl PartialEq for Video {
96 fn eq(&self, other: &Self) -> bool {
97 self.id() == other.id()
98 }
99}
100
101impl Eq for Video {}
102
103#[derive(Clone)]
105pub struct Playlist(pub(super) CompactPlaylistRenderer, pub(super) crate::Client);
106
107impl Playlist {
108 pub fn id(&self) -> crate::playlist::Id {
110 crate::playlist::Id(self.0.playlist_id.clone())
111 }
112
113 pub fn title(&self) -> &str {
115 &self.0.title
116 }
117
118 pub fn thumbnails(&self) -> impl Iterator<Item = &crate::Thumbnail> {
120 self.0.thumbnail.thumbnails.iter()
121 }
122
123 pub fn channel(&self) -> Channel<'_> {
125 Channel {
126 id: self.0.channel_id(),
127 name: &self.0.channel_name(),
128 badges: &self.0.owner_badges,
129 client: &self.1,
130 }
131 }
132
133 pub async fn upgrade(&self) -> crate::Result<crate::Playlist> {
135 self.1.playlist(self.id()).await
136 }
137}
138
139impl Debug for Playlist {
140 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
141 f.debug_struct("Playlist")
142 .field("id", &self.id())
143 .field("title", &self.title())
144 .field("thumbnails", &self.thumbnails().collect::<Vec<_>>())
145 .field("channel", &self.channel())
146 .finish()
147 }
148}
149
150impl PartialEq for Playlist {
151 fn eq(&self, other: &Self) -> bool {
152 self.id() == other.id()
153 }
154}
155
156impl Eq for Playlist {}
157
158#[derive(Clone)]
160pub struct Radio(pub(super) CompactRadioRenderer, pub(super) crate::Client);
161
162impl Radio {
163 pub fn id(&self) -> crate::playlist::Id {
165 crate::playlist::Id(self.0.playlist_id.clone())
166 }
167
168 pub fn title(&self) -> &str {
170 &self.0.title
171 }
172
173 pub fn thumbnails(&self) -> impl Iterator<Item = &crate::Thumbnail> {
175 self.0.thumbnail.thumbnails.iter()
176 }
177
178 pub async fn upgrade(&self) -> crate::Result<crate::Playlist> {
180 self.1.playlist(self.id()).await
181 }
182}
183
184impl Debug for Radio {
185 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186 f.debug_struct("Radio")
187 .field("id", &self.id())
188 .field("title", &self.title())
189 .field("thumbnails", &self.thumbnails().collect::<Vec<_>>())
190 .finish()
191 }
192}
193
194impl PartialEq for Radio {
195 fn eq(&self, other: &Self) -> bool {
196 self.id() == other.id()
197 }
198}
199
200impl Eq for Radio {}
201
202#[derive(Clone)]
204pub struct Movie(pub(super) CompactMovieRenderer, pub(super) crate::Client);
205
206impl Movie {
207 pub fn id(&self) -> super::Id {
209 self.0.video_id
210 }
211
212 pub fn title(&self) -> &str {
214 &self.0.title
215 }
216
217 pub fn thumbnails(&self) -> impl Iterator<Item = &crate::Thumbnail> {
219 self.0.thumbnail.thumbnails.iter()
220 }
221
222 pub fn length(&self) -> std::time::Duration {
224 parse_length(&self.0.length_text)
225 }
226
227 pub async fn upgrade(&self) -> crate::Result<crate::Video> {
229 self.1.video(self.id()).await
230 }
231}
232
233impl std::fmt::Debug for Movie {
234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235 f.debug_struct("Movie")
236 .field("id", &self.id())
237 .field("title", &self.title())
238 .field("thumbnails", &self.thumbnails().collect::<Vec<_>>())
239 .field("length", &self.length())
240 .finish()
241 }
242}
243
244impl PartialEq for Movie {
245 fn eq(&self, other: &Self) -> bool {
246 self.id() == other.id()
247 }
248}
249
250impl Eq for Movie {}
251
252#[derive(Clone)]
254pub struct Channel<'a> {
255 id: Option<crate::channel::Id>,
256 name: &'a str,
257 badges: &'a Vec<youtube::Badge>,
258 client: &'a crate::Client,
259}
260
261impl<'a> Channel<'a> {
262 pub fn id(&self) -> Option<crate::channel::Id> {
264 self.id
265 }
266
267 pub fn name(&self) -> &str {
269 self.name
270 }
271
272 pub fn badges(&self) -> impl Iterator<Item = crate::channel::Badge> + '_ {
274 self.badges.iter().map(crate::channel::Badge::from)
275 }
276
277 pub async fn upgrade(&self) -> Option<crate::Result<crate::Channel>> {
279 Some(self.client.channel(self.id?).await)
280 }
281}
282
283impl<'a> std::fmt::Debug for Channel<'a> {
284 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
285 f.debug_struct("Channel")
286 .field("id", &self.id())
287 .field("name", &self.name())
288 .field("badges", &self.badges().collect::<Vec<_>>())
289 .finish()
290 }
291}
292
293impl<'a> PartialEq for Channel<'a> {
294 fn eq(&self, other: &Self) -> bool {
295 self.id() == other.id()
296 }
297}
298
299impl<'a> Eq for Channel<'a> {}