Compare commits

..

No commits in common. "06344a67ea397347fc16cccfc14ef56f4fccdbc9" and "c4aaa11fc2c44a9c97f19d046d9ab3fe96653dc6" have entirely different histories.

3 changed files with 17 additions and 58 deletions

2
Cargo.lock generated
View File

@ -428,7 +428,7 @@ dependencies = [
[[package]] [[package]]
name = "gemfreely" name = "gemfreely"
version = "0.1.3" version = "0.1.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"atom_syndication", "atom_syndication",

View File

@ -1,6 +1,6 @@
[package] [package]
name = "gemfreely" name = "gemfreely"
version = "0.1.3" version = "0.1.2"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
description = "Synchronize Gemini protocol blogs to the Fediverse" description = "Synchronize Gemini protocol blogs to the Fediverse"

View File

@ -29,7 +29,7 @@ fn is_gemfeed_post_link(node: &GemtextNode) -> bool {
} }
} }
fn parse_gemfeed(base_url: &Url, gemfeed: &GemtextAst) -> Result<Vec<GemfeedEntry>> { fn parse_gemfeed_gemtext(base_url: &Url, gemfeed: &GemtextAst) -> Result<Vec<GemfeedEntry>> {
gemfeed gemfeed
.inner() .inner()
.into_iter() .into_iter()
@ -38,10 +38,9 @@ fn parse_gemfeed(base_url: &Url, gemfeed: &GemtextAst) -> Result<Vec<GemfeedEntr
.collect() .collect()
} }
fn parse_atom( fn parse_gemfeed_atom(feed: &str, settings: &GemfeedParserSettings) -> Result<Vec<GemfeedEntry>> {
feed: &AtomFeed, let feed = feed.parse::<AtomFeed>()?;
settings: &GemfeedParserSettings,
) -> Result<Vec<GemfeedEntry>> {
feed.entries() feed.entries()
.into_iter() .into_iter()
.map(|entry| GemfeedEntry::from_atom(entry, &settings.atom_date_format)) .map(|entry| GemfeedEntry::from_atom(entry, &settings.atom_date_format))
@ -76,11 +75,9 @@ impl From<Cow<'_, str>> for GemfeedType {
} }
} }
#[allow(dead_code)]
#[derive(Debug)] #[derive(Debug)]
pub struct Gemfeed { pub struct Gemfeed {
url: Url, url: Url,
title: String,
entries: Vec<GemfeedEntry>, entries: Vec<GemfeedEntry>,
} }
@ -114,10 +111,9 @@ impl Default for GemfeedParserSettings<'_> {
#[allow(dead_code)] #[allow(dead_code)]
impl Gemfeed { impl Gemfeed {
pub fn new(url: &Url, title: &str, entries: Vec<GemfeedEntry>) -> Gemfeed { pub fn new(url: &Url, entries: Vec<GemfeedEntry>) -> Gemfeed {
Gemfeed { Gemfeed {
url: url.clone(), url: url.clone(),
title: title.to_owned(),
entries, entries,
} }
} }
@ -144,10 +140,8 @@ impl Gemfeed {
settings: &GemfeedParserSettings, settings: &GemfeedParserSettings,
) -> Result<Gemfeed> { ) -> Result<Gemfeed> {
if let Some(content) = resp.content() { if let Some(content) = resp.content() {
let feed = content.parse::<AtomFeed>()?; let entries = parse_gemfeed_atom(content, settings)?;
let entries = parse_atom(&feed, settings)?; Ok(Self::new(url, entries))
let title = feed.title();
Ok(Self::new(url, title, entries))
} else { } else {
Err(anyhow!("Not a valid Atom Gemfeed")) Err(anyhow!("Not a valid Atom Gemfeed"))
} }
@ -159,24 +153,12 @@ impl Gemfeed {
.to_owned() .to_owned()
.map(|text| GemtextAst::from_value(&text)); .map(|text| GemtextAst::from_value(&text));
// TODO should be some actual validation of the feed here.
if let Some(ref feed) = maybe_feed { if let Some(ref feed) = maybe_feed {
Self::load_from_ast(url, feed) let entries = parse_gemfeed_gemtext(url, feed)?;
Ok(Self::new(url, entries))
} else { } else {
Err(anyhow!("Not a valid Gemfeed - could not parse gemtext")) Err(anyhow!("Not a valid Gemtext Gemfeed"))
}
}
fn load_from_ast(url: &Url, feed: &GemtextAst) -> Result<Gemfeed> {
let feed_title = feed.inner().iter().find_map(|node| match node {
GemtextNode::Heading { level, text } if *level == (1 as usize) => Some(text),
_ => None,
});
if let Some(title) = feed_title {
let entries = parse_gemfeed(url, feed)?;
Ok(Self::new(url, title, entries))
} else {
Err(anyhow!("Not a valid Gemfeed: missing title"))
} }
} }
@ -227,7 +209,7 @@ pub struct GemfeedEntry {
impl GemfeedEntry { impl GemfeedEntry {
pub fn from_ast(base_url: &Url, node: &GemtextNode) -> Result<GemfeedEntry> { pub fn from_ast(base_url: &Url, node: &GemtextNode) -> Result<GemfeedEntry> {
let link = GemfeedLink::try_from(node)?; let link = GemfeedLink::try_from(node)?;
// Gemfeeds have only the date--according to spec, it should be 12pm UTC. // Gemfeeds have only the date--lock to 12pm UTC as a guess.
println!("{:?}", link.published); println!("{:?}", link.published);
let publish_date = link let publish_date = link
.published .published
@ -409,29 +391,6 @@ impl TryFrom<&AtomEntry> for GemfeedLink {
mod gemfeed_tests { mod gemfeed_tests {
use super::*; use super::*;
#[test]
fn parse_gemfeed_invalid_if_no_title() -> Result<()> {
let gemfeed: String = r#"
This is a gemfeed without a title.
=> atom.xml Atom Feed
## Posts
=> post2.gmi 2023-03-05 Post 2
=> post1.gmi 2023-02-01 Post 1
"#
.lines()
.map(|line| line.trim_start())
.map(|line| format!("{}\n", line))
.collect();
let base_url = Url::parse("gemini://example.com/posts")?;
let ast = GemtextAst::from_string(gemfeed);
let result = Gemfeed::load_from_ast(&base_url, &ast);
assert!(matches!(result, Err(_)));
Ok(())
}
#[test] #[test]
fn parse_gemfeed_ignores_non_post_links() -> Result<()> { fn parse_gemfeed_ignores_non_post_links() -> Result<()> {
let gemfeed: String = r#" let gemfeed: String = r#"
@ -452,7 +411,7 @@ mod gemfeed_tests {
let base_url = Url::parse("gemini://example.com/posts")?; let base_url = Url::parse("gemini://example.com/posts")?;
let ast = GemtextAst::from_string(gemfeed); let ast = GemtextAst::from_string(gemfeed);
let results = parse_gemfeed(&base_url, &ast)?; let results = parse_gemfeed_gemtext(&base_url, &ast)?;
assert_eq!(results.len(), 2); assert_eq!(results.len(), 2);
Ok(()) Ok(())
} }
@ -476,13 +435,13 @@ mod gemfeed_tests {
let base_url = Url::parse("gemini://example.com/posts")?; let base_url = Url::parse("gemini://example.com/posts")?;
let ast = GemtextAst::from_string(gemfeed); let ast = GemtextAst::from_string(gemfeed);
let results = parse_gemfeed(&base_url, &ast)?; let results = parse_gemfeed_gemtext(&base_url, &ast)?;
assert_eq!(results.len(), 2); assert_eq!(results.len(), 2);
Ok(()) Ok(())
} }
#[test] #[test]
fn convert_gemfeed_links_success() -> Result<()> { fn convert_gemfeed_success() -> Result<()> {
let gemfeed_links: String = r#" let gemfeed_links: String = r#"
=> post2.gmi 2023-03-05 Post 2 => post2.gmi 2023-03-05 Post 2
=> post1.gmi 2023-02-01 Post 1 => post1.gmi 2023-02-01 Post 1