musicou_kit/
lib.rs

1use serde_json::Value;
2use structs::{Album, Artist, Error, Page, Playlist, Search, Song};
3
4use crate::extractors::Fast;
5
6mod extractors;
7mod scrapers;
8pub mod structs;
9
10mod tests;
11
12impl Search {
13    pub async fn fetch(&mut self, page: Page) -> Result<Search, Error> {
14        log::debug!(
15            "SEARCH | Fetching for  {} on {:?} page ",
16            self.query.clone(),
17            page.clone(),
18        );
19        let data: Value;
20        // Checking if a search has  been already made
21        match self.get_continuation(page.clone()) {
22            Some(next_page) => {
23                log::debug!("SEARCH | Not new search, has history about this page");
24
25                // searching with parameter
26                let specific_search =
27                    scrapers::youtube::search(structs::YtSearchType::Final(next_page)).await;
28
29                // TODO this might cause problems later, since there is an end to these pages
30                // extraxting next page parameter for later searches
31                let next_page = extractors::youtube::search::cont::extract_from_contiunation_search(
32                    specific_search.as_ref().unwrap().clone(),
33                );
34
35                match next_page {
36                    Err(error) => {
37                        log::warn!(
38                        "Hmm.. there seems to be no next page for this kind of search {:?} or the extractor might be broken ({:?})",
39                        page,
40                        error
41                    )
42                    }
43                    Ok(next_page) => self.set_continuation(next_page, page.clone()),
44                }
45                data = specific_search.unwrap()["continuationContents"]["musicShelfContinuation"]
46                    ["contents"]
47                    .clone();
48            }
49            None => {
50                log::debug!("SEARCH | New search, no history");
51                // getting search results
52                let generic_search =
53                    scrapers::youtube::search(structs::YtSearchType::Basic(self.query.clone()))
54                        .await;
55
56                let cont = extractors::youtube::search::cont::extract_from_basic_search(
57                    generic_search.unwrap(),
58                    page.clone(),
59                );
60
61                // searching again with next page parameter
62                let specific_search = scrapers::youtube::search(
63                    structs::YtSearchType::Continuation(self.query.clone(), cont.unwrap()),
64                )
65                .await;
66
67                // extraxting next page parameter for later searches | there may be no contiunation for some, like artists
68                let next_page = extractors::youtube::search::cont::extract_from_specific_search(
69                    specific_search.as_ref().unwrap().clone(),
70                );
71                match next_page {
72                    Err(_) => {
73                        log::warn!(
74                            "Hmm.. there seems to be no next page for this kind of search {:?}",
75                            page
76                        )
77                    }
78                    Ok(next_page) => self.set_continuation(next_page, page.clone()),
79                }
80
81                match specific_search.unwrap().pointer_converter("/contents/tabbedSearchResultsRenderer/tabs/0/tabRenderer/content/sectionListRenderer/contents/1/musicShelfRenderer/contents"){
82                    Ok(items) => data = items,
83                    Err(error) => return Err(error)
84                 };
85            }
86        }
87
88        match page {
89            Page::Song => return extractors::youtube::search::song::extract(data.clone(), self),
90            Page::Artist => {
91                return extractors::youtube::search::artist::extract(data.clone(), self)
92            }
93            Page::Album => return extractors::youtube::search::album::extract(data.clone(), self),
94            Page::Playlist => {
95                return extractors::youtube::search::playlist::extract(data.clone(), self)
96            }
97        }
98    }
99}
100
101impl Song {
102    pub async fn fetch(&mut self) -> Result<Song, Error> {
103        match scrapers::youtube::song(self.id.clone()).await {
104            Ok(song_value) => match extractors::youtube::normal::song::extract(song_value) {
105                Ok(song) => {
106                    *self = song.clone();
107                    return Ok(song);
108                }
109                Err(error) => return Err(error),
110            },
111            Err(error) => {
112                return Err(error);
113            }
114        }
115    }
116}
117impl Artist {
118    pub async fn fetch(&mut self) -> Result<Artist, Error> {
119        match scrapers::youtube::browse(self.id.clone()).await {
120            Ok(artist) => match extractors::youtube::normal::artist::extract(artist) {
121                Ok(artist) => {
122                    *self = artist.clone();
123                    return Ok(artist);
124                }
125                Err(error) => return Err(error),
126            },
127            Err(error) => {
128                return Err(error);
129            }
130        }
131    }
132}
133
134// TODO implement fetching for contiunation , since it doesnt load all the songs by default
135impl Playlist {
136    pub async fn fetch(&mut self) -> Result<Playlist, Error> {
137        match scrapers::youtube::browse(self.id.clone()).await {
138            Ok(playlist) => match extractors::youtube::normal::playlist::extract(playlist) {
139                Ok(playlist) => {
140                    *self = playlist.clone();
141                    return Ok(playlist);
142                }
143                Err(error) => return Err(error),
144            },
145            Err(error) => {
146                return Err(error);
147            }
148        }
149    }
150}
151impl Album {
152    pub async fn fetch(&mut self) -> Result<Album, Error> {
153        match scrapers::youtube::browse(self.id.clone()).await {
154            Ok(playlist) => match extractors::youtube::normal::album::extract(playlist) {
155                Ok(album) => {
156                    *self = album.clone();
157                    return Ok(album);
158                }
159                Err(error) => return Err(error),
160            },
161            Err(error) => {
162                return Err(error);
163            }
164        }
165    }
166}