Add writing to XML

This commit is contained in:
Max Nuding 2023-01-17 19:46:56 +00:00
commit c43a1b5ed3
5 changed files with 1950 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

1810
Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

12
Cargo.toml Normal file
View File

@ -0,0 +1,12 @@
[package]
name = "bib-watcher"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
chrono = "0.4.23"
reqwest = { version = "0.11.13", features = ["blocking"]}
rss = "2.0.2"
scraper = "0.14.0"

14
bib.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Bib Watcher</title>
<link>https://phlaym.net</link>
<description>Watches availability status of library books</description>
<item>
<title>Klufti Affenhitze</title>
<link>https://webopac.winbiap.de/konstanz/detail.aspx?data=U29ydD1adWdhbmdzZGF0dW0gKEJpYmxpb3RoZWspJmFtcDtjbWQ9MSZhbXA7cFM9MTAmYW1wO0NhdGFsb2d1ZUlkPTEwNjYwNCZhbXA7cEk9MCZhbXA7c0M9Y18wPTAlJW1fMD0xJSVmXzA9MiUlb18wPTglJXZfMD1hZmZlbmhpdHplJSVnXzA9LTEmYW1wO3NDYXRJZD0xMDY2MDQmYW1wO3BhZ2VJZD0yJmFtcDtTcmM9Mg%3d%3d</link>
<description><![CDATA[entliehen]]></description>
<pubDate>Tue, 17 Jan 2023 19:45:23 +0000</pubDate>
</item>
</channel>
</rss>

113
src/main.rs Normal file
View File

@ -0,0 +1,113 @@
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<String, Box<dyn Error>> {
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<dyn Error>> {
let searches = [(
"Klufti Affenhitze",
"https://webopac.winbiap.de/konstanz/detail.aspx?data=U29ydD1adWdhbmdzZGF0dW0gKEJpYmxpb3RoZWspJmFtcDtjbWQ9MSZhbXA7cFM9MTAmYW1wO0NhdGFsb2d1ZUlkPTEwNjYwNCZhbXA7cEk9MCZhbXA7c0M9Y18wPTAlJW1fMD0xJSVmXzA9MiUlb18wPTglJXZfMD1hZmZlbmhpdHplJSVnXzA9LTEmYW1wO3NDYXRJZD0xMDY2MDQmYW1wO3BhZ2VJZD0yJmFtcDtTcmM9Mg%3d%3d"
)]
.iter()
.cloned()
.collect::<std::collections::HashMap<&str, &str>>();
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<dyn Error>> {
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<String, Box<dyn Error>> {
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::<String>())
.unwrap_or_else(|| "Unknown".into()))
}