This repository has been archived on 2026-05-27. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
rustypipe/src/client/channel_rss.rs
ThetaDev f526ab38eb refactor!: refactored response models
doc: documented all public methods
2022-12-09 01:02:09 +01:00

91 lines
3 KiB
Rust

use std::collections::BTreeMap;
use crate::{
error::{Error, ExtractionError},
model::ChannelRss,
report::Report,
};
use super::{response, RustyPipeQuery};
impl RustyPipeQuery {
/// Get the 15 latest videos from the channel's RSS feed
///
/// Example: <https://www.youtube.com/feeds/videos.xml?channel_id=UC2DjFE7Xf11URZqWBigcVOQ>
///
/// Fetching RSS feeds is a lot faster than querying the InnerTube API, so this method is great
/// for checking a lot of channels or implementing a subscription feed.
pub async fn channel_rss<S: AsRef<str>>(&self, channel_id: S) -> Result<ChannelRss, Error> {
let url = format!(
"https://www.youtube.com/feeds/videos.xml?channel_id={}",
channel_id.as_ref()
);
let xml = self
.client
.http_request_txt(self.client.inner.http.get(&url).build()?)
.await
.map_err(|e| match e {
Error::HttpStatus(404) => Error::Extraction(ExtractionError::ContentUnavailable(
"Channel not found".into(),
)),
_ => e,
})?;
match quick_xml::de::from_str::<response::ChannelRss>(&xml) {
Ok(feed) => Ok(feed.into()),
Err(e) => {
if let Some(reporter) = &self.client.inner.reporter {
let report = Report {
info: Default::default(),
level: crate::report::Level::ERR,
operation: "channel_rss".to_owned(),
error: Some(e.to_string()),
msgs: Vec::new(),
deobf_data: None,
http_request: crate::report::HTTPRequest {
url,
method: "GET".to_owned(),
req_header: BTreeMap::new(),
req_body: String::new(),
status: 200,
resp_body: xml,
},
};
reporter.report(&report);
}
Err(ExtractionError::InvalidData(
format!("could not deserialize xml: {}", e).into(),
)
.into())
}
}
}
}
#[cfg(test)]
mod tests {
use std::{fs::File, io::BufReader};
use crate::{client::response, model::ChannelRss};
use path_macro::path;
use rstest::rstest;
#[rstest]
#[case::base("base")]
#[case::no_likes("no_likes")]
#[case::no_channel_id("no_channel_id")]
fn map_channel_rss(#[case] name: &str) {
let xml_path = path!("testfiles" / "channel_rss" / format!("{}.xml", name));
let xml_file = File::open(xml_path).unwrap();
let feed: response::ChannelRss =
quick_xml::de::from_reader(BufReader::new(xml_file)).unwrap();
let map_res: ChannelRss = feed.into();
insta::assert_ron_snapshot!(format!("map_channel_rss_{}", name), map_res);
}
}