feat: add chapter extraction
This commit is contained in:
parent
8629454b5b
commit
ed522e622d
3 changed files with 102 additions and 8 deletions
|
|
@ -13,8 +13,8 @@ use crate::serializer::{
|
|||
};
|
||||
|
||||
use super::{
|
||||
ChannelBadge, ContentsRenderer, ContinuationEndpoint, ContinuationItemRenderer, Icon,
|
||||
Thumbnails, VideoBadge, VideoListItem, VideoOwner,
|
||||
ChannelBadge, ContinuationEndpoint, ContinuationItemRenderer, Icon, Thumbnails, VideoBadge,
|
||||
VideoListItem, VideoOwner,
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -348,7 +348,16 @@ pub enum EngagementPanelRenderer {
|
|||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ChapterMarkersContent {
|
||||
pub macro_markers_list_renderer: ContentsRenderer<MacroMarkersListItem>,
|
||||
pub macro_markers_list_renderer: MacroMarkersListRenderer,
|
||||
}
|
||||
|
||||
/// Chapter markers
|
||||
#[serde_as]
|
||||
#[derive(Clone, Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct MacroMarkersListRenderer {
|
||||
#[serde_as(as = "VecLogError<_>")]
|
||||
pub contents: MapResult<Vec<MacroMarkersListItem>>,
|
||||
}
|
||||
|
||||
/// Chapter marker
|
||||
|
|
@ -366,9 +375,6 @@ pub struct MacroMarkersListItemRenderer {
|
|||
/// Contains chapter start time in seconds
|
||||
pub on_tap: MacroMarkersListItemOnTap,
|
||||
pub thumbnail: Thumbnails,
|
||||
/// Textual time (`1:42`)
|
||||
#[serde_as(as = "Text")]
|
||||
pub time_description: String,
|
||||
/// Chapter title
|
||||
#[serde_as(as = "Text")]
|
||||
pub title: String,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,9 @@ use reqwest::Method;
|
|||
use serde::Serialize;
|
||||
|
||||
use crate::{
|
||||
model::{Channel, ChannelId, Comment, Language, Paginator, RecommendedVideo, VideoDetails},
|
||||
model::{
|
||||
Channel, ChannelId, Chapter, Comment, Language, Paginator, RecommendedVideo, VideoDetails,
|
||||
},
|
||||
serializer::MapResult,
|
||||
timeago,
|
||||
util::{self, TryRemove},
|
||||
|
|
@ -258,6 +260,26 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
|
|||
response::video_details::EngagementPanelRenderer::None => {},
|
||||
});
|
||||
|
||||
let chapters = chapter_panel
|
||||
.map(|chapters| {
|
||||
let mut content = chapters.macro_markers_list_renderer.contents;
|
||||
warnings.append(&mut content.warnings);
|
||||
content
|
||||
.c
|
||||
.into_iter()
|
||||
.map(|item| Chapter {
|
||||
title: item.macro_markers_list_item_renderer.title,
|
||||
position: item
|
||||
.macro_markers_list_item_renderer
|
||||
.on_tap
|
||||
.watch_endpoint
|
||||
.start_time_seconds,
|
||||
thumbnail: item.macro_markers_list_item_renderer.thumbnail.into(),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default();
|
||||
|
||||
let latest_comments_ctoken = comment_panel.and_then(|comments| {
|
||||
let mut items = comments
|
||||
.engagement_panel_title_header_renderer
|
||||
|
|
@ -288,6 +310,7 @@ impl MapResponse<VideoDetails> for response::VideoDetails {
|
|||
publish_date_txt,
|
||||
is_live,
|
||||
is_ccommons,
|
||||
chapters,
|
||||
recommended,
|
||||
top_comments: Paginator::new(None, Vec::new(), comment_ctoken),
|
||||
latest_comments: Paginator::new(None, Vec::new(), latest_comments_ctoken),
|
||||
|
|
@ -942,6 +965,57 @@ mod tests {
|
|||
assert!(!details.is_live);
|
||||
assert!(!details.is_ccommons);
|
||||
|
||||
insta::assert_yaml_snapshot!(details.chapters, {
|
||||
"[].thumbnail" => insta::dynamic_redaction(move |value, _path| {
|
||||
assert!(!value.as_slice().unwrap().is_empty());
|
||||
"[ok]"
|
||||
}),
|
||||
}, @r###"
|
||||
---
|
||||
- title: Intro
|
||||
position: 0
|
||||
thumbnail: "[ok]"
|
||||
- title: The PC Built for Super Efficiency
|
||||
position: 42
|
||||
thumbnail: "[ok]"
|
||||
- title: Our BURIAL ENCLOSURE?!
|
||||
position: 161
|
||||
thumbnail: "[ok]"
|
||||
- title: Our Power Solution (Thanks Jackery!)
|
||||
position: 211
|
||||
thumbnail: "[ok]"
|
||||
- title: "Diggin' Holes"
|
||||
position: 287
|
||||
thumbnail: "[ok]"
|
||||
- title: Colonoscopy?
|
||||
position: 330
|
||||
thumbnail: "[ok]"
|
||||
- title: "Diggin' like a man"
|
||||
position: 424
|
||||
thumbnail: "[ok]"
|
||||
- title: "The world's worst woodsman"
|
||||
position: 509
|
||||
thumbnail: "[ok]"
|
||||
- title: Backyard cable management
|
||||
position: 543
|
||||
thumbnail: "[ok]"
|
||||
- title: Time to bury this boy
|
||||
position: 602
|
||||
thumbnail: "[ok]"
|
||||
- title: Solar Power Generation
|
||||
position: 646
|
||||
thumbnail: "[ok]"
|
||||
- title: Issues
|
||||
position: 697
|
||||
thumbnail: "[ok]"
|
||||
- title: First Play Test
|
||||
position: 728
|
||||
thumbnail: "[ok]"
|
||||
- title: Conclusion
|
||||
position: 800
|
||||
thumbnail: "[ok]"
|
||||
"###);
|
||||
|
||||
assert!(!details.recommended.items.is_empty());
|
||||
assert!(!details.recommended.is_exhausted());
|
||||
|
||||
|
|
@ -1032,7 +1106,7 @@ mod tests {
|
|||
let rp = RustyPipe::builder().strict().build();
|
||||
let details = rp.query().video_details("HRKu0cvrr_o").await.unwrap();
|
||||
|
||||
dbg!(&details);
|
||||
// dbg!(&details);
|
||||
|
||||
assert_eq!(details.id, "HRKu0cvrr_o");
|
||||
assert_eq!(
|
||||
|
|
|
|||
|
|
@ -245,6 +245,8 @@ pub struct VideoDetails {
|
|||
///
|
||||
/// https://creativecommons.org/licenses/by/3.0/
|
||||
pub is_ccommons: bool,
|
||||
/// Chapters of the video
|
||||
pub chapters: Vec<Chapter>,
|
||||
/// Recommended videos
|
||||
///
|
||||
/// Note: Recommendations are not available for age-restricted videos
|
||||
|
|
@ -255,6 +257,18 @@ pub struct VideoDetails {
|
|||
pub latest_comments: Paginator<Comment>,
|
||||
}
|
||||
|
||||
/// Videos can consist of different chapters, which YouTube shows
|
||||
/// on the seek bar and below the description text.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Chapter {
|
||||
/// Chapter title
|
||||
pub title: String,
|
||||
/// Chapter position in seconds
|
||||
pub position: u32,
|
||||
/// Chapter thumbnail
|
||||
pub thumbnail: Vec<Thumbnail>,
|
||||
}
|
||||
|
||||
/*
|
||||
@RECOMMENDATIONS
|
||||
*/
|
||||
|
|
|
|||
Reference in a new issue