feed-rs 3.0.0

A feed parser that handles Atom, RSS 2.0, RSS 1.0, RSS 0.x and JSON Feed
Documentation
use crate::model::{Feed, Group, MediaObject, PodcastPerson, Role, Transcript};
use crate::parser::util::{if_some_then, parse_uri};
use crate::parser::{ParseFeedResult, common};
use crate::xml::{Element, NS};
use mediatype::MediaTypeBuf;
use std::io::BufRead;
use url::Url;

// Process <podcast> elements at channel level updating the Feed object as required
pub(crate) fn handle_podcast_channel_element<R: BufRead>(element: Element<R>, feed: &mut Feed) -> ParseFeedResult<()> {
    if let (NS::Podcast, "person") = element.ns_and_tag() {
        if_some_then(handle_person(element)?, |person| feed.people.push(person))
    }

    Ok(())
}

/// Process <podcast> elements at entry level updating the MediaObject as required
pub(crate) fn handle_podcast_item_element<R: BufRead>(element: Element<R>, media_obj: &mut MediaObject) -> ParseFeedResult<()> {
    match element.ns_and_tag() {
        (NS::Podcast, "person") => if_some_then(handle_person(element)?, |person| media_obj.people.push(person)),

        (NS::Podcast, "season") => if_some_then(common::handle_season(element), |season| media_obj.season = Some(season)),

        (NS::Podcast, "episode") => if_some_then(common::handle_episode(element), |episode| media_obj.episode = Some(episode)),

        (NS::Podcast, "transcript") => if_some_then(handle_transcript(element), |transcript| media_obj.transcripts.push(transcript)),

        // skip unknown properties
        _ => {}
    }

    Ok(())
}

// Handles <podcast:person>
fn handle_person<R: BufRead>(element: Element<R>) -> ParseFeedResult<Option<PodcastPerson>> {
    if let Some(role) = element.attr_value("role") {
        let role = Role::parse(element.buffer_pos, &role)?;
        if let Some(name) = element.child_as_text() {
            return Ok(Some(PodcastPerson {
                name,
                role,
                group: element
                    .attr_value("group")
                    .map(|g| Group::parse(element.buffer_pos, &g))
                    .transpose()?
                    .unwrap_or_default(),
                img: element.attr_value("img").and_then(|img| Url::parse(&img).ok()),
                href: element.attr_value("href").and_then(|href| Url::parse(&href).ok()),
            }));
        }
    }

    Ok(None)
}

// Handles <podcast:transcript>
fn handle_transcript<R: BufRead>(element: Element<R>) -> Option<Transcript> {
    if let Some(url) = element.attr_value("url").and_then(|url| parse_uri(&url, None)) {
        if let Some(content_type) = element.attr_value("type").and_then(|content_type| content_type.parse::<MediaTypeBuf>().ok()) {
            return Some(Transcript {
                url,
                content_type,
                language: None,
                rel: element.attr_value("rel"),
            });
        }
    }

    None
}