Skip to content

Commit

Permalink
add feed meta to item
Browse files Browse the repository at this point in the history
  • Loading branch information
morphy2k committed Sep 13, 2021
1 parent 90730a6 commit 2f8d31f
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 23 deletions.
75 changes: 55 additions & 20 deletions src/feed/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ pub trait FeedItem<'a>: Sync {
fn date(&'a self) -> DateTime<FixedOffset>;

fn authors(&'a self) -> Vec<Author>;

/// Feed metadata
fn source(&'a self) -> Option<&Source>;
}

pub trait TryFromItem<'a, T>
Expand Down Expand Up @@ -89,6 +92,10 @@ impl<'a> FeedItem<'a> for rss::Item {
None => Vec::default(),
}
}

fn source(&'a self) -> Option<&Source> {
None
}
}

impl<'a> FeedItem<'a> for atom_syndication::Entry {
Expand Down Expand Up @@ -173,6 +180,10 @@ impl<'a> FeedItem<'a> for atom_syndication::Entry {
})
.collect()
}

fn source(&'a self) -> Option<&Source> {
None
}
}

#[derive(Debug, Serialize)]
Expand All @@ -182,81 +193,105 @@ pub struct Author<'a> {
pub uri: Option<&'a str>,
}

#[derive(Debug, Clone, Serialize)]
pub struct Source<'a> {
pub title: &'a str,
pub url: Option<&'a str>,
}

pub enum Item<'a> {
Rss(&'a rss::Item),
Atom(&'a atom_syndication::Entry),
Rss {
source: Source<'a>,
item: &'a rss::Item,
},
Atom {
source: Source<'a>,
entry: &'a atom_syndication::Entry,
},
}

impl<'a> FeedItem<'a> for Item<'a> {
#[inline]
fn title(&self) -> Option<&str> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::title(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::title(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::title(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::title(entry),
}
}

#[inline]
fn title_as_text(&self) -> Option<String> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::title_as_text(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::title_as_text(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::title_as_text(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::title_as_text(entry),
}
}

#[inline]
fn description(&self) -> Option<&str> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::description(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::description(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::description(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::description(entry),
}
}

#[inline]
fn description_as_text(&self) -> Option<String> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::description_as_text(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::description_as_text(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::description_as_text(item),
Item::Atom { entry, .. } => {
<atom_syndication::Entry as FeedItem>::description_as_text(entry)
}
}
}

#[inline]
fn content(&self) -> Option<&str> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::content(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::content(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::content(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::content(entry),
}
}

#[inline]
fn content_as_text(&self) -> Option<String> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::content_as_text(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::content_as_text(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::content_as_text(item),
Item::Atom { entry, .. } => {
<atom_syndication::Entry as FeedItem>::content_as_text(entry)
}
}
}

#[inline]
fn link(&self) -> Option<&str> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::link(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::link(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::link(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::link(entry),
}
}

#[inline]
fn date(&self) -> DateTime<FixedOffset> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::date(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::date(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::date(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::date(entry),
}
}

#[inline]
fn authors(&self) -> Vec<Author> {
match self {
Item::Rss(i) => <rss::Item as FeedItem>::authors(i),
Item::Atom(e) => <atom_syndication::Entry as FeedItem>::authors(e),
Item::Rss { item, .. } => <rss::Item as FeedItem>::authors(item),
Item::Atom { entry, .. } => <atom_syndication::Entry as FeedItem>::authors(entry),
}
}

#[inline]
fn source(&'a self) -> Option<&Source> {
match self {
Item::Rss { source, .. } => Some(source),
Item::Atom { source, .. } => Some(source),
}
}
}
36 changes: 33 additions & 3 deletions src/feed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ pub mod item;

use crate::error::FeedError;

use self::item::{FeedItem, Item};
use self::item::{FeedItem, Item, Source};

use std::{cmp::Reverse, io::BufRead};

Expand Down Expand Up @@ -38,10 +38,40 @@ impl<'a> Feed {
}
}

pub fn link(&self) -> Option<&str> {
match self {
Feed::Rss(c) => Some(c.link()),
Feed::Atom(f) => f
.links()
.iter()
.find(|s| s.rel() == "alternate")
.map(|s| s.href()),
}
}

pub fn items(&'a self) -> Vec<Item<'a>> {
let source: Source<'a> = Source {
title: self.title(),
url: self.link(),
};

let mut items: Vec<Item<'a>> = match self {
Feed::Rss(c) => c.items().iter().map(|v| Item::Rss(v)).collect(),
Feed::Atom(f) => f.entries().iter().map(|v| Item::Atom(v)).collect(),
Feed::Rss(c) => c
.items()
.iter()
.map(|v| Item::Rss {
source: source.clone(),
item: v,
})
.collect(),
Feed::Atom(f) => f
.entries()
.iter()
.map(|v| Item::Atom {
source: source.clone(),
entry: v,
})
.collect(),
};

items.sort_unstable_by_key(|v| Reverse(v.date()));
Expand Down

0 comments on commit 2f8d31f

Please sign in to comment.