Gemfeed parsing now requires a title.
This commit is contained in:
parent
c4aaa11fc2
commit
dbddde049e
|
@ -38,9 +38,10 @@ fn parse_gemfeed_gemtext(base_url: &Url, gemfeed: &GemtextAst) -> Result<Vec<Gem
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_gemfeed_atom(feed: &str, settings: &GemfeedParserSettings) -> Result<Vec<GemfeedEntry>> {
|
fn parse_gemfeed_atom(
|
||||||
let feed = feed.parse::<AtomFeed>()?;
|
feed: &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))
|
||||||
|
@ -75,9 +76,11 @@ 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>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,9 +114,10 @@ impl Default for GemfeedParserSettings<'_> {
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
impl Gemfeed {
|
impl Gemfeed {
|
||||||
pub fn new(url: &Url, entries: Vec<GemfeedEntry>) -> Gemfeed {
|
pub fn new(url: &Url, title: &str, entries: Vec<GemfeedEntry>) -> Gemfeed {
|
||||||
Gemfeed {
|
Gemfeed {
|
||||||
url: url.clone(),
|
url: url.clone(),
|
||||||
|
title: title.to_owned(),
|
||||||
entries,
|
entries,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,8 +144,10 @@ impl Gemfeed {
|
||||||
settings: &GemfeedParserSettings,
|
settings: &GemfeedParserSettings,
|
||||||
) -> Result<Gemfeed> {
|
) -> Result<Gemfeed> {
|
||||||
if let Some(content) = resp.content() {
|
if let Some(content) = resp.content() {
|
||||||
let entries = parse_gemfeed_atom(content, settings)?;
|
let feed = content.parse::<AtomFeed>()?;
|
||||||
Ok(Self::new(url, entries))
|
let entries = parse_gemfeed_atom(&feed, settings)?;
|
||||||
|
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"))
|
||||||
}
|
}
|
||||||
|
@ -153,12 +159,24 @@ 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 {
|
||||||
let entries = parse_gemfeed_gemtext(url, feed)?;
|
Self::load_from_ast(url, feed)
|
||||||
Ok(Self::new(url, entries))
|
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("Not a valid Gemtext Gemfeed"))
|
Err(anyhow!("Not a valid Gemfeed - could not parse gemtext"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_gemtext(url, feed)?;
|
||||||
|
Ok(Self::new(url, title, entries))
|
||||||
|
} else {
|
||||||
|
Err(anyhow!("Not a valid Gemfeed: missing title"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -209,7 +227,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--lock to 12pm UTC as a guess.
|
// Gemfeeds have only the date--according to spec, it should be 12pm UTC.
|
||||||
println!("{:?}", link.published);
|
println!("{:?}", link.published);
|
||||||
let publish_date = link
|
let publish_date = link
|
||||||
.published
|
.published
|
||||||
|
@ -391,6 +409,29 @@ 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#"
|
||||||
|
@ -441,7 +482,7 @@ mod gemfeed_tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn convert_gemfeed_success() -> Result<()> {
|
fn convert_gemfeed_links_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
|
||||||
|
|
Loading…
Reference in New Issue