2020-07-31 11:49:06 +00:00
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
use atom_syndication as atom;
|
|
|
|
use maj::gemini::Node;
|
|
|
|
use rustls::ClientConfig;
|
|
|
|
use std::io::{self, BufReader, Cursor, Write};
|
|
|
|
use std::ops::Sub;
|
|
|
|
use std::str;
|
|
|
|
use chrono::{Duration, prelude::*};
|
|
|
|
|
|
|
|
mod tls;
|
|
|
|
|
|
|
|
fn gem_to_md(tcana: Vec<Node>, out: &mut impl Write) -> io::Result<()> {
|
|
|
|
use Node::*;
|
|
|
|
|
|
|
|
for tcan in tcana {
|
|
|
|
match tcan {
|
|
|
|
Text(body) => {
|
|
|
|
if body == "---" {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
write!(out, "{}\n", body)?;
|
|
|
|
}
|
|
|
|
Link { to, name } => match name {
|
|
|
|
Some(name) => write!(out, "[{}]({})\n\n", name, to)?,
|
|
|
|
None => write!(out, "[{0}]({0})", to)?,
|
|
|
|
},
|
|
|
|
Preformatted(body) => write!(out, "```\n{}\n```\n\n", body)?,
|
|
|
|
Heading { level, body } => {
|
|
|
|
write!(out, "##{} {}\n\n", "#".repeat(level as usize), body)?
|
|
|
|
}
|
|
|
|
ListItem(body) => write!(out, "* {}\n", body)?,
|
|
|
|
Quote(body) => write!(out, "> {}\n\n", body)?,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn read_feed(gurl: String, cfg: ClientConfig) -> Result<atom::Feed> {
|
|
|
|
let resp = maj::get(gurl, cfg).await?;
|
|
|
|
if resp.status != maj::StatusCode::Success {
|
|
|
|
Err(anyhow!(
|
|
|
|
"expected success, got: {} {}",
|
|
|
|
resp.status as u8,
|
|
|
|
resp.meta
|
|
|
|
))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
let body = Cursor::new(resp.body);
|
|
|
|
let feed = atom::Feed::read_from(BufReader::new(body))?;
|
|
|
|
|
|
|
|
Ok(feed)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn run(nuzyurli: Vec<String>, seldei: usize) -> Result<()> {
|
|
|
|
let cfg = tls::config();
|
|
|
|
let ca: atom::FixedDateTime = Utc::now().into();
|
|
|
|
|
|
|
|
for urli in nuzyurli {
|
|
|
|
let feed = read_feed(urli.clone(), cfg.clone()).await?;
|
|
|
|
log::info!("reading entries for {}: {}", urli, feed.title);
|
2020-07-31 11:59:27 +00:00
|
|
|
println!("## {}\nBy {}\n\n", feed.title, feed.authors[0].name);
|
|
|
|
println!("[Site link]({})\n\n", feed.id);
|
2020-07-31 11:49:06 +00:00
|
|
|
|
|
|
|
for entry in feed.entries {
|
|
|
|
if ca.sub(entry.updated) > Duration::days(seldei as i64) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let href: String = entry.links()[0].href.clone();
|
|
|
|
let resp = maj::get(href, cfg.clone()).await?;
|
|
|
|
if resp.status != maj::StatusCode::Success {
|
|
|
|
return Err(anyhow!(
|
|
|
|
"expected success, got: {} {}",
|
|
|
|
resp.status as u8,
|
|
|
|
resp.meta
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let body = str::from_utf8(&resp.body)?;
|
|
|
|
let body = maj::gemini::parse(body);
|
|
|
|
let mut buf: Vec<u8> = vec![];
|
|
|
|
gem_to_md(body, &mut buf)?;
|
|
|
|
println!("{}", str::from_utf8(&buf)?);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|