feat: music search suggestions
This commit is contained in:
parent
ef86181627
commit
bd936a8c42
10 changed files with 474 additions and 3 deletions
|
|
@ -23,7 +23,7 @@ inspired by [NewPipe](https://github.com/TeamNewPipe/NewPipeExtractor).
|
||||||
- [X] **Album**
|
- [X] **Album**
|
||||||
- [X] **Artist**
|
- [X] **Artist**
|
||||||
- [X] **Search**
|
- [X] **Search**
|
||||||
- [ ] **Search suggestions**
|
- [X] **Search suggestions**
|
||||||
- [X] **Radio**
|
- [X] **Radio**
|
||||||
- [X] **Track details** (lyrics, recommendations)
|
- [X] **Track details** (lyrics, recommendations)
|
||||||
- [ ] **Moods**
|
- [ ] **Moods**
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,7 @@ pub async fn download_testfiles(project_root: &Path) {
|
||||||
music_search_artists(&testfiles).await;
|
music_search_artists(&testfiles).await;
|
||||||
music_search_playlists(&testfiles).await;
|
music_search_playlists(&testfiles).await;
|
||||||
music_search_cont(&testfiles).await;
|
music_search_cont(&testfiles).await;
|
||||||
|
music_search_suggestion(&testfiles).await;
|
||||||
music_artist(&testfiles).await;
|
music_artist(&testfiles).await;
|
||||||
music_details(&testfiles).await;
|
music_details(&testfiles).await;
|
||||||
music_lyrics(&testfiles).await;
|
music_lyrics(&testfiles).await;
|
||||||
|
|
@ -585,10 +586,14 @@ async fn music_album(testfiles: &Path) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn music_search(testfiles: &Path) {
|
async fn music_search(testfiles: &Path) {
|
||||||
for (name, query) in [("default", "black mamba"), ("typo", "liblingsmensch")] {
|
for (name, query) in [
|
||||||
|
("default", "black mamba"),
|
||||||
|
("typo", "liblingsmensch"),
|
||||||
|
("radio", "pop radio"),
|
||||||
|
] {
|
||||||
let mut json_path = testfiles.to_path_buf();
|
let mut json_path = testfiles.to_path_buf();
|
||||||
json_path.push("music_search");
|
json_path.push("music_search");
|
||||||
json_path.push(format!("{}.json", name));
|
json_path.push(format!("main_{}.json", name));
|
||||||
if json_path.exists() {
|
if json_path.exists() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -684,6 +689,20 @@ async fn music_search_cont(testfiles: &Path) {
|
||||||
res.items.next(&rp.query()).await.unwrap().unwrap();
|
res.items.next(&rp.query()).await.unwrap().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn music_search_suggestion(testfiles: &Path) {
|
||||||
|
for (name, query) in [("default", "t"), ("empty", "reujbhevmfndxnjrze")] {
|
||||||
|
let mut json_path = testfiles.to_path_buf();
|
||||||
|
json_path.push("music_search");
|
||||||
|
json_path.push(format!("suggestion_{}.json", name));
|
||||||
|
if json_path.exists() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rp = rp_testfile(&json_path);
|
||||||
|
rp.query().music_search_suggestion(query).await.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async fn music_artist(testfiles: &Path) {
|
async fn music_artist(testfiles: &Path) {
|
||||||
for (name, id) in [
|
for (name, id) in [
|
||||||
("default", "UClmXPfaYhXOYsNn_QUyheWQ"),
|
("default", "UClmXPfaYhXOYsNn_QUyheWQ"),
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@ struct QSearch<'a> {
|
||||||
params: Option<Params>,
|
params: Option<Params>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
struct QSearchSuggestion<'a> {
|
||||||
|
context: YTContext<'a>,
|
||||||
|
input: &'a str,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize)]
|
#[derive(Debug, Serialize)]
|
||||||
enum Params {
|
enum Params {
|
||||||
#[serde(rename = "EgWKAQIIAWoMEAMQBBAJEA4QChAF")]
|
#[serde(rename = "EgWKAQIIAWoMEAMQBBAJEA4QChAF")]
|
||||||
|
|
@ -182,6 +189,23 @@ impl RustyPipeQuery {
|
||||||
)
|
)
|
||||||
.await
|
.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 {
|
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{fs::File, io::BufReader, path::Path};
|
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);
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ pub(crate) use music_details::MusicRelated;
|
||||||
pub(crate) use music_item::MusicContinuation;
|
pub(crate) use music_item::MusicContinuation;
|
||||||
pub(crate) use music_playlist::MusicPlaylist;
|
pub(crate) use music_playlist::MusicPlaylist;
|
||||||
pub(crate) use music_search::MusicSearch;
|
pub(crate) use music_search::MusicSearch;
|
||||||
|
pub(crate) use music_search::MusicSearchSuggestion;
|
||||||
pub(crate) use player::Player;
|
pub(crate) use player::Player;
|
||||||
pub(crate) use playlist::Playlist;
|
pub(crate) use playlist::Playlist;
|
||||||
pub(crate) use playlist::PlaylistCont;
|
pub(crate) use playlist::PlaylistCont;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,16 @@ pub(crate) struct MusicSearch {
|
||||||
pub contents: Contents,
|
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)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub(crate) struct Contents {
|
pub(crate) struct Contents {
|
||||||
|
|
@ -45,3 +55,21 @@ pub(crate) struct ShowingResultsForRenderer {
|
||||||
#[serde_as(as = "Text")]
|
#[serde_as(as = "Text")]
|
||||||
pub corrected_query: String,
|
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,
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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",
|
||||||
|
]
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
source: src/client/music_search.rs
|
||||||
|
expression: map_res.c
|
||||||
|
---
|
||||||
|
[]
|
||||||
242
testfiles/music_search/suggestion_default.json
Normal file
242
testfiles/music_search/suggestion_default.json
Normal file
|
|
@ -0,0 +1,242 @@
|
||||||
|
{
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"searchSuggestionsSectionRenderer": {
|
||||||
|
"contents": [
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAcQpWEYASITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "taylor swift"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "aylor swift"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAcQpWEYASITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAYQpWEYAiITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "tkkg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "kkg"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAYQpWEYAiITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAUQpWEYAyITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "techno"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "echno"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAUQpWEYAyITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAQQpWEYBCITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "t low"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": " low"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAQQpWEYBCITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAMQpWEYBSITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "the weeknd"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "he weeknd"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAMQpWEYBSITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAIQpWEYBiITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "tiktok songs"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "iktok songs"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAIQpWEYBiITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"searchSuggestionRenderer": {
|
||||||
|
"icon": {
|
||||||
|
"iconType": "SEARCH"
|
||||||
|
},
|
||||||
|
"navigationEndpoint": {
|
||||||
|
"clickTrackingParams": "CAEQpWEYByITCKbj7Pb3yPsCFcfUEQgdRe0MBA==",
|
||||||
|
"searchEndpoint": {
|
||||||
|
"query": "toten hosen"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"suggestion": {
|
||||||
|
"runs": [
|
||||||
|
{
|
||||||
|
"bold": true,
|
||||||
|
"text": "t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "oten hosen"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"trackingParams": "CAEQpWEYByITCKbj7Pb3yPsCFcfUEQgdRe0MBA=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responseContext": {
|
||||||
|
"serviceTrackingParams": [
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "c",
|
||||||
|
"value": "WEB_REMIX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cver",
|
||||||
|
"value": "1.20221121.01.00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "yt_li",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "GetMusicSearchSuggestions_rid",
|
||||||
|
"value": "0xe343e5421f9bc4f5"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "CSI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "logged_in",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "e",
|
||||||
|
"value": "1714247,9407157,23804281,23882685,23885487,23918597,23934970,23946420,23966208,23983296,23998056,24001373,24002022,24002025,24004644,24007246,24034168,24036948,24077241,24080738,24108448,24120820,24135310,24140247,24161116,24162920,24164186,24169501,24181174,24187043,24187377,24191629,24197450,24199724,24200839,24211178,24217535,24219713,24237297,24241378,24255165,24255543,24255545,24257695,24262346,24263796,24265426,24267564,24268142,24271464,24279196,24282724,24287327,24287604,24288043,24288442,24290971,24292955,24293803,24296354,24298084,24299747,24299875,24390374,24390675,24391018,24391541,24391579,24392268,24392403,24392452,24398048,24401557,24402891,24405024,24406605,24407200,24407452,24407665,24410273,24410853,24412682,24412897,24413820,24414162,24414917,24415579,24415866,24416290,24419371,24420756,24421162,24421894,24422904,24424806,24590921,39322504,39322574"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "GFEEDBACK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "client.version",
|
||||||
|
"value": "1.20000101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "client.name",
|
||||||
|
"value": "WEB_REMIX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "client.fexp",
|
||||||
|
"value": "24257695,24288043,24415579,23882685,24412682,39322574,24287604,24410273,23885487,24217535,24392452,1714247,9407157,24390675,24299747,24401557,39322504,24410853,24191629,24108448,24279196,24255545,24292955,24001373,24161116,24290971,24413820,23934970,24007246,24187377,23998056,24391018,24415866,24293803,24262346,24282724,24398048,24407452,24187043,24407200,24419371,24199724,24421162,24211178,24287327,24265426,24392268,24164186,24241378,24391541,24422904,24255165,24402891,24140247,24416290,23983296,24002025,24414917,24414162,24391579,24237297,24406605,24424806,24255543,24299875,24263796,24298084,24135310,24267564,24004644,24077241,24036948,24405024,24420756,24296354,24590921,24268142,23918597,24390374,24271464,23946420,24197450,24412897,24120820,24421894,23804281,24392403,24181174,24002022,24200839,24288442,24219713,23966208,24034168,24080738,24162920,24169501,24407665"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "ECATCHER"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visitorData": "CgtHV2dSNHFYMDhLSSjZ_4GcBg%3D%3D"
|
||||||
|
},
|
||||||
|
"trackingParams": "CAAQi24iEwim4-z298j7AhXH1BEIHUXtDAQ="
|
||||||
|
}
|
||||||
59
testfiles/music_search/suggestion_empty.json
Normal file
59
testfiles/music_search/suggestion_empty.json
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
{
|
||||||
|
"responseContext": {
|
||||||
|
"serviceTrackingParams": [
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "c",
|
||||||
|
"value": "WEB_REMIX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "cver",
|
||||||
|
"value": "1.20221121.01.00"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "yt_li",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "GetMusicSearchSuggestions_rid",
|
||||||
|
"value": "0x0a90fd4a664adea1"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "CSI"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "logged_in",
|
||||||
|
"value": "0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "e",
|
||||||
|
"value": "1714245,23804281,23882685,23918597,23934970,23946420,23966208,23983296,23998056,24001373,24002022,24002025,24004644,24007246,24034168,24036948,24077241,24080738,24120819,24135310,24140247,24161116,24162920,24164186,24169501,24181174,24184893,24187043,24187377,24191629,24197450,24199724,24200839,24211178,24217535,24219713,24241378,24255163,24255543,24255545,24262346,24263796,24265426,24267564,24268142,24279196,24280999,24281671,24282722,24287327,24288043,24290971,24292955,24293803,24299747,24299875,24390374,24390675,24391018,24391539,24392399,24400178,24400185,24401291,24401557,24402891,24404641,24406605,24407200,24407665,24412154,24413415,24414074,24414162,24415866,24416291,24416439,24417792,24418790,24420756,24421162,24423785,24426598,24426910,24590921,24591020,39322504,39322574"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "GFEEDBACK"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"params": [
|
||||||
|
{
|
||||||
|
"key": "client.version",
|
||||||
|
"value": "1.20000101"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "client.name",
|
||||||
|
"value": "WEB_REMIX"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "client.fexp",
|
||||||
|
"value": "24292955,24413415,24077241,24001373,24263796,24267564,24161116,24290971,24412154,24191629,24420756,23882685,24299747,24288043,24591020,24184893,24414162,24255543,24406605,24200839,24287327,24280999,24407665,23946420,23804281,24390374,24140247,24414074,23966208,24080738,24418790,23983296,24219713,24164186,24187043,24400178,24400185,24404641,24426910,23998056,24391539,24007246,24401291,24293803,24135310,24255163,24268142,23918597,24187377,24004644,24390675,24255545,24036948,24423785,24392399,24417792,24299875,1714245,24217535,39322574,24281671,24002025,24426598,24199724,24401557,39322504,24421162,24120819,24211178,24265426,24402891,24391018,24181174,24002022,24416439,24407200,24034168,24415866,24282722,24241378,24162920,24416291,23934970,24169501,24590921,24279196,24262346,24197450"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service": "ECATCHER"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visitorData": "Cgtyb1QtdzRqZXZGayisj4KcBg%3D%3D"
|
||||||
|
},
|
||||||
|
"trackingParams": "CAAQi24iEwi6jvCx_8j7AhWbyxEIHYe1Bno="
|
||||||
|
}
|
||||||
|
|
@ -1798,6 +1798,29 @@ async fn music_search_genre_radio() {
|
||||||
rp.query().music_search("pop radio").await.unwrap();
|
rp.query().music_search("pop radio").await.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case::default("ed sheer", Some("ed sheeran"))]
|
||||||
|
#[case::empty("reujbhevmfndxnjrze", None)]
|
||||||
|
#[tokio::test]
|
||||||
|
async fn music_search_suggestion(#[case] query: &str, #[case] expect: Option<&str>) {
|
||||||
|
let rp = RustyPipe::builder().strict().build();
|
||||||
|
let suggestion = rp.query().music_search_suggestion(query).await.unwrap();
|
||||||
|
|
||||||
|
match expect {
|
||||||
|
Some(expect) => assert!(
|
||||||
|
suggestion.iter().any(|s| s == expect),
|
||||||
|
"suggestion: {:?}, expected: {}",
|
||||||
|
suggestion,
|
||||||
|
expect
|
||||||
|
),
|
||||||
|
None => assert!(
|
||||||
|
suggestion.is_empty(),
|
||||||
|
"suggestion: {:?}, expected to be empty",
|
||||||
|
suggestion
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::mv("mv", "ZeerrnuLi5E")]
|
#[case::mv("mv", "ZeerrnuLi5E")]
|
||||||
#[case::track("track", "7nigXQS1Xb0")]
|
#[case::track("track", "7nigXQS1Xb0")]
|
||||||
|
|
|
||||||
Reference in a new issue