use reqwest::header; use rss::{Channel, ChannelBuilder, ItemBuilder}; use scraper::{Html, Selector}; use std::{error::Error, fs::File, io::BufReader}; use chrono::prelude::*; const FILE_NAME: &str = "bib.xml"; fn get_last_status(title: &str) -> Result> { let file = File::open(FILE_NAME); let channel = match file { Ok(f) => Channel::read_from(BufReader::new(f)), Err(_) => { let c = ChannelBuilder::default() .title("Bib Watcher".to_string()) .description("Watches availability status of library books".to_string()) .link("https://phlaym.net".to_string()) .build(); c.pretty_write_to(File::create(FILE_NAME)?, b' ', 4)?; Ok(c) } }?; Ok(channel .items() .iter() .filter(|i| i.title().unwrap_or("") == title) .last() .and_then(|i| i.description()) .unwrap_or("") .into()) } fn main() -> Result<(), Box> { let searches = [( "Klufti Affenhitze", "https://webopac.winbiap.de/konstanz/detail.aspx?data=U29ydD1adWdhbmdzZGF0dW0gKEJpYmxpb3RoZWspJmFtcDtjbWQ9MSZhbXA7cFM9MTAmYW1wO0NhdGFsb2d1ZUlkPTEwNjYwNCZhbXA7cEk9MCZhbXA7c0M9Y18wPTAlJW1fMD0xJSVmXzA9MiUlb18wPTglJXZfMD1hZmZlbmhpdHplJSVnXzA9LTEmYW1wO3NDYXRJZD0xMDY2MDQmYW1wO3BhZ2VJZD0yJmFtcDtTcmM9Mg%3d%3d" )] .iter() .cloned() .collect::>(); for (title, url) in searches { search(url, title)? } /* let url = "https://webopac.winbiap.de/konstanz/detail.aspx?data=U29ydD1adWdhbmdzZGF0dW0gKEJpYmxpb3RoZWspJmFtcDtjbWQ9MSZhbXA7cFM9MTAmYW1wO0NhdGFsb2d1ZUlkPTEwNjYwNCZhbXA7cEk9MCZhbXA7c0M9Y18wPTAlJW1fMD0xJSVmXzA9MiUlb18wPTglJXZfMD1hZmZlbmhpdHplJSVnXzA9LTEmYW1wO3NDYXRJZD0xMDY2MDQmYW1wO3BhZ2VJZD0yJmFtcDtTcmM9Mg%3d%3d"; if status != "entliehen" { Notification::new() .summary("Klufti News") .body(&format!("Neuer Status: {}", status)) .show()?; }*/ Ok(()) } fn search(url: &str, title: &str) -> Result<(), Box> { let mut headers = header::HeaderMap::new(); headers.append( header::ACCEPT, header::HeaderValue::from_static( "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", ), ); headers.append( header::HOST, header::HeaderValue::from_static("webopac.winbiap.de"), ); headers.append( header::REFERER, header::HeaderValue::from_static("https://webopac.winbiap.de/"), ); let client = reqwest::blocking::Client::builder() .default_headers(headers) .build()?; let request = client.get(url).build()?; let response = client.execute(request)?; let status = parse(&response.text()?)?; let last_status = get_last_status(title)?; if status != last_status { let file = File::open(FILE_NAME); let mut channel = match file { Ok(f) => Channel::read_from(BufReader::new(f)), Err(_) => Ok(ChannelBuilder::default() .title("Bib Watcher".to_string()) .description("Watches availability status of library books".to_string()) .link("https://phlaym.net".to_string()) .build()), }?; let mut items = channel.clone().into_items(); items.push( ItemBuilder::default() .title(Some(title.to_string())) .pub_date(Some(Utc::now().to_rfc2822())) .link(Some(url.to_string())) .description(Some(status)) .build(), ); channel.set_items(items); channel.pretty_write_to(File::create(FILE_NAME)?, b' ', 4)?; } Ok(()) } fn parse(html: &str) -> Result> { let document = Html::parse_document(html); let selector = Selector::parse("#detail-left-wrapper .mediaStatus span")?; Ok(document .select(&selector) .next() .map(|r| r.text().collect::()) .unwrap_or_else(|| "Unknown".into())) }