per [official recommendation](https://help.apple.com/itc/podcasts_connect/#/itcb54353390)master
| @@ -2,12 +2,15 @@ import 'package:webfeed/util/helpers.dart'; | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| import 'rss_itunes_category.dart'; | import 'rss_itunes_category.dart'; | ||||
| import 'rss_itunes_episode_type.dart'; | |||||
| import 'rss_itunes_image.dart'; | import 'rss_itunes_image.dart'; | ||||
| class RssItemItunes { | class RssItemItunes { | ||||
| final String title; | |||||
| final int episode; | final int episode; | ||||
| final int season; | |||||
| final Duration duration; | final Duration duration; | ||||
| final String episodeType; | |||||
| final RssItunesEpisodeType episodeType; | |||||
| final String author; | final String author; | ||||
| final String summary; | final String summary; | ||||
| final bool explicit; | final bool explicit; | ||||
| @@ -15,9 +18,12 @@ class RssItemItunes { | |||||
| final List<String> keywords; | final List<String> keywords; | ||||
| final RssItunesImage image; | final RssItunesImage image; | ||||
| final RssItunesCategory category; | final RssItunesCategory category; | ||||
| final bool block; | |||||
| RssItemItunes({ | RssItemItunes({ | ||||
| this.title, | |||||
| this.episode, | this.episode, | ||||
| this.season, | |||||
| this.duration, | this.duration, | ||||
| this.episodeType, | this.episodeType, | ||||
| this.author, | this.author, | ||||
| @@ -27,31 +33,32 @@ class RssItemItunes { | |||||
| this.keywords, | this.keywords, | ||||
| this.image, | this.image, | ||||
| this.category, | this.category, | ||||
| this.block, | |||||
| }); | }); | ||||
| factory RssItemItunes.parse(XmlElement element) { | factory RssItemItunes.parse(XmlElement element) { | ||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| var explicitStr = | |||||
| findElementOrNull(element, "itunes:explicit")?.text?.toLowerCase()?.trim(); | |||||
| var episodeStr = findElementOrNull(element, "itunes:episode")?.text?.trim(); | var episodeStr = findElementOrNull(element, "itunes:episode")?.text?.trim(); | ||||
| var seasonStr = findElementOrNull(element, "itunes:season")?.text?.trim(); | |||||
| var durationStr = findElementOrNull(element, "itunes:duration")?.text?.trim(); | var durationStr = findElementOrNull(element, "itunes:duration")?.text?.trim(); | ||||
| return RssItemItunes( | return RssItemItunes( | ||||
| title: findElementOrNull(element, "itunes:title")?.text?.trim(), | |||||
| episode: episodeStr == null ? null : int.parse(episodeStr), | episode: episodeStr == null ? null : int.parse(episodeStr), | ||||
| season: seasonStr == null ? null : int.parse(seasonStr), | |||||
| duration: durationStr == null ? null : parseDuration(durationStr), | duration: durationStr == null ? null : parseDuration(durationStr), | ||||
| episodeType: findElementOrNull(element, "itunes:episodeType")?.text?.trim(), | |||||
| episodeType: newRssItunesEpisodeType(findElementOrNull(element, "itunes:episodeType")), | |||||
| author: findElementOrNull(element, "itunes:author")?.text?.trim(), | author: findElementOrNull(element, "itunes:author")?.text?.trim(), | ||||
| summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), | summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), | ||||
| explicit: explicitStr == null | |||||
| ? null | |||||
| : explicitStr == "yes" || explicitStr == "true", | |||||
| explicit: parseBoolLiteral(element, "itunes:explicit"), | |||||
| subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), | subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), | ||||
| keywords: findElementOrNull(element, "itunes:keywords")?.text?.split(",")?.map((keyword) => keyword.trim())?.toList(), | keywords: findElementOrNull(element, "itunes:keywords")?.text?.split(",")?.map((keyword) => keyword.trim())?.toList(), | ||||
| image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), | image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), | ||||
| category: RssItunesCategory.parse( | category: RssItunesCategory.parse( | ||||
| findElementOrNull(element, "itunes:category")), | findElementOrNull(element, "itunes:category")), | ||||
| block: parseBoolLiteral(element, "itunes:block"), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -4,62 +4,66 @@ import 'package:webfeed/util/helpers.dart'; | |||||
| import 'rss_itunes_category.dart'; | import 'rss_itunes_category.dart'; | ||||
| import 'rss_itunes_image.dart'; | import 'rss_itunes_image.dart'; | ||||
| import 'rss_itunes_owner.dart'; | |||||
| import 'rss_itunes_type.dart'; | |||||
| class RssItunes { | class RssItunes { | ||||
| final String author; | final String author; | ||||
| final String summary; | final String summary; | ||||
| final bool explicit; | final bool explicit; | ||||
| final String title; | |||||
| final String subtitle; | final String subtitle; | ||||
| final RssItunesOwner owner; | final RssItunesOwner owner; | ||||
| final List<String> keywords; | final List<String> keywords; | ||||
| final RssItunesImage image; | final RssItunesImage image; | ||||
| final RssItunesCategory category; | |||||
| final List<RssItunesCategory> categories; | |||||
| final RssItunesType type; | |||||
| final String newFeedUrl; | |||||
| final bool block; | |||||
| final bool complete; | |||||
| RssItunes({ | RssItunes({ | ||||
| this.author, | this.author, | ||||
| this.summary, | this.summary, | ||||
| this.explicit, | this.explicit, | ||||
| this.title, | |||||
| this.subtitle, | this.subtitle, | ||||
| this.owner, | this.owner, | ||||
| this.keywords, | this.keywords, | ||||
| this.image, | this.image, | ||||
| this.category, | |||||
| this.categories, | |||||
| this.type, | |||||
| this.newFeedUrl, | |||||
| this.block, | |||||
| this.complete, | |||||
| }); | }); | ||||
| factory RssItunes.parse(XmlElement element) { | factory RssItunes.parse(XmlElement element) { | ||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| var explicitStr = | |||||
| findElementOrNull(element, "itunes:explicit")?.text?.toLowerCase()?.trim(); | |||||
| return RssItunes( | return RssItunes( | ||||
| author: findElementOrNull(element, "itunes:author")?.text?.trim(), | author: findElementOrNull(element, "itunes:author")?.text?.trim(), | ||||
| summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), | summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), | ||||
| explicit: explicitStr == null | |||||
| ? null | |||||
| : explicitStr == "yes" || explicitStr == "true", | |||||
| explicit: parseBoolLiteral(element, "itunes:explicit"), | |||||
| title: findElementOrNull(element, "itunes:title")?.text?.trim(), | |||||
| subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), | subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), | ||||
| owner: RssItunesOwner.parse(findElementOrNull(element, "itunes:owner")), | owner: RssItunesOwner.parse(findElementOrNull(element, "itunes:owner")), | ||||
| keywords: findElementOrNull(element, "itunes:keywords")?.text?.split(",")?.map((keyword) => keyword.trim())?.toList(), | |||||
| keywords: findElementOrNull(element, "itunes:keywords") | |||||
| ?.text | |||||
| ?.split(",") | |||||
| ?.map((keyword) => keyword.trim()) | |||||
| ?.toList(), | |||||
| image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), | image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), | ||||
| category: RssItunesCategory.parse( | |||||
| findElementOrNull(element, "itunes:category")), | |||||
| categories: findAllDirectElementsOrNull(element, "itunes:category") | |||||
| .map((ele) => RssItunesCategory.parse(ele)) | |||||
| .toList(), | |||||
| type: newRssItunesType(findElementOrNull(element, "itunes:type")), | |||||
| newFeedUrl: | |||||
| findElementOrNull(element, "itunes:new-feed-url")?.text?.trim(), | |||||
| block: parseBoolLiteral(element, "itunes:block"), | |||||
| complete: parseBoolLiteral(element, "itunes:complete"), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| class RssItunesOwner { | |||||
| final String name; | |||||
| final String email; | |||||
| RssItunesOwner({this.name, this.email}); | |||||
| factory RssItunesOwner.parse(XmlElement element) { | |||||
| if (element == null) return null; | |||||
| return RssItunesOwner( | |||||
| name: findElementOrNull(element, "itunes:name")?.text?.trim(), | |||||
| email: findElementOrNull(element, "itunes:email")?.text?.trim(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -11,7 +11,7 @@ class RssItunesCategory { | |||||
| Iterable<XmlElement> subCategories; | Iterable<XmlElement> subCategories; | ||||
| try { | try { | ||||
| subCategories = element.findAllElements("itunes:category"); | |||||
| subCategories = element.findElements("itunes:category"); | |||||
| } on StateError { | } on StateError { | ||||
| subCategories = null; | subCategories = null; | ||||
| } | } | ||||
| @@ -0,0 +1,19 @@ | |||||
| import 'package:xml/xml.dart'; | |||||
| enum RssItunesEpisodeType {full, trailer, bonus} | |||||
| RssItunesEpisodeType newRssItunesEpisodeType(XmlElement element) { | |||||
| // "full" is default type | |||||
| if (element == null) return RssItunesEpisodeType.full; | |||||
| switch (element.text) { | |||||
| case "full": | |||||
| return RssItunesEpisodeType.full; | |||||
| case "trailer": | |||||
| return RssItunesEpisodeType.trailer; | |||||
| case "bonus": | |||||
| return RssItunesEpisodeType.bonus; | |||||
| default: | |||||
| return null; | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,18 @@ | |||||
| import 'package:xml/xml.dart'; | |||||
| import '../util/helpers.dart'; | |||||
| class RssItunesOwner { | |||||
| final String name; | |||||
| final String email; | |||||
| RssItunesOwner({this.name, this.email}); | |||||
| factory RssItunesOwner.parse(XmlElement element) { | |||||
| if (element == null) return null; | |||||
| return RssItunesOwner( | |||||
| name: findElementOrNull(element, "itunes:name")?.text?.trim(), | |||||
| email: findElementOrNull(element, "itunes:email")?.text?.trim(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,17 @@ | |||||
| import 'package:xml/xml.dart'; | |||||
| enum RssItunesType { episodic, serial } | |||||
| RssItunesType newRssItunesType(XmlElement element) { | |||||
| // "episodic" is default type | |||||
| if (element == null) return RssItunesType.episodic; | |||||
| switch (element.text) { | |||||
| case "episodic": | |||||
| return RssItunesType.episodic; | |||||
| case "serial": | |||||
| return RssItunesType.serial; | |||||
| default: | |||||
| return null; | |||||
| } | |||||
| } | |||||
| @@ -2,10 +2,27 @@ import 'dart:core'; | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| XmlElement findElementOrNull(XmlElement element, String name, {String namespace}) { | |||||
| XmlElement findElementOrNull(XmlElement element, String name, | |||||
| {String namespace}) { | |||||
| try { | try { | ||||
| return element.findAllElements(name, namespace: namespace).first; | return element.findAllElements(name, namespace: namespace).first; | ||||
| } on StateError { | } on StateError { | ||||
| return null; | return null; | ||||
| } | } | ||||
| } | } | ||||
| List<XmlElement> findAllDirectElementsOrNull(XmlElement element, String name, | |||||
| {String namespace}) { | |||||
| try { | |||||
| return element.findElements(name, namespace: namespace).toList(); | |||||
| } on StateError { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| bool parseBoolLiteral(XmlElement element, String tagName) { | |||||
| var v = findElementOrNull(element, tagName)?.text?.toLowerCase()?.trim(); | |||||
| if (v == null) return null; | |||||
| return ["yes", "true"].contains(v); | |||||
| } | |||||
| @@ -4,6 +4,9 @@ import 'dart:io'; | |||||
| import 'package:test/test.dart'; | import 'package:test/test.dart'; | ||||
| import 'package:webfeed/webfeed.dart'; | import 'package:webfeed/webfeed.dart'; | ||||
| import 'package:webfeed/domain/rss_itunes_type.dart'; | |||||
| import 'package:webfeed/domain/rss_itunes_episode_type.dart'; | |||||
| void main() { | void main() { | ||||
| test("parse Invalid.xml", () { | test("parse Invalid.xml", () { | ||||
| var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); | var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); | ||||
| @@ -19,7 +22,8 @@ void main() { | |||||
| var feed = new RssFeed.parse(xmlString); | var feed = new RssFeed.parse(xmlString); | ||||
| expect(feed.title, "News - Foo bar News"); | expect(feed.title, "News - Foo bar News"); | ||||
| expect(feed.description, "Foo bar News and Updates feed provided by Foo bar, Inc."); | |||||
| expect(feed.description, | |||||
| "Foo bar News and Updates feed provided by Foo bar, Inc."); | |||||
| expect(feed.link, "https://foo.bar.news/"); | expect(feed.link, "https://foo.bar.news/"); | ||||
| expect(feed.author, "hello@world.net"); | expect(feed.author, "hello@world.net"); | ||||
| expect(feed.language, "en-US"); | expect(feed.language, "en-US"); | ||||
| @@ -62,8 +66,10 @@ void main() { | |||||
| expect(feed.items.length, 2); | expect(feed.items.length, 2); | ||||
| expect(feed.items.first.title, "The standard Lorem Ipsum passage, used since the 1500s"); | |||||
| expect(feed.items.first.description, "Lorem ipsum dolor sit amet, consectetur adipiscing elit"); | |||||
| expect(feed.items.first.title, | |||||
| "The standard Lorem Ipsum passage, used since the 1500s"); | |||||
| expect(feed.items.first.description, | |||||
| "Lorem ipsum dolor sit amet, consectetur adipiscing elit"); | |||||
| expect(feed.items.first.link, "https://foo.bar.news/1"); | expect(feed.items.first.link, "https://foo.bar.news/1"); | ||||
| expect(feed.items.first.guid, "https://foo.bar.news/1?guid"); | expect(feed.items.first.guid, "https://foo.bar.news/1?guid"); | ||||
| expect(feed.items.first.pubDate, "Mon, 26 Mar 2018 14:00:00 PDT"); | expect(feed.items.first.pubDate, "Mon, 26 Mar 2018 14:00:00 PDT"); | ||||
| @@ -73,22 +79,26 @@ void main() { | |||||
| expect(feed.items.first.source.url, "https://foo.bar.news/1?source"); | expect(feed.items.first.source.url, "https://foo.bar.news/1?source"); | ||||
| expect(feed.items.first.source.value, "Foo Bar"); | expect(feed.items.first.source.value, "Foo Bar"); | ||||
| expect(feed.items.first.comments, "https://foo.bar.news/1/comments"); | expect(feed.items.first.comments, "https://foo.bar.news/1/comments"); | ||||
| expect(feed.items.first.enclosure.url, "http://www.scripting.com/mp3s/weatherReportSuite.mp3"); | |||||
| expect(feed.items.first.enclosure.url, | |||||
| "http://www.scripting.com/mp3s/weatherReportSuite.mp3"); | |||||
| expect(feed.items.first.enclosure.length, 12216320); | expect(feed.items.first.enclosure.length, 12216320); | ||||
| expect(feed.items.first.enclosure.type, "audio/mpeg"); | expect(feed.items.first.enclosure.type, "audio/mpeg"); | ||||
| expect(feed.items.first.content.value, "<img width=\"1000\" height=\"690\" src=\"https://test.com/image_link\"/> Test content<br />"); | |||||
| expect(feed.items.first.content.images.first, "https://test.com/image_link"); | |||||
| expect(feed.items.first.content.value, | |||||
| "<img width=\"1000\" height=\"690\" src=\"https://test.com/image_link\"/> Test content<br />"); | |||||
| expect( | |||||
| feed.items.first.content.images.first, "https://test.com/image_link"); | |||||
| }); | }); | ||||
| test("parse RSS-Media.xml", (){ | |||||
| test("parse RSS-Media.xml", () { | |||||
| var xmlString = new File("test/xml/RSS-Media.xml").readAsStringSync(); | var xmlString = new File("test/xml/RSS-Media.xml").readAsStringSync(); | ||||
| var feed = new RssFeed.parse(xmlString); | var feed = new RssFeed.parse(xmlString); | ||||
| expect(feed.title, "Song Site"); | expect(feed.title, "Song Site"); | ||||
| expect(feed.description, "Media RSS example with new fields added in v1.5.0"); | |||||
| expect( | |||||
| feed.description, "Media RSS example with new fields added in v1.5.0"); | |||||
| expect(feed.items.length, 1); | expect(feed.items.length, 1); | ||||
| var item = feed.items.first; | var item = feed.items.first; | ||||
| expect(item.title, null); | expect(item.title, null); | ||||
| expect(item.link, "http://www.foo.com"); | expect(item.link, "http://www.foo.com"); | ||||
| @@ -118,7 +128,8 @@ void main() { | |||||
| expect(mediaCredit.scheme, "urn:yvs"); | expect(mediaCredit.scheme, "urn:yvs"); | ||||
| expect(mediaCredit.value, "copyright holder of the entity"); | expect(mediaCredit.value, "copyright holder of the entity"); | ||||
| expect(item.media.category.scheme, "http://search.yahoo.com/mrss/category_ schema"); | |||||
| expect(item.media.category.scheme, | |||||
| "http://search.yahoo.com/mrss/category_ schema"); | |||||
| expect(item.media.category.label, "Music"); | expect(item.media.category.label, "Music"); | ||||
| expect(item.media.category.value, "music/artist/album/song"); | expect(item.media.category.value, "music/artist/album/song"); | ||||
| @@ -129,10 +140,11 @@ void main() { | |||||
| expect(item.media.title.value, "The Judy's -- The Moo Song"); | expect(item.media.title.value, "The Judy's -- The Moo Song"); | ||||
| expect(item.media.description.type, "plain"); | expect(item.media.description.type, "plain"); | ||||
| expect(item.media.description.value, "This was some really bizarre band I listened to as a young lad."); | |||||
| expect(item.media.description.value, | |||||
| "This was some really bizarre band I listened to as a young lad."); | |||||
| expect(item.media.keywords, "kitty, cat, big dog, yarn, fluffy"); | expect(item.media.keywords, "kitty, cat, big dog, yarn, fluffy"); | ||||
| expect(item.media.thumbnails.length, 2); | expect(item.media.thumbnails.length, 2); | ||||
| var mediaThumbnail = item.media.thumbnails.first; | var mediaThumbnail = item.media.thumbnails.first; | ||||
| expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); | expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); | ||||
| @@ -179,7 +191,8 @@ void main() { | |||||
| expect(item.media.embed.height, 323); | expect(item.media.embed.height, 323); | ||||
| expect(item.media.embed.params.length, 5); | expect(item.media.embed.params.length, 5); | ||||
| expect(item.media.embed.params.first.name, "type"); | expect(item.media.embed.params.first.name, "type"); | ||||
| expect(item.media.embed.params.first.value, "application/x-shockwave-flash"); | |||||
| expect( | |||||
| item.media.embed.params.first.value, "application/x-shockwave-flash"); | |||||
| expect(item.media.responses.length, 2); | expect(item.media.responses.length, 2); | ||||
| expect(item.media.responses.first, "http://www.response1.com"); | expect(item.media.responses.first, "http://www.response1.com"); | ||||
| @@ -195,7 +208,8 @@ void main() { | |||||
| expect(item.media.prices.length, 2); | expect(item.media.prices.length, 2); | ||||
| expect(item.media.prices.first.price, 19.99); | expect(item.media.prices.first.price, 19.99); | ||||
| expect(item.media.prices.first.type, "rent"); | expect(item.media.prices.first.type, "rent"); | ||||
| expect(item.media.prices.first.info, "http://www.dummy.jp/package_info.html"); | |||||
| expect( | |||||
| item.media.prices.first.info, "http://www.dummy.jp/package_info.html"); | |||||
| expect(item.media.prices.first.currency, "EUR"); | expect(item.media.prices.first.currency, "EUR"); | ||||
| expect(item.media.license.type, "text/html"); | expect(item.media.license.type, "text/html"); | ||||
| @@ -214,7 +228,7 @@ void main() { | |||||
| expect(item.media.scenes.first.startTime, "00:15"); | expect(item.media.scenes.first.startTime, "00:15"); | ||||
| expect(item.media.scenes.first.endTime, "00:45"); | expect(item.media.scenes.first.endTime, "00:45"); | ||||
| }); | }); | ||||
| test("parse RSS-DC.xml", (){ | |||||
| test("parse RSS-DC.xml", () { | |||||
| var xmlString = File("test/xml/RSS-DC.xml").readAsStringSync(); | var xmlString = File("test/xml/RSS-DC.xml").readAsStringSync(); | ||||
| var feed = RssFeed.parse(xmlString); | var feed = RssFeed.parse(xmlString); | ||||
| @@ -256,7 +270,7 @@ void main() { | |||||
| var xmlString = File("test/xml/RSS-Empty.xml").readAsStringSync(); | var xmlString = File("test/xml/RSS-Empty.xml").readAsStringSync(); | ||||
| var feed = RssFeed.parse(xmlString); | var feed = RssFeed.parse(xmlString); | ||||
| expect(feed.title, null); | expect(feed.title, null); | ||||
| expect(feed.description, null); | expect(feed.description, null); | ||||
| expect(feed.link, null); | expect(feed.link, null); | ||||
| @@ -304,22 +318,50 @@ void main() { | |||||
| expect(feed.itunes.author, "Changelog Media"); | expect(feed.itunes.author, "Changelog Media"); | ||||
| expect(feed.itunes.summary, "Foo"); | expect(feed.itunes.summary, "Foo"); | ||||
| expect(feed.itunes.explicit, false); | expect(feed.itunes.explicit, false); | ||||
| expect(feed.itunes.image.href, "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); | |||||
| expect(feed.itunes.keywords, "go,golang,open source,software,development".split(",")); | |||||
| expect(feed.itunes.image.href, | |||||
| "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); | |||||
| expect(feed.itunes.keywords, | |||||
| "go,golang,open source,software,development".split(",")); | |||||
| expect(feed.itunes.owner.name, "Changelog Media"); | expect(feed.itunes.owner.name, "Changelog Media"); | ||||
| expect(feed.itunes.owner.email, "editors@changelog.com"); | expect(feed.itunes.owner.email, "editors@changelog.com"); | ||||
| expect(feed.itunes.category.category, "Technology"); | |||||
| expect(feed.itunes.category.subCategories, ["Software How-To", "Tech News"]); | |||||
| expect( | |||||
| Set.from([ | |||||
| feed.itunes.categories[0].category, | |||||
| feed.itunes.categories[1].category | |||||
| ]), | |||||
| ["Technology", "Foo"]); | |||||
| for (var category in feed.itunes.categories) { | |||||
| switch (category.category) { | |||||
| case "Foo": | |||||
| expect(category.subCategories, ["Bar", "Baz"]); | |||||
| break; | |||||
| case "Technology": | |||||
| expect(category.subCategories, ["Software How-To", "Tech News"]); | |||||
| break; | |||||
| } | |||||
| } | |||||
| expect(feed.itunes.title, "Go Time"); | |||||
| expect(feed.itunes.type, RssItunesType.serial); | |||||
| expect(feed.itunes.newFeedUrl, "wubawuba"); | |||||
| expect(feed.itunes.block, true); | |||||
| expect(feed.itunes.complete, true); | |||||
| var item = feed.items[0]; | var item = feed.items[0]; | ||||
| expect(item.itunes.episodeType, "full"); | |||||
| expect(item.itunes.episodeType, RssItunesEpisodeType.full); | |||||
| expect(item.itunes.episode, 1); | expect(item.itunes.episode, 1); | ||||
| expect(item.itunes.image.href, "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); | |||||
| expect(item.itunes.season, 1); | |||||
| expect(item.itunes.image.href, | |||||
| "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); | |||||
| expect(item.itunes.duration, Duration(minutes: 32, seconds: 30)); | expect(item.itunes.duration, Duration(minutes: 32, seconds: 30)); | ||||
| expect(item.itunes.explicit, false); | expect(item.itunes.explicit, false); | ||||
| expect(item.itunes.keywords, "go,golang,open source,software,development".split(",")); | |||||
| expect(item.itunes.keywords, | |||||
| "go,golang,open source,software,development".split(",")); | |||||
| expect(item.itunes.subtitle, "with Erik, Carlisia, and Brian"); | expect(item.itunes.subtitle, "with Erik, Carlisia, and Brian"); | ||||
| expect(item.itunes.summary, "Foo"); | expect(item.itunes.summary, "Foo"); | ||||
| expect(item.itunes.author, "Erik St. Martin, Carlisia Pinto, and Brian Ketelsen"); | |||||
| expect(item.itunes.author, | |||||
| "Erik St. Martin, Carlisia Pinto, and Brian Ketelsen"); | |||||
| expect(item.itunes.explicit, false); | |||||
| expect(item.itunes.title, "awesome title"); | |||||
| expect(item.itunes.block, false); | |||||
| }); | }); | ||||
| } | } | ||||
| @@ -1,6 +1,11 @@ | |||||
| <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0" nighteye="disabled"> | <rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" version="2.0" nighteye="disabled"> | ||||
| <channel> | <channel> | ||||
| <title>Go Time</title> | <title>Go Time</title> | ||||
| <itunes:title>Go Time</itunes:title> | |||||
| <itunes:type>serial</itunes:type> | |||||
| <itunes:block>Yes</itunes:block> | |||||
| <itunes:complete>TRUE</itunes:complete> | |||||
| <itunes:new-feed-url>wubawuba</itunes:new-feed-url> | |||||
| <copyright>All rights reserved</copyright> | <copyright>All rights reserved</copyright> | ||||
| <link>https://changelog.com/gotime</link> | <link>https://changelog.com/gotime</link> | ||||
| <atom:link href="https://changelog.com/gotime/feed" rel="self" type="application/rss+xml"/> | <atom:link href="https://changelog.com/gotime/feed" rel="self" type="application/rss+xml"/> | ||||
| @@ -24,9 +29,16 @@ | |||||
| <itunes:category text="Software How-To"/> | <itunes:category text="Software How-To"/> | ||||
| <itunes:category text="Tech News"/> | <itunes:category text="Tech News"/> | ||||
| </itunes:category> | </itunes:category> | ||||
| <itunes:category text="Foo"> | |||||
| <itunes:category text="Bar"/> | |||||
| <itunes:category text="Baz"/> | |||||
| </itunes:category> | |||||
| <item> | <item> | ||||
| <itunes:title>awesome title</itunes:title> | |||||
| <itunes:episodeType>full</itunes:episodeType> | <itunes:episodeType>full</itunes:episodeType> | ||||
| <itunes:episode>1</itunes:episode> | <itunes:episode>1</itunes:episode> | ||||
| <itunes:season>1</itunes:season> | |||||
| <itunes:block>xxx</itunes:block> | |||||
| <itunes:image href="https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"/> | <itunes:image href="https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"/> | ||||
| <itunes:duration>32:30</itunes:duration> | <itunes:duration>32:30</itunes:duration> | ||||
| <itunes:explicit>no</itunes:explicit> | <itunes:explicit>no</itunes:explicit> | ||||