1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
use crate::itunes;
use crate::podcast;

use crate::basic;
use crate::language;
use crate::mime;
use crate::strings::{Url, UrlConstraint};
use crate::time;
use crate::Other;

#[derive(Debug, PartialEq, Default)]
pub struct Xml {
    pub rss: Rss,
}

/// RSS feed.
#[derive(Debug, PartialEq, Default)]
pub struct Rss {
    pub version: Option<String>,
    pub channel: Vec<Channel>,
}

/// Podcast feed.
#[derive(Debug, PartialEq, Default)]
pub struct Channel {
    pub category: Vec<String>,
    pub copyright: Vec<String>,
    pub description: Vec<String>,
    pub docs: Vec<Url>,
    pub generator: Vec<String>,
    pub item: Vec<Item>,
    pub language: Vec<language::Language>,
    pub last_build_date: Vec<time::DateTime>,
    pub link: Vec<Url>,
    pub managing_editor: Vec<String>,
    pub pub_date: Vec<time::DateTime>,
    pub title: Vec<String>,
    pub ttl: Vec<basic::Integer>,
    pub web_master: Vec<String>,

    pub content_encoded: Vec<String>,

    pub itunes_author: Vec<String>,
    pub itunes_block: Vec<itunes::Yes>,
    pub itunes_category: Vec<itunes::Category>,
    pub itunes_complete: Vec<itunes::Yes>,
    pub itunes_explicit: Vec<basic::Bool>,
    pub itunes_image: Vec<itunes::Image>,
    pub itunes_new_feed_url: Vec<Url>,
    pub itunes_owner: Vec<itunes::Owner>,
    pub itunes_type: Vec<itunes::PodcastType>,

    pub podcast_locked: Vec<podcast::Locked>,
    pub podcast_funding: Vec<podcast::Funding>,
    pub podcast_person: Vec<podcast::Person>,
    pub podcast_location: Vec<podcast::Location>,
    pub podcast_trailer: Vec<podcast::Trailer>,
    pub podcast_license: Vec<podcast::License>,
    pub podcast_guid: Vec<podcast::Guid>,
    pub podcast_value: Vec<podcast::Value>,
    pub podcast_medium: Vec<podcast::Medium>,
    pub podcast_images: Vec<podcast::Images>,
    pub podcast_live_item: Vec<podcast::LiveItem>,
    pub podcast_block: Vec<podcast::Block>,
    pub podcast_txt: Vec<podcast::Txt>,
    pub podcast_remote_item: Vec<podcast::RemoteItem>,
}

/// Podcast episode.
#[derive(Debug, PartialEq, Default)]
pub struct Item {
    pub description: Vec<String>,
    pub link: Vec<Url>,
    pub title: Vec<String>,
    pub enclosure: Vec<Enclosure>,
    pub guid: Vec<Guid>,
    pub pub_date: Vec<time::DateTime>,

    pub content_encoded: Vec<String>,

    pub itunes_block: Vec<itunes::Yes>,
    pub itunes_duration: Vec<itunes::Duration>,
    pub itunes_season: Vec<basic::Integer>,
    pub itunes_episode: Vec<basic::Integer>,
    pub itunes_explicit: Vec<basic::Bool>,
    pub itunes_image: Vec<itunes::Image>,
    pub itunes_title: Vec<String>,
    pub itunes_type: Vec<itunes::EpisodeType>,

    pub podcast_transcript: Vec<podcast::Transcript>,
    pub podcast_chapters: Vec<podcast::Chapters>,
    pub podcast_soundbite: Vec<podcast::Soundbite>,
    pub podcast_person: Vec<podcast::Person>,
    pub podcast_location: Vec<podcast::Location>,
    pub podcast_season: Vec<podcast::Season>,
    pub podcast_episode: Vec<podcast::Episode>,
    pub podcast_alternate_enclosure: Vec<podcast::AlternateEnclosure>,
    pub podcast_value: Vec<podcast::Value>,
    pub podcast_images: Vec<podcast::Images>,
    pub podcast_social_interact: Vec<podcast::SocialInteract>,
    pub podcast_license: Vec<podcast::License>,
    pub podcast_txt: Vec<podcast::Txt>,
}

/// Episode's media content.
#[derive(Debug, PartialEq, Eq, Default)]
pub struct Enclosure {
    pub url: Option<Url>,
    pub length: Option<basic::Integer>,
    pub type_: Option<mime::Enclosure>,
}

/// Episode's globally unique identifier.
#[derive(Debug, PartialEq, Eq, Default)]
pub struct Guid {
    pub is_permalink: Option<basic::Bool>,
    pub value: Option<GuidValue>,
}

/// GUID's value.
#[derive(Debug, PartialEq, Eq)]
pub enum GuidValue {
    Url(url::Url),
    Text(String),
    Other(Other),
}

impl GuidValue {
    pub fn parse(value: &str, is_permalink: &Option<basic::Bool>) -> Self {
        match Url::parse(value, UrlConstraint::HttpOrHttps) {
            Url::Ok(url) => GuidValue::Url(url),
            Url::Other(_) => match is_permalink {
                Some(basic::Bool::Ok(true)) => GuidValue::Other((
                    value.to_string(),
                    "should be a URL when `isPermalink` is true".to_string(),
                )),
                None => GuidValue::Other((
                    value.to_string(),
                    "should be a URL when `isPermalink` is not set".to_string(),
                )),
                _ => GuidValue::Text(value.to_string()),
            },
        }
    }
}