feat: add video response
- started timeago_table
This commit is contained in:
parent
346406c1c8
commit
9da166304a
21 changed files with 41070 additions and 9244 deletions
|
|
@ -1,3 +1,2 @@
|
|||
pub mod range;
|
||||
pub mod text;
|
||||
// pub mod renderer;
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
use std::marker::PhantomData;
|
||||
|
||||
use serde::{de::Visitor, Deserialize, Deserializer};
|
||||
use serde_with::{serde_as, DeserializeAs, rust::maps_duplicate_key_is_error::deserialize};
|
||||
|
||||
/// ```json
|
||||
/// {
|
||||
/// itemSectionRenderer": {
|
||||
/// "contents": [
|
||||
/// {
|
||||
/// "playlistVideoListRenderer": {
|
||||
/// "contents": [
|
||||
/// {
|
||||
/// "playlistVideoRenderer": { ... }
|
||||
/// },
|
||||
/// {
|
||||
/// "playlistVideoRenderer": { ... }
|
||||
/// },
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ]
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// Renderer names:
|
||||
///
|
||||
/// 1 content element:
|
||||
/// - tabRenderer > content
|
||||
///
|
||||
/// 1 content element (array):
|
||||
/// - twoColumnBrowseResultsRenderer > tabs
|
||||
/// - sectionListRenderer > contents
|
||||
/// - itemSectionRenderer > contents
|
||||
///
|
||||
/// n content elements:
|
||||
/// - playlistVideoListRenderer > contents
|
||||
|
||||
#[serde_as]
|
||||
#[derive(Deserialize)]
|
||||
#[serde(untagged, bound = "for<'de2> T: Deserialize<'de2>")]
|
||||
pub enum Renderer<T> where for<'de2> T: Deserialize<'de2> {
|
||||
Single {
|
||||
#[serde_as(as = "crate::serializer::renderer::Renderer<T>")]
|
||||
content: T,
|
||||
},
|
||||
Multiple {
|
||||
#[serde(alias = "tabs")]
|
||||
#[serde_as(as = "crate::serializer::renderer::Renderer<T>")]
|
||||
contents: Vec<T>,
|
||||
},
|
||||
Content {
|
||||
#[serde(flatten)]
|
||||
inner: T,
|
||||
},
|
||||
}
|
||||
|
||||
// pub struct Renderer<T>(PhantomData<T>);
|
||||
|
||||
impl<'de, T> DeserializeAs<'de, T> for Renderer<T> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de, T> DeserializeAs<'de, Vec<T>> for Renderer<T> {
|
||||
fn deserialize_as<D>(deserializer: D) -> Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
struct RendererVisitor<T, U>(PhantomData<T>, PhantomData<U>);
|
||||
|
||||
impl<'de, T, U> Visitor<'de> for RendererVisitor<T, U>
|
||||
where
|
||||
U: DeserializeAs<'de, T>,
|
||||
{
|
||||
type Value = T;
|
||||
|
||||
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
formatter.write_str("a yt renderer")
|
||||
}
|
||||
|
||||
fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>, {
|
||||
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
|
@ -65,12 +65,16 @@ pub enum TextLink {
|
|||
page_type: PageType,
|
||||
browse_id: String,
|
||||
},
|
||||
Web {
|
||||
text: String,
|
||||
url: String,
|
||||
},
|
||||
None {
|
||||
text: String,
|
||||
},
|
||||
}
|
||||
|
||||
pub struct TextLinks {}
|
||||
pub struct TextLinks;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct TextLinkInternal {
|
||||
|
|
@ -97,6 +101,9 @@ struct NavigationEndpoint {
|
|||
browse_endpoint: Option<BrowseEndpoint>,
|
||||
#[serde(default)]
|
||||
#[serde_as(deserialize_as = "DefaultOnError")]
|
||||
url_endpoint: Option<UrlEndpoint>,
|
||||
#[serde(default)]
|
||||
#[serde_as(deserialize_as = "DefaultOnError")]
|
||||
command_metadata: Option<CommandMetadata>,
|
||||
}
|
||||
|
||||
|
|
@ -113,6 +120,12 @@ struct BrowseEndpoint {
|
|||
browse_endpoint_context_supported_configs: Option<BrowseEndpointConfig>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct UrlEndpoint {
|
||||
url: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct BrowseEndpointConfig {
|
||||
|
|
@ -173,7 +186,13 @@ fn map_text_linkrun(lr: &TextLinkRun) -> Option<TextLink> {
|
|||
},
|
||||
browse_id: b.browse_id.to_owned(),
|
||||
},
|
||||
None => TextLink::None { text },
|
||||
None => match &nav.url_endpoint {
|
||||
Some(u) => TextLink::Web {
|
||||
text,
|
||||
url: u.url.to_owned(),
|
||||
},
|
||||
None => TextLink::None { text },
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
@ -398,6 +417,42 @@ mod tests {
|
|||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t_link_web() {
|
||||
let test_json = r#"{
|
||||
"ln": {
|
||||
"runs": [
|
||||
{
|
||||
"text": "Creative Commons",
|
||||
"navigationEndpoint": {
|
||||
"clickTrackingParams": "CJsBEM2rARgBIhMImKz9y6Oc-QIVTJpVCh3VrAYM",
|
||||
"commandMetadata": {
|
||||
"webCommandMetadata": {
|
||||
"url": "https://www.youtube.com/t/creative_commons",
|
||||
"webPageType": "WEB_PAGE_TYPE_UNKNOWN",
|
||||
"rootVe": 83769
|
||||
}
|
||||
},
|
||||
"urlEndpoint": {
|
||||
"url": "https://www.youtube.com/t/creative_commons"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}"#;
|
||||
|
||||
let res = serde_json::from_str::<SLink>(&test_json).unwrap();
|
||||
insta::assert_debug_snapshot!(res, @r###"
|
||||
SLink {
|
||||
ln: Web {
|
||||
text: "Creative Commons",
|
||||
url: "https://www.youtube.com/t/creative_commons",
|
||||
},
|
||||
}
|
||||
"###);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn t_links_artists() {
|
||||
let test_json = r#"{
|
||||
|
|
|
|||
Reference in a new issue