feat: music search suggestions

This commit is contained in:
ThetaDev 2022-11-25 10:33:49 +01:00
parent ef86181627
commit bd936a8c42
10 changed files with 474 additions and 3 deletions

View file

@ -24,6 +24,13 @@ struct QSearch<'a> {
params: Option<Params>,
}
#[derive(Debug, Serialize)]
#[serde(rename_all = "camelCase")]
struct QSearchSuggestion<'a> {
context: YTContext<'a>,
input: &'a str,
}
#[derive(Debug, Serialize)]
enum Params {
#[serde(rename = "EgWKAQIIAWoMEAMQBBAJEA4QChAF")]
@ -182,6 +189,23 @@ impl RustyPipeQuery {
)
.await
}
pub async fn music_search_suggestion(&self, query: &str) -> Result<Vec<String>, Error> {
let context = self.get_context(ClientType::DesktopMusic, true, None).await;
let request_body = QSearchSuggestion {
context,
input: query,
};
self.execute_request::<response::MusicSearchSuggestion, _, _>(
ClientType::DesktopMusic,
"music_search_suggestion",
query,
"music/get_search_suggestions",
&request_body,
)
.await
}
}
impl MapResponse<MusicSearchResult> for response::MusicSearch {
@ -293,6 +317,41 @@ impl<T: FromYtItem> MapResponse<MusicSearchFiltered<T>> for response::MusicSearc
}
}
impl MapResponse<Vec<String>> for response::MusicSearchSuggestion {
fn map_response(
self,
_id: &str,
_lang: crate::param::Language,
_deobf: Option<&crate::deobfuscate::Deobfuscator>,
) -> Result<MapResult<Vec<String>>, ExtractionError> {
let items = self
.contents
.into_iter()
.next()
.map(|content| {
content
.search_suggestions_section_renderer
.contents
.into_iter()
.filter_map(|itm| {
match itm {
response::music_search::SearchSuggestionItem::SearchSuggestionRenderer {
suggestion,
} => Some(suggestion),
response::music_search::SearchSuggestionItem::None => None,
}
})
.collect::<Vec<_>>()
})
.unwrap_or_default();
Ok(MapResult {
c: items,
warnings: Vec::new(),
})
}
}
#[cfg(test)]
mod tests {
use std::{fs::File, io::BufReader, path::Path};
@ -417,4 +476,26 @@ mod tests {
insta::assert_ron_snapshot!(format!("map_music_search_playlists_{}", name), map_res.c);
}
#[rstest]
#[case::default("default")]
#[case::empty("empty")]
fn map_music_search_suggestion(#[case] name: &str) {
let filename = format!("testfiles/music_search/suggestion_{}.json", name);
let json_path = Path::new(&filename);
let json_file = File::open(json_path).unwrap();
let suggestion: response::MusicSearchSuggestion =
serde_json::from_reader(BufReader::new(json_file)).unwrap();
let map_res: MapResult<Vec<String>> =
suggestion.map_response("", Language::En, None).unwrap();
assert!(
map_res.warnings.is_empty(),
"deserialization/mapping warnings: {:?}",
map_res.warnings
);
insta::assert_ron_snapshot!(format!("map_music_search_suggestion_{}", name), map_res.c);
}
}

View file

@ -21,6 +21,7 @@ pub(crate) use music_details::MusicRelated;
pub(crate) use music_item::MusicContinuation;
pub(crate) use music_playlist::MusicPlaylist;
pub(crate) use music_search::MusicSearch;
pub(crate) use music_search::MusicSearchSuggestion;
pub(crate) use player::Player;
pub(crate) use playlist::Playlist;
pub(crate) use playlist::PlaylistCont;

View file

@ -12,6 +12,16 @@ pub(crate) struct MusicSearch {
pub contents: Contents,
}
/// Response model for YouTube Music suggestion
#[serde_as]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct MusicSearchSuggestion {
#[serde(default)]
#[serde_as(as = "VecSkipError<_>")]
pub contents: Vec<SearchSuggestionsSection>,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct Contents {
@ -45,3 +55,21 @@ pub(crate) struct ShowingResultsForRenderer {
#[serde_as(as = "Text")]
pub corrected_query: String,
}
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) struct SearchSuggestionsSection {
pub search_suggestions_section_renderer: ContentsRenderer<SearchSuggestionItem>,
}
#[serde_as]
#[derive(Debug, Deserialize)]
#[serde(rename_all = "camelCase")]
pub(crate) enum SearchSuggestionItem {
SearchSuggestionRenderer {
#[serde_as(as = "Text")]
suggestion: String,
},
#[serde(other, deserialize_with = "deserialize_ignore_any")]
None,
}

View file

@ -0,0 +1,13 @@
---
source: src/client/music_search.rs
expression: map_res.c
---
[
"taylor swift",
"tkkg",
"techno",
"t low",
"the weeknd",
"tiktok songs",
"toten hosen",
]

View file

@ -0,0 +1,5 @@
---
source: src/client/music_search.rs
expression: map_res.c
---
[]