diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml new file mode 100644 index 0000000..cfd5a3a --- /dev/null +++ b/.github/workflows/dart.yml @@ -0,0 +1,19 @@ +name: Dart CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + container: + image: google/dart:latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: pub get + - name: Run tests + run: pub run test diff --git a/CHANGELOG.md b/CHANGELOG.md index 901904c..3c8d64f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,27 @@ # Changelog +## [0.6.0](https://pub.dartlang.org/packages/webfeed/versions/0.6.0) +- Refactor util/xml.dart +- Support RDF feed +- Support Syndication namespace + +## [0.5.2](https://pub.dartlang.org/packages/webfeed/versions/0.5.2) +- Lower the xml package version constraints + +## [0.5.1](https://pub.dartlang.org/packages/webfeed/versions/0.5.1) +- Support iTunes namespace [#19](https://github.com/witochandra/webfeed/pull/19) +- Parse date strings into DateTime [#22](https://github.com/witochandra/webfeed/pull/22) +- Add created & modified into dublin core namespace [#27](https://github.com/witochandra/webfeed/pull/27) +- Upgrade xml package [#28](https://github.com/witochandra/webfeed/issues/28) +- Fix linting warnings + ## [0.4.2](https://pub.dartlang.org/packages/webfeed/versions/0.4.2) ### Fixed - Bad import in `rss_content.dart` & `rss_source.dart` + ## [0.4.1](https://pub.dartlang.org/packages/webfeed/versions/0.4.1) ### Added - Support `author` in RssFeed + ## [0.4.0](https://pub.dartlang.org/packages/webfeed/versions/0.4.0) ### Added - Support for dublin core namespace diff --git a/README.md b/README.md index 0e83d16..6e179d2 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,19 @@ A dart package for parsing RSS and Atom feed. ### Features -- [x] RSS +- [x] RSS (0.9, 1.0, & 2.0) - [x] Atom - [x] Namespaces - [x] Media RSS - [x] Dublin Core + - [x] iTunes + - [x] Syndication ### Installing Add this line into your `pubspec.yaml` ``` -webfeed: ^0.4.2 +webfeed: ^0.6.0 ``` Import the package into your dart code using: @@ -29,8 +31,8 @@ import 'package:webfeed/webfeed.dart'; To parse string into `RssFeed` object use: ``` -var rssFeed = new RssFeed.parse(xmlString); // for parsing RSS feed -var atomFeed = new AtomFeed.parse(xmlString); // for parsing Atom feed +var rssFeed = RssFeed.parse(xmlString); // for parsing RSS feed +var atomFeed = AtomFeed.parse(xmlString); // for parsing Atom feed ``` ### Preview diff --git a/analysis_options.yaml b/analysis_options.yaml index 0323d68..d74c8fe 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,7 +1,4 @@ analyzer: - language: - enablePreviewDart2: true - strong-mode: true errors: unused_import: error unused_local_variable: error @@ -35,3 +32,5 @@ linter: - prefer_typing_uninitialized_variables - slash_for_doc_comments - type_init_formals + - unnecessary_new + - prefer_single_quotes diff --git a/example/main.dart b/example/main.dart index 81a0888..7a4500c 100644 --- a/example/main.dart +++ b/example/main.dart @@ -1,24 +1,19 @@ import 'package:http/http.dart' as http; import 'package:webfeed/webfeed.dart'; -void main() { - var client = new http.Client(); +void main() async { + var client = http.Client(); // RSS feed - client.get("https://developer.apple.com/news/releases/rss/releases.rss").then((response) { - return response.body; - }).then((bodyString) { - var channel = new RssFeed.parse(bodyString); - print(channel); - return channel; - }); + var response = await client + .get('https://developer.apple.com/news/releases/rss/releases.rss'); + var channel = RssFeed.parse(response.body); + print(channel); // Atom feed - client.get("https://www.theverge.com/rss/index.xml").then((response) { - return response.body; - }).then((bodyString) { - var feed = new AtomFeed.parse(bodyString); - print(feed); - return feed; - }); + response = await client.get('https://www.theverge.com/rss/index.xml'); + var feed = AtomFeed.parse(response.body); + print(feed); + + client.close(); } diff --git a/lib/domain/atom_category.dart b/lib/domain/atom_category.dart index 22c6a97..acd5b58 100644 --- a/lib/domain/atom_category.dart +++ b/lib/domain/atom_category.dart @@ -8,9 +8,9 @@ class AtomCategory { AtomCategory(this.term, this.scheme, this.label); factory AtomCategory.parse(XmlElement element) { - var term = element.getAttribute("term"); - var scheme = element.getAttribute("scheme"); - var label = element.getAttribute("label"); + var term = element.getAttribute('term'); + var scheme = element.getAttribute('scheme'); + var label = element.getAttribute('label'); return AtomCategory(term, scheme, label); } } diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 92f2cd6..128ed30 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -3,13 +3,14 @@ import 'package:webfeed/domain/atom_generator.dart'; import 'package:webfeed/domain/atom_item.dart'; import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/datetime.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomFeed { final String id; final String title; - final String updated; + final DateTime updated; final List items; final List links; @@ -39,39 +40,42 @@ class AtomFeed { }); factory AtomFeed.parse(String xmlString) { - var document = parse(xmlString); - XmlElement feedElement; - try { - feedElement = document.findElements("feed").first; - } on StateError { - throw new ArgumentError("feed not found"); + var document = XmlDocument.parse(xmlString); + var feedElement = findFirstElement(document, 'feed'); + if (feedElement == null) { + throw ArgumentError('feed not found'); } return AtomFeed( - id: findElementOrNull(feedElement, "id")?.text, - title: findElementOrNull(feedElement, "title")?.text, - updated: findElementOrNull(feedElement, "updated")?.text, - items: feedElement.findElements("entry").map((element) { - return AtomItem.parse(element); - }).toList(), - links: feedElement.findElements("link").map((element) { - return AtomLink.parse(element); - }).toList(), - authors: feedElement.findElements("author").map((element) { - return AtomPerson.parse(element); - }).toList(), - contributors: feedElement.findElements("contributor").map((element) { - return AtomPerson.parse(element); - }).toList(), - categories: feedElement.findElements("category").map((element) { - return AtomCategory.parse(element); - }).toList(), + id: findFirstElement(feedElement, 'id')?.text, + title: findFirstElement(feedElement, 'title')?.text, + updated: parseDateTime(findFirstElement(feedElement, 'updated')?.text), + items: feedElement + .findElements('entry') + .map((e) => AtomItem.parse(e)) + .toList(), + links: feedElement + .findElements('link') + .map((e) => AtomLink.parse(e)) + .toList(), + authors: feedElement + .findElements('author') + .map((e) => AtomPerson.parse(e)) + .toList(), + contributors: feedElement + .findElements('contributor') + .map((e) => AtomPerson.parse(e)) + .toList(), + categories: feedElement + .findElements('category') + .map((e) => AtomCategory.parse(e)) + .toList(), generator: - AtomGenerator.parse(findElementOrNull(feedElement, "generator")), - icon: findElementOrNull(feedElement, "icon")?.text, - logo: findElementOrNull(feedElement, "logo")?.text, - rights: findElementOrNull(feedElement, "rights")?.text, - subtitle: findElementOrNull(feedElement, "subtitle")?.text, + AtomGenerator.parse(findFirstElement(feedElement, 'generator')), + icon: findFirstElement(feedElement, 'icon')?.text, + logo: findFirstElement(feedElement, 'logo')?.text, + rights: findFirstElement(feedElement, 'rights')?.text, + subtitle: findFirstElement(feedElement, 'subtitle')?.text, ); } } diff --git a/lib/domain/atom_generator.dart b/lib/domain/atom_generator.dart index 7fd8579..b3a0b5f 100644 --- a/lib/domain/atom_generator.dart +++ b/lib/domain/atom_generator.dart @@ -11,9 +11,9 @@ class AtomGenerator { if (element == null) { return null; } - var uri = element.getAttribute("uri"); - var version = element.getAttribute("version"); + var uri = element.getAttribute('uri'); + var version = element.getAttribute('version'); var value = element.text; - return new AtomGenerator(uri, version, value); + return AtomGenerator(uri, version, value); } } diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index 618015b..a5efa08 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -3,13 +3,14 @@ import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; import 'package:webfeed/domain/atom_source.dart'; import 'package:webfeed/domain/media/media.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/datetime.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomItem { final String id; final String title; - final String updated; + final DateTime updated; final List authors; final List links; @@ -40,26 +41,28 @@ class AtomItem { factory AtomItem.parse(XmlElement element) { return AtomItem( - id: findElementOrNull(element, "id")?.text, - title: findElementOrNull(element, "title")?.text, - updated: findElementOrNull(element, "updated")?.text, - authors: element.findElements("author").map((element) { - return AtomPerson.parse(element); - }).toList(), - links: element.findElements("link").map((element) { - return AtomLink.parse(element); - }).toList(), - categories: element.findElements("category").map((element) { - return AtomCategory.parse(element); - }).toList(), - contributors: element.findElements("contributor").map((element) { - return AtomPerson.parse(element); - }).toList(), - source: AtomSource.parse(findElementOrNull(element, "source")), - published: findElementOrNull(element, "published")?.text, - content: findElementOrNull(element, "content")?.text, - summary: findElementOrNull(element, "summary")?.text, - rights: findElementOrNull(element, "rights")?.text, + id: findFirstElement(element, 'id')?.text, + title: findFirstElement(element, 'title')?.text, + updated: parseDateTime(findFirstElement(element, 'updated')?.text), + authors: element + .findElements('author') + .map((e) => AtomPerson.parse(e)) + .toList(), + links: + element.findElements('link').map((e) => AtomLink.parse(e)).toList(), + categories: element + .findElements('category') + .map((e) => AtomCategory.parse(e)) + .toList(), + contributors: element + .findElements('contributor') + .map((e) => AtomPerson.parse(e)) + .toList(), + source: AtomSource.parse(findFirstElement(element, 'source')), + published: findFirstElement(element, 'published')?.text, + content: findFirstElement(element, 'content')?.text, + summary: findFirstElement(element, 'summary')?.text, + rights: findFirstElement(element, 'rights')?.text, media: Media.parse(element), ); } diff --git a/lib/domain/atom_link.dart b/lib/domain/atom_link.dart index 3b570f2..9b68ac2 100644 --- a/lib/domain/atom_link.dart +++ b/lib/domain/atom_link.dart @@ -18,14 +18,14 @@ class AtomLink { ); factory AtomLink.parse(XmlElement element) { - var href = element.getAttribute("href"); - var rel = element.getAttribute("rel"); - var type = element.getAttribute("type"); - var title = element.getAttribute("title"); - var hreflang = element.getAttribute("hreflang"); + var href = element.getAttribute('href'); + var rel = element.getAttribute('rel'); + var type = element.getAttribute('type'); + var title = element.getAttribute('title'); + var hreflang = element.getAttribute('hreflang'); var length = 0; - if (element.getAttribute("length") != null) { - length = int.parse(element.getAttribute("length")); + if (element.getAttribute('length') != null) { + length = int.parse(element.getAttribute('length')); } return AtomLink(href, rel, type, hreflang, title, length); } diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart index 3eb1e4a..749e7e0 100644 --- a/lib/domain/atom_person.dart +++ b/lib/domain/atom_person.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomPerson { @@ -6,12 +6,13 @@ class AtomPerson { final String uri; final String email; - AtomPerson(this.name, this.uri, this.email); + AtomPerson({this.name, this.uri, this.email}); factory AtomPerson.parse(XmlElement element) { - var name = findElementOrNull(element, "name")?.text; - var uri = findElementOrNull(element, "uri")?.text; - var email = findElementOrNull(element, "email")?.text; - return AtomPerson(name, uri, email); + return AtomPerson( + name: findFirstElement(element, 'name')?.text, + uri: findFirstElement(element, 'uri')?.text, + email: findFirstElement(element, 'email')?.text, + ); } } diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart index 37fb619..b917f14 100644 --- a/lib/domain/atom_source.dart +++ b/lib/domain/atom_source.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomSource { @@ -6,16 +6,20 @@ class AtomSource { final String title; final String updated; - AtomSource(this.id, this.title, this.updated); + AtomSource({ + this.id, + this.title, + this.updated, + }); factory AtomSource.parse(XmlElement element) { if (element == null) { return null; } - var id = findElementOrNull(element, "id")?.text; - var title = findElementOrNull(element, "title")?.text; - var updated = findElementOrNull(element, "updated")?.text; - - return AtomSource(id, title, updated); + return AtomSource( + id: findFirstElement(element, 'id')?.text, + title: findFirstElement(element, 'title')?.text, + updated: findFirstElement(element, 'updated')?.text, + ); } } diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index 564bb4c..d297df5 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -1,4 +1,5 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/datetime.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class DublinCore { @@ -8,7 +9,9 @@ class DublinCore { final String subject; final String publisher; final String contributor; - final String date; + final DateTime date; + final DateTime created; + final DateTime modified; final String type; final String format; final String identifier; @@ -26,6 +29,8 @@ class DublinCore { this.publisher, this.contributor, this.date, + this.created, + this.modified, this.type, this.format, this.identifier, @@ -41,21 +46,23 @@ class DublinCore { return null; } return DublinCore( - title: findElementOrNull(element, "dc:title")?.text, - description: findElementOrNull(element, "dc:description")?.text, - creator: findElementOrNull(element, "dc:creator")?.text, - subject: findElementOrNull(element, "dc:subject")?.text, - publisher: findElementOrNull(element, "dc:publisher")?.text, - contributor: findElementOrNull(element, "dc:contributor")?.text, - date: findElementOrNull(element, "dc:date")?.text, - type: findElementOrNull(element, "dc:type")?.text, - format: findElementOrNull(element, "dc:format")?.text, - identifier: findElementOrNull(element, "dc:identifier")?.text, - source: findElementOrNull(element, "dc:source")?.text, - language: findElementOrNull(element, "dc:language")?.text, - relation: findElementOrNull(element, "dc:relation")?.text, - coverage: findElementOrNull(element, "dc:coverage")?.text, - rights: findElementOrNull(element, "dc:rights")?.text, + title: findFirstElement(element, 'dc:title')?.text, + description: findFirstElement(element, 'dc:description')?.text, + creator: findFirstElement(element, 'dc:creator')?.text, + subject: findFirstElement(element, 'dc:subject')?.text, + publisher: findFirstElement(element, 'dc:publisher')?.text, + contributor: findFirstElement(element, 'dc:contributor')?.text, + date: parseDateTime(findFirstElement(element, 'dc:date')?.text), + created: parseDateTime(findFirstElement(element, 'dc:created')?.text), + modified: parseDateTime(findFirstElement(element, 'dc:modified')?.text), + type: findFirstElement(element, 'dc:type')?.text, + format: findFirstElement(element, 'dc:format')?.text, + identifier: findFirstElement(element, 'dc:identifier')?.text, + source: findFirstElement(element, 'dc:source')?.text, + language: findFirstElement(element, 'dc:language')?.text, + relation: findFirstElement(element, 'dc:relation')?.text, + coverage: findFirstElement(element, 'dc:coverage')?.text, + rights: findFirstElement(element, 'dc:rights')?.text, ); } } diff --git a/lib/domain/itunes/itunes.dart b/lib/domain/itunes/itunes.dart new file mode 100644 index 0000000..a6cc682 --- /dev/null +++ b/lib/domain/itunes/itunes.dart @@ -0,0 +1,102 @@ +import 'package:webfeed/domain/itunes/itunes_category.dart'; +import 'package:webfeed/domain/itunes/itunes_episode_type.dart'; +import 'package:webfeed/domain/itunes/itunes_image.dart'; +import 'package:webfeed/domain/itunes/itunes_owner.dart'; +import 'package:webfeed/domain/itunes/itunes_type.dart'; +import 'package:webfeed/util/xml.dart'; +import 'package:xml/xml.dart'; + +class Itunes { + final String author; + final String summary; + final bool explicit; + final String title; + final String subtitle; + final ItunesOwner owner; + final List keywords; + final ItunesImage image; + final List categories; + final ItunesType type; + final String newFeedUrl; + final bool block; + final bool complete; + final int episode; + final int season; + final Duration duration; + final ItunesEpisodeType episodeType; + + Itunes({ + this.author, + this.summary, + this.explicit, + this.title, + this.subtitle, + this.owner, + this.keywords, + this.image, + this.categories, + this.type, + this.newFeedUrl, + this.block, + this.complete, + this.episode, + this.season, + this.duration, + this.episodeType, + }); + + factory Itunes.parse(XmlElement element) { + if (element == null) { + return null; + } + var episodeStr = findFirstElement(element, 'itunes:episode')?.text; + var seasonStr = findFirstElement(element, 'itunes:season')?.text; + var durationStr = findFirstElement(element, 'itunes:duration')?.text; + return Itunes( + author: findFirstElement(element, 'itunes:author')?.text, + summary: findFirstElement(element, 'itunes:summary')?.text, + explicit: parseBoolLiteral(element, 'itunes:explicit'), + title: findFirstElement(element, 'itunes:title')?.text, + subtitle: findFirstElement(element, 'itunes:subtitle')?.text, + owner: ItunesOwner.parse(findFirstElement(element, 'itunes:owner')), + keywords: findFirstElement(element, 'itunes:keywords') + ?.text + ?.split(',') + ?.map((keyword) => keyword.trim()) + ?.toList() ?? + [], + image: ItunesImage.parse(findFirstElement(element, 'itunes:image')), + categories: findElements(element, 'itunes:category') + .map((e) => ItunesCategory.parse(e)) + .toList(), + type: newItunesType(findFirstElement(element, 'itunes:type')), + newFeedUrl: findFirstElement(element, 'itunes:new-feed-url')?.text, + block: parseBoolLiteral(element, 'itunes:block'), + complete: parseBoolLiteral(element, 'itunes:complete'), + episode: episodeStr == null ? null : int.parse(episodeStr), + season: seasonStr == null ? null : int.parse(seasonStr), + duration: durationStr == null ? null : _parseDuration(durationStr), + episodeType: + newItunesEpisodeType(findFirstElement(element, 'itunes:episodeType')), + ); + } + + static Duration _parseDuration(String s) { + var hours = 0; + var minutes = 0; + var seconds = 0; + var parts = s.split(':'); + if (parts.length > 2) { + hours = int.parse(parts[parts.length - 3]); + } + if (parts.length > 1) { + minutes = int.parse(parts[parts.length - 2]); + } + seconds = int.parse(parts[parts.length - 1]); + return Duration( + hours: hours, + minutes: minutes, + seconds: seconds, + ); + } +} diff --git a/lib/domain/itunes/itunes_category.dart b/lib/domain/itunes/itunes_category.dart new file mode 100644 index 0000000..2bfc792 --- /dev/null +++ b/lib/domain/itunes/itunes_category.dart @@ -0,0 +1,20 @@ +import 'package:xml/xml.dart'; + +class ItunesCategory { + final String category; + final List subCategories; + + ItunesCategory({this.category, this.subCategories}); + + factory ItunesCategory.parse(XmlElement element) { + if (element == null) return null; + return ItunesCategory( + category: element.getAttribute('text')?.trim(), + subCategories: element + .findElements('itunes:category') + ?.map((e) => e.getAttribute('text')?.trim()) + ?.toList() ?? + [], + ); + } +} diff --git a/lib/domain/itunes/itunes_episode_type.dart b/lib/domain/itunes/itunes_episode_type.dart new file mode 100644 index 0000000..fc84b39 --- /dev/null +++ b/lib/domain/itunes/itunes_episode_type.dart @@ -0,0 +1,16 @@ +import 'package:xml/xml.dart'; + +enum ItunesEpisodeType { full, trailer, bonus, unknown } + +ItunesEpisodeType newItunesEpisodeType(XmlElement element) { + switch (element?.text) { + case 'full': + return ItunesEpisodeType.full; + case 'trailer': + return ItunesEpisodeType.trailer; + case 'bonus': + return ItunesEpisodeType.bonus; + default: + return ItunesEpisodeType.unknown; + } +} diff --git a/lib/domain/itunes/itunes_image.dart b/lib/domain/itunes/itunes_image.dart new file mode 100644 index 0000000..4ae61ca --- /dev/null +++ b/lib/domain/itunes/itunes_image.dart @@ -0,0 +1,14 @@ +import 'package:xml/xml.dart'; + +class ItunesImage { + final String href; + + ItunesImage({this.href}); + + factory ItunesImage.parse(XmlElement element) { + if (element == null) return null; + return ItunesImage( + href: element.getAttribute('href')?.trim(), + ); + } +} diff --git a/lib/domain/itunes/itunes_owner.dart b/lib/domain/itunes/itunes_owner.dart new file mode 100644 index 0000000..2aa3f3a --- /dev/null +++ b/lib/domain/itunes/itunes_owner.dart @@ -0,0 +1,17 @@ +import 'package:webfeed/util/xml.dart'; +import 'package:xml/xml.dart'; + +class ItunesOwner { + final String name; + final String email; + + ItunesOwner({this.name, this.email}); + + factory ItunesOwner.parse(XmlElement element) { + if (element == null) return null; + return ItunesOwner( + name: findFirstElement(element, 'itunes:name')?.text?.trim(), + email: findFirstElement(element, 'itunes:email')?.text?.trim(), + ); + } +} diff --git a/lib/domain/itunes/itunes_type.dart b/lib/domain/itunes/itunes_type.dart new file mode 100644 index 0000000..b32f6bd --- /dev/null +++ b/lib/domain/itunes/itunes_type.dart @@ -0,0 +1,14 @@ +import 'package:xml/xml.dart'; + +enum ItunesType { episodic, serial, unknown } + +ItunesType newItunesType(XmlElement element) { + switch (element?.text) { + case 'episodic': + return ItunesType.episodic; + case 'serial': + return ItunesType.serial; + default: + return ItunesType.unknown; + } +} diff --git a/lib/domain/media/category.dart b/lib/domain/media/category.dart index 4796cd7..967e0a2 100644 --- a/lib/domain/media/category.dart +++ b/lib/domain/media/category.dart @@ -15,9 +15,9 @@ class Category { if (element == null) { return null; } - return new Category( - scheme: element.getAttribute("scheme"), - label: element.getAttribute("label"), + return Category( + scheme: element.getAttribute('scheme'), + label: element.getAttribute('label'), value: element.text, ); } diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index b301050..a29ed1e 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -1,7 +1,7 @@ import 'package:webfeed/domain/media/star_rating.dart'; import 'package:webfeed/domain/media/statistics.dart'; import 'package:webfeed/domain/media/tags.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Community { @@ -19,15 +19,15 @@ class Community { if (element == null) { return null; } - return new Community( - starRating: new StarRating.parse( - findElementOrNull(element, "media:starRating"), + return Community( + starRating: StarRating.parse( + findFirstElement(element, 'media:starRating'), ), - statistics: new Statistics.parse( - findElementOrNull(element, "media:statistics"), + statistics: Statistics.parse( + findFirstElement(element, 'media:statistics'), ), - tags: new Tags.parse( - findElementOrNull(element, "media:tags"), + tags: Tags.parse( + findFirstElement(element, 'media:tags'), ), ); } diff --git a/lib/domain/media/content.dart b/lib/domain/media/content.dart index 3a4ebaa..061119c 100644 --- a/lib/domain/media/content.dart +++ b/lib/domain/media/content.dart @@ -34,23 +34,23 @@ class Content { }); factory Content.parse(XmlElement element) { - return new Content( - url: element.getAttribute("url"), - type: element.getAttribute("type"), - fileSize: int.tryParse(element.getAttribute("fileSize") ?? "0"), - medium: element.getAttribute("medium"), - isDefault: element.getAttribute("isDefault") == "true", - expression: element.getAttribute("expression"), - bitrate: int.tryParse(element.getAttribute("bitrate") ?? "0"), - framerate: double.tryParse(element.getAttribute("framerate") ?? "0"), + return Content( + url: element.getAttribute('url'), + type: element.getAttribute('type'), + fileSize: int.tryParse(element.getAttribute('fileSize') ?? '0'), + medium: element.getAttribute('medium'), + isDefault: element.getAttribute('isDefault') == 'true', + expression: element.getAttribute('expression'), + bitrate: int.tryParse(element.getAttribute('bitrate') ?? '0'), + framerate: double.tryParse(element.getAttribute('framerate') ?? '0'), samplingrate: double.tryParse( - element.getAttribute("samplingrate") ?? "0", + element.getAttribute('samplingrate') ?? '0', ), - channels: int.tryParse(element.getAttribute("channels") ?? "0"), - duration: int.tryParse(element.getAttribute("duration") ?? "0"), - height: int.tryParse(element.getAttribute("height") ?? "0"), - width: int.tryParse(element.getAttribute("width") ?? "0"), - lang: element.getAttribute("lang"), + channels: int.tryParse(element.getAttribute('channels') ?? '0'), + duration: int.tryParse(element.getAttribute('duration') ?? '0'), + height: int.tryParse(element.getAttribute('height') ?? '0'), + width: int.tryParse(element.getAttribute('width') ?? '0'), + lang: element.getAttribute('lang'), ); } } diff --git a/lib/domain/media/copyright.dart b/lib/domain/media/copyright.dart index 1cad059..e40c4c7 100644 --- a/lib/domain/media/copyright.dart +++ b/lib/domain/media/copyright.dart @@ -13,8 +13,8 @@ class Copyright { if (element == null) { return null; } - return new Copyright( - url: element.getAttribute("url"), + return Copyright( + url: element.getAttribute('url'), value: element.text, ); } diff --git a/lib/domain/media/credit.dart b/lib/domain/media/credit.dart index 70a5e50..3f0838b 100644 --- a/lib/domain/media/credit.dart +++ b/lib/domain/media/credit.dart @@ -12,9 +12,9 @@ class Credit { }); factory Credit.parse(XmlElement element) { - return new Credit( - role: element.getAttribute("role"), - scheme: element.getAttribute("scheme"), + return Credit( + role: element.getAttribute('role'), + scheme: element.getAttribute('scheme'), value: element.text, ); } diff --git a/lib/domain/media/description.dart b/lib/domain/media/description.dart index ba6f0e0..29866d0 100644 --- a/lib/domain/media/description.dart +++ b/lib/domain/media/description.dart @@ -13,8 +13,8 @@ class Description { if (element == null) { return null; } - return new Description( - type: element.getAttribute("type"), + return Description( + type: element.getAttribute('type'), value: element.text, ); } diff --git a/lib/domain/media/embed.dart b/lib/domain/media/embed.dart index 1cca476..81555be 100644 --- a/lib/domain/media/embed.dart +++ b/lib/domain/media/embed.dart @@ -18,12 +18,12 @@ class Embed { if (element == null) { return null; } - return new Embed( - url: element.getAttribute("url"), - width: int.tryParse(element.getAttribute("width") ?? "0"), - height: int.tryParse(element.getAttribute("height") ?? "0"), - params: element.findElements("media:param").map((e) { - return new Param.parse(e); + return Embed( + url: element.getAttribute('url'), + width: int.tryParse(element.getAttribute('width') ?? '0'), + height: int.tryParse(element.getAttribute('height') ?? '0'), + params: element.findElements('media:param').map((e) { + return Param.parse(e); }).toList(), ); } diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 1a9a1cb..8f82f7b 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -2,7 +2,7 @@ import 'package:webfeed/domain/media/category.dart'; import 'package:webfeed/domain/media/content.dart'; import 'package:webfeed/domain/media/credit.dart'; import 'package:webfeed/domain/media/rating.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Group { @@ -22,18 +22,18 @@ class Group { if (element == null) { return null; } - return new Group( - contents: element.findElements("media:content").map((e) { - return new Content.parse(e); + return Group( + contents: element.findElements('media:content').map((e) { + return Content.parse(e); }).toList(), - credits: element.findElements("media:credit").map((e) { - return new Credit.parse(e); + credits: element.findElements('media:credit').map((e) { + return Credit.parse(e); }).toList(), - category: new Category.parse( - findElementOrNull(element, "media:category"), + category: Category.parse( + findFirstElement(element, 'media:category'), ), - rating: new Rating.parse( - findElementOrNull(element, "media:rating"), + rating: Rating.parse( + findFirstElement(element, 'media:rating'), ), ); } diff --git a/lib/domain/media/hash.dart b/lib/domain/media/hash.dart index 72ce859..bfcbd72 100644 --- a/lib/domain/media/hash.dart +++ b/lib/domain/media/hash.dart @@ -13,8 +13,8 @@ class Hash { if (element == null) { return null; } - return new Hash( - algo: element.getAttribute("algo"), + return Hash( + algo: element.getAttribute('algo'), value: element.text, ); } diff --git a/lib/domain/media/license.dart b/lib/domain/media/license.dart index c52a8c6..e3990db 100644 --- a/lib/domain/media/license.dart +++ b/lib/domain/media/license.dart @@ -15,9 +15,9 @@ class License { if (element == null) { return null; } - return new License( - type: element.getAttribute("type"), - href: element.getAttribute("href"), + return License( + type: element.getAttribute('type'), + href: element.getAttribute('href'), value: element.text, ); } diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index 2f685c1..2ee0cba 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -19,7 +19,7 @@ import 'package:webfeed/domain/media/status.dart'; import 'package:webfeed/domain/media/text.dart'; import 'package:webfeed/domain/media/thumbnail.dart'; import 'package:webfeed/domain/media/title.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Media { @@ -78,90 +78,90 @@ class Media { }); factory Media.parse(XmlElement element) { - return new Media( - group: new Group.parse( - findElementOrNull(element, "media:group"), + return Media( + group: Group.parse( + findFirstElement(element, 'media:group'), ), - contents: element.findElements("media:content").map((e) { - return new Content.parse(e); + contents: element.findElements('media:content').map((e) { + return Content.parse(e); }).toList(), - credits: element.findElements("media:credit").map((e) { - return new Credit.parse(e); + credits: element.findElements('media:credit').map((e) { + return Credit.parse(e); }).toList(), - category: new Category.parse( - findElementOrNull(element, "media:category"), + category: Category.parse( + findFirstElement(element, 'media:category'), ), - rating: new Rating.parse( - findElementOrNull(element, "media:rating"), + rating: Rating.parse( + findFirstElement(element, 'media:rating'), ), - title: new Title.parse( - findElementOrNull(element, "media:title"), + title: Title.parse( + findFirstElement(element, 'media:title'), ), - description: new Description.parse( - findElementOrNull(element, "media:description"), + description: Description.parse( + findFirstElement(element, 'media:description'), ), - keywords: findElementOrNull(element, "media:keywords")?.text, - thumbnails: element.findElements("media:thumbnail").map((e) { - return new Thumbnail.parse(e); + keywords: findFirstElement(element, 'media:keywords')?.text, + thumbnails: element.findElements('media:thumbnail').map((e) { + return Thumbnail.parse(e); }).toList(), - hash: new Hash.parse( - findElementOrNull(element, "media:hash"), + hash: Hash.parse( + findFirstElement(element, 'media:hash'), ), - player: new Player.parse( - findElementOrNull(element, "media:player"), + player: Player.parse( + findFirstElement(element, 'media:player'), ), - copyright: new Copyright.parse( - findElementOrNull(element, "media:copyright"), + copyright: Copyright.parse( + findFirstElement(element, 'media:copyright'), ), - text: new Text.parse( - findElementOrNull(element, "media:text"), + text: Text.parse( + findFirstElement(element, 'media:text'), ), - restriction: new Restriction.parse( - findElementOrNull(element, "media:restriction"), + restriction: Restriction.parse( + findFirstElement(element, 'media:restriction'), ), - community: new Community.parse( - findElementOrNull(element, "media:community"), + community: Community.parse( + findFirstElement(element, 'media:community'), ), - comments: findElementOrNull(element, "media:comments") - ?.findElements("media:comment") + comments: findFirstElement(element, 'media:comments') + ?.findElements('media:comment') ?.map((e) { return e.text; })?.toList() ?? [], - embed: new Embed.parse( - findElementOrNull(element, "media:embed"), + embed: Embed.parse( + findFirstElement(element, 'media:embed'), ), - responses: findElementOrNull(element, "media:responses") - ?.findElements("media:response") + responses: findFirstElement(element, 'media:responses') + ?.findElements('media:response') ?.map((e) { return e.text; })?.toList() ?? [], - backLinks: findElementOrNull(element, "media:backLinks") - ?.findElements("media:backLink") + backLinks: findFirstElement(element, 'media:backLinks') + ?.findElements('media:backLink') ?.map((e) { return e.text; })?.toList() ?? [], - status: new Status.parse( - findElementOrNull(element, "media:status"), + status: Status.parse( + findFirstElement(element, 'media:status'), ), - prices: element.findElements("media:price").map((e) { - return new Price.parse(e); + prices: element.findElements('media:price').map((e) { + return Price.parse(e); }).toList(), - license: new License.parse( - findElementOrNull(element, "media:license"), + license: License.parse( + findFirstElement(element, 'media:license'), ), - peerLink: new PeerLink.parse( - findElementOrNull(element, "media:peerLink"), + peerLink: PeerLink.parse( + findFirstElement(element, 'media:peerLink'), ), - rights: new Rights.parse( - findElementOrNull(element, "media:rights"), + rights: Rights.parse( + findFirstElement(element, 'media:rights'), ), - scenes: findElementOrNull(element, "media:scenes") - ?.findElements("media:scene") + scenes: findFirstElement(element, 'media:scenes') + ?.findElements('media:scene') ?.map((e) { - return new Scene.parse(e); + return Scene.parse(e); })?.toList() ?? [], ); diff --git a/lib/domain/media/param.dart b/lib/domain/media/param.dart index 175e6b8..ac42675 100644 --- a/lib/domain/media/param.dart +++ b/lib/domain/media/param.dart @@ -13,8 +13,8 @@ class Param { if (element == null) { return null; } - return new Param( - name: element.getAttribute("name"), + return Param( + name: element.getAttribute('name'), value: element.text, ); } diff --git a/lib/domain/media/peer_link.dart b/lib/domain/media/peer_link.dart index 6c51a17..08a5524 100644 --- a/lib/domain/media/peer_link.dart +++ b/lib/domain/media/peer_link.dart @@ -15,9 +15,9 @@ class PeerLink { if (element == null) { return null; } - return new PeerLink( - type: element.getAttribute("type"), - href: element.getAttribute("href"), + return PeerLink( + type: element.getAttribute('type'), + href: element.getAttribute('href'), value: element.text, ); } diff --git a/lib/domain/media/player.dart b/lib/domain/media/player.dart index 23d5e7a..2036445 100644 --- a/lib/domain/media/player.dart +++ b/lib/domain/media/player.dart @@ -17,10 +17,10 @@ class Player { if (element == null) { return null; } - return new Player( - url: element.getAttribute("url"), - width: int.tryParse(element.getAttribute("width") ?? "0"), - height: int.tryParse(element.getAttribute("height") ?? "0"), + return Player( + url: element.getAttribute('url'), + width: int.tryParse(element.getAttribute('width') ?? '0'), + height: int.tryParse(element.getAttribute('height') ?? '0'), value: element.text, ); } diff --git a/lib/domain/media/price.dart b/lib/domain/media/price.dart index 6da075b..4ac9059 100644 --- a/lib/domain/media/price.dart +++ b/lib/domain/media/price.dart @@ -14,11 +14,11 @@ class Price { }); factory Price.parse(XmlElement element) { - return new Price( - price: double.tryParse(element.getAttribute("price") ?? "0"), - type: element.getAttribute("type"), - info: element.getAttribute("info"), - currency: element.getAttribute("currency"), + return Price( + price: double.tryParse(element.getAttribute('price') ?? '0'), + type: element.getAttribute('type'), + info: element.getAttribute('info'), + currency: element.getAttribute('currency'), ); } } diff --git a/lib/domain/media/rating.dart b/lib/domain/media/rating.dart index 77c2b12..7924cdd 100644 --- a/lib/domain/media/rating.dart +++ b/lib/domain/media/rating.dart @@ -13,8 +13,8 @@ class Rating { if (element == null) { return null; } - return new Rating( - scheme: element.getAttribute("scheme"), + return Rating( + scheme: element.getAttribute('scheme'), value: element.text, ); } diff --git a/lib/domain/media/restriction.dart b/lib/domain/media/restriction.dart index 4aa56bd..cc896e9 100644 --- a/lib/domain/media/restriction.dart +++ b/lib/domain/media/restriction.dart @@ -15,9 +15,9 @@ class Restriction { if (element == null) { return null; } - return new Restriction( - relationship: element.getAttribute("relationship"), - type: element.getAttribute("type"), + return Restriction( + relationship: element.getAttribute('relationship'), + type: element.getAttribute('type'), value: element.text, ); } diff --git a/lib/domain/media/rights.dart b/lib/domain/media/rights.dart index eb00d4d..2dfd20b 100644 --- a/lib/domain/media/rights.dart +++ b/lib/domain/media/rights.dart @@ -11,8 +11,8 @@ class Rights { if (element == null) { return null; } - return new Rights( - status: element.getAttribute("status"), + return Rights( + status: element.getAttribute('status'), ); } } diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index 9eab8d0..f327a87 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Scene { @@ -18,11 +18,11 @@ class Scene { if (element == null) { return null; } - return new Scene( - title: findElementOrNull(element, "sceneTitle")?.text, - description: findElementOrNull(element, "sceneDescription")?.text, - startTime: findElementOrNull(element, "sceneStartTime")?.text, - endTime: findElementOrNull(element, "sceneEndTime")?.text, + return Scene( + title: findFirstElement(element, 'sceneTitle')?.text, + description: findFirstElement(element, 'sceneDescription')?.text, + startTime: findFirstElement(element, 'sceneStartTime')?.text, + endTime: findFirstElement(element, 'sceneEndTime')?.text, ); } } diff --git a/lib/domain/media/star_rating.dart b/lib/domain/media/star_rating.dart index ae4c400..9348a5a 100644 --- a/lib/domain/media/star_rating.dart +++ b/lib/domain/media/star_rating.dart @@ -14,11 +14,11 @@ class StarRating { }); factory StarRating.parse(XmlElement element) { - return new StarRating( - average: double.tryParse(element.getAttribute("average") ?? "0"), - count: int.tryParse(element.getAttribute("count") ?? "0"), - min: int.tryParse(element.getAttribute("min") ?? "0"), - max: int.tryParse(element.getAttribute("max") ?? "0"), + return StarRating( + average: double.tryParse(element.getAttribute('average') ?? '0'), + count: int.tryParse(element.getAttribute('count') ?? '0'), + min: int.tryParse(element.getAttribute('min') ?? '0'), + max: int.tryParse(element.getAttribute('max') ?? '0'), ); } } diff --git a/lib/domain/media/statistics.dart b/lib/domain/media/statistics.dart index d93461f..01ade1e 100644 --- a/lib/domain/media/statistics.dart +++ b/lib/domain/media/statistics.dart @@ -10,9 +10,9 @@ class Statistics { }); factory Statistics.parse(XmlElement element) { - return new Statistics( - views: int.tryParse(element.getAttribute("views") ?? "0"), - favorites: int.tryParse(element.getAttribute("favorites") ?? "0"), + return Statistics( + views: int.tryParse(element.getAttribute('views') ?? '0'), + favorites: int.tryParse(element.getAttribute('favorites') ?? '0'), ); } } diff --git a/lib/domain/media/status.dart b/lib/domain/media/status.dart index 3071a09..a5f0b15 100644 --- a/lib/domain/media/status.dart +++ b/lib/domain/media/status.dart @@ -13,9 +13,9 @@ class Status { if (element == null) { return null; } - return new Status( - state: element.getAttribute("state"), - reason: element.getAttribute("reason"), + return Status( + state: element.getAttribute('state'), + reason: element.getAttribute('reason'), ); } } diff --git a/lib/domain/media/tags.dart b/lib/domain/media/tags.dart index c7001a7..b3f747d 100644 --- a/lib/domain/media/tags.dart +++ b/lib/domain/media/tags.dart @@ -13,9 +13,9 @@ class Tags { if (element == null) { return null; } - return new Tags( + return Tags( tags: element.text, - weight: int.tryParse(element.getAttribute("weight") ?? "1"), + weight: int.tryParse(element.getAttribute('weight') ?? '1'), ); } } diff --git a/lib/domain/media/text.dart b/lib/domain/media/text.dart index 1ff886b..58e8d21 100644 --- a/lib/domain/media/text.dart +++ b/lib/domain/media/text.dart @@ -19,11 +19,11 @@ class Text { if (element == null) { return null; } - return new Text( - type: element.getAttribute("type"), - lang: element.getAttribute("lang"), - start: element.getAttribute("start"), - end: element.getAttribute("end"), + return Text( + type: element.getAttribute('type'), + lang: element.getAttribute('lang'), + start: element.getAttribute('start'), + end: element.getAttribute('end'), value: element.text, ); } diff --git a/lib/domain/media/thumbnail.dart b/lib/domain/media/thumbnail.dart index 8adce3b..85d81e7 100644 --- a/lib/domain/media/thumbnail.dart +++ b/lib/domain/media/thumbnail.dart @@ -14,11 +14,11 @@ class Thumbnail { }); factory Thumbnail.parse(XmlElement element) { - return new Thumbnail( - url: element.getAttribute("url"), - width: element.getAttribute("width"), - height: element.getAttribute("height"), - time: element.getAttribute("time"), + return Thumbnail( + url: element.getAttribute('url'), + width: element.getAttribute('width'), + height: element.getAttribute('height'), + time: element.getAttribute('time'), ); } } diff --git a/lib/domain/media/title.dart b/lib/domain/media/title.dart index 8c875a6..9968bce 100644 --- a/lib/domain/media/title.dart +++ b/lib/domain/media/title.dart @@ -13,8 +13,8 @@ class Title { if (element == null) { return null; } - return new Title( - type: element.getAttribute("type"), + return Title( + type: element.getAttribute('type'), value: element.text, ); } diff --git a/lib/domain/rss_category.dart b/lib/domain/rss_category.dart index 845a837..a3ca7d7 100644 --- a/lib/domain/rss_category.dart +++ b/lib/domain/rss_category.dart @@ -10,7 +10,7 @@ class RssCategory { if (element == null) { return null; } - var domain = element.getAttribute("domain"); + var domain = element.getAttribute('domain'); var value = element.text; return RssCategory(domain, value); diff --git a/lib/domain/rss_cloud.dart b/lib/domain/rss_cloud.dart index 74d8b6a..73f3c32 100644 --- a/lib/domain/rss_cloud.dart +++ b/lib/domain/rss_cloud.dart @@ -19,11 +19,11 @@ class RssCloud { if (node == null) { return null; } - var domain = node.getAttribute("domain"); - var port = node.getAttribute("port"); - var path = node.getAttribute("path"); - var registerProcedure = node.getAttribute("registerProcedure"); - var protocol = node.getAttribute("protocol"); + var domain = node.getAttribute('domain'); + var port = node.getAttribute('port'); + var path = node.getAttribute('path'); + var registerProcedure = node.getAttribute('registerProcedure'); + var protocol = node.getAttribute('protocol'); return RssCloud(domain, port, path, registerProcedure, protocol); } } diff --git a/lib/domain/rss_content.dart b/lib/domain/rss_content.dart index ded57bc..5dacce1 100644 --- a/lib/domain/rss_content.dart +++ b/lib/domain/rss_content.dart @@ -1,6 +1,6 @@ import 'package:xml/xml.dart'; -final _imagesRegExp = new RegExp( +final _imagesRegExp = RegExp( "]+)(?:'|\")", multiLine: true, caseSensitive: false, diff --git a/lib/domain/rss_enclosure.dart b/lib/domain/rss_enclosure.dart index 4b125e2..dd303c7 100644 --- a/lib/domain/rss_enclosure.dart +++ b/lib/domain/rss_enclosure.dart @@ -11,9 +11,9 @@ class RssEnclosure { if (element == null) { return null; } - var url = element.getAttribute("url"); - var type = element.getAttribute("type"); - var length = int.tryParse(element.getAttribute("length") ?? "0"); + var url = element.getAttribute('url'); + var type = element.getAttribute('type'); + var length = int.tryParse(element.getAttribute('length') ?? '0'); return RssEnclosure(url, type, length); } } diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 6978ef1..a2e66c2 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -1,15 +1,15 @@ import 'dart:core'; import 'package:webfeed/domain/dublin_core/dublin_core.dart'; +import 'package:webfeed/domain/itunes/itunes.dart'; import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_cloud.dart'; import 'package:webfeed/domain/rss_image.dart'; import 'package:webfeed/domain/rss_item.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/domain/syndication/syndication.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; -import 'rss_itunes.dart'; - class RssFeed { final String title; final String author; @@ -32,7 +32,8 @@ class RssFeed { final String webMaster; final int ttl; final DublinCore dc; - final RssItunes itunes; + final Itunes itunes; + final Syndication syndication; RssFeed({ this.title, @@ -56,53 +57,58 @@ class RssFeed { this.ttl, this.dc, this.itunes, + this.syndication, }); factory RssFeed.parse(String xmlString) { - var document = parse(xmlString); - XmlElement channelElement; - try { - channelElement = document.findAllElements("channel").first; - } on StateError { - throw ArgumentError("channel not found"); + var document = XmlDocument.parse(xmlString); + var rss = findFirstElement(document, 'rss'); + var rdf = findFirstElement(document, 'rdf:RDF'); + if (rss == null && rdf == null) { + throw ArgumentError('not a rss feed'); + } + var channelElement = findFirstElement(rss ?? rdf, 'channel'); + if (channelElement == null) { + throw ArgumentError('channel not found'); } - return RssFeed( - title: findElementOrNull(channelElement, "title")?.text, - author: findElementOrNull(channelElement, "author")?.text, - description: findElementOrNull(channelElement, "description")?.text, - link: findElementOrNull(channelElement, "link")?.text, - items: channelElement.findElements("item").map((element) { - return RssItem.parse(element); - }).toList(), - image: RssImage.parse(findElementOrNull(channelElement, "image")), - cloud: RssCloud.parse(findElementOrNull(channelElement, "cloud")), - categories: channelElement.findElements("category").map((element) { - return RssCategory.parse(element); - }).toList(), - skipDays: findElementOrNull(channelElement, "skipDays") - ?.findAllElements("day") - ?.map((element) { - return element.text; - })?.toList() ?? + title: findFirstElement(channelElement, 'title')?.text, + author: findFirstElement(channelElement, 'author')?.text, + description: findFirstElement(channelElement, 'description')?.text, + link: findFirstElement(channelElement, 'link')?.text, + items: (rss != null ? channelElement : rdf) + .findElements('item') + .map((e) => RssItem.parse(e)) + .toList(), + image: RssImage.parse( + findFirstElement(rss != null ? channelElement : rdf, 'image')), + cloud: RssCloud.parse(findFirstElement(channelElement, 'cloud')), + categories: channelElement + .findElements('category') + .map((e) => RssCategory.parse(e)) + .toList(), + skipDays: findFirstElement(channelElement, 'skipDays') + ?.findAllElements('day') + ?.map((e) => e.text) + ?.toList() ?? [], - skipHours: findElementOrNull(channelElement, "skipHours") - ?.findAllElements("hour") - ?.map((element) { - return int.tryParse(element.text ?? "0"); - })?.toList() ?? + skipHours: findFirstElement(channelElement, 'skipHours') + ?.findAllElements('hour') + ?.map((e) => int.tryParse(e.text ?? '0')) + ?.toList() ?? [], - lastBuildDate: findElementOrNull(channelElement, "lastBuildDate")?.text, - language: findElementOrNull(channelElement, "language")?.text, - generator: findElementOrNull(channelElement, "generator")?.text, - copyright: findElementOrNull(channelElement, "copyright")?.text, - docs: findElementOrNull(channelElement, "docs")?.text, - managingEditor: findElementOrNull(channelElement, "managingEditor")?.text, - rating: findElementOrNull(channelElement, "rating")?.text, - webMaster: findElementOrNull(channelElement, "webMaster")?.text, - ttl: int.tryParse(findElementOrNull(channelElement, "ttl")?.text ?? "0"), + lastBuildDate: findFirstElement(channelElement, 'lastBuildDate')?.text, + language: findFirstElement(channelElement, 'language')?.text, + generator: findFirstElement(channelElement, 'generator')?.text, + copyright: findFirstElement(channelElement, 'copyright')?.text, + docs: findFirstElement(channelElement, 'docs')?.text, + managingEditor: findFirstElement(channelElement, 'managingEditor')?.text, + rating: findFirstElement(channelElement, 'rating')?.text, + webMaster: findFirstElement(channelElement, 'webMaster')?.text, + ttl: int.tryParse(findFirstElement(channelElement, 'ttl')?.text ?? '0'), dc: DublinCore.parse(channelElement), - itunes: RssItunes.parse(channelElement), + itunes: Itunes.parse(channelElement), + syndication: Syndication.parse(channelElement), ); } } diff --git a/lib/domain/rss_image.dart b/lib/domain/rss_image.dart index cfc9479..35e39b3 100644 --- a/lib/domain/rss_image.dart +++ b/lib/domain/rss_image.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class RssImage { @@ -6,16 +6,16 @@ class RssImage { final String url; final String link; - RssImage(this.title, this.url, this.link); + RssImage({this.title, this.url, this.link}); factory RssImage.parse(XmlElement element) { if (element == null) { return null; } - var title = findElementOrNull(element, "title")?.text; - var url = findElementOrNull(element, "url")?.text; - var link = findElementOrNull(element, "link")?.text; - - return RssImage(title, url, link); + return RssImage( + title: findFirstElement(element, 'title')?.text, + url: findFirstElement(element, 'url')?.text, + link: findFirstElement(element, 'link')?.text, + ); } } diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 783585a..15fa909 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -1,15 +1,14 @@ -import 'package:intl/intl.dart'; import 'package:webfeed/domain/dublin_core/dublin_core.dart'; +import 'package:webfeed/domain/itunes/itunes.dart'; import 'package:webfeed/domain/media/media.dart'; import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_content.dart'; import 'package:webfeed/domain/rss_enclosure.dart'; import 'package:webfeed/domain/rss_source.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/datetime.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; -import 'rss_item_itunes.dart'; - class RssItem { final String title; final String description; @@ -25,7 +24,7 @@ class RssItem { final Media media; final RssEnclosure enclosure; final DublinCore dc; - final RssItemItunes itunes; + final Itunes itunes; RssItem({ this.title, @@ -33,7 +32,7 @@ class RssItem { this.link, this.categories, this.guid, - String pubDate, + this.pubDate, this.author, this.comments, this.source, @@ -42,33 +41,27 @@ class RssItem { this.enclosure, this.dc, this.itunes, - }) - : this.pubDate = _parsePubDate(pubDate); + }); factory RssItem.parse(XmlElement element) { return RssItem( - title: findElementOrNull(element, "title")?.text, - description: findElementOrNull(element, "description")?.text, - link: findElementOrNull(element, "link")?.text, - categories: element.findElements("category").map((element) { - return RssCategory.parse(element); - }).toList(), - guid: findElementOrNull(element, "guid")?.text, - pubDate: findElementOrNull(element, "pubDate")?.text, - author: findElementOrNull(element, "author")?.text, - comments: findElementOrNull(element, "comments")?.text, - source: RssSource.parse(findElementOrNull(element, "source")), - content: RssContent.parse(findElementOrNull(element, "content:encoded")), + title: findFirstElement(element, 'title')?.text, + description: findFirstElement(element, 'description')?.text, + link: findFirstElement(element, 'link')?.text, + categories: element + .findElements('category') + .map((e) => RssCategory.parse(e)) + .toList(), + guid: findFirstElement(element, 'guid')?.text, + pubDate: parseDateTime(findFirstElement(element, 'pubDate')?.text), + author: findFirstElement(element, 'author')?.text, + comments: findFirstElement(element, 'comments')?.text, + source: RssSource.parse(findFirstElement(element, 'source')), + content: RssContent.parse(findFirstElement(element, 'content:encoded')), media: Media.parse(element), - enclosure: RssEnclosure.parse(findElementOrNull(element, "enclosure")), + enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')), dc: DublinCore.parse(element), - itunes: RssItemItunes.parse(element), + itunes: Itunes.parse(element), ); } - - static _parsePubDate(pubDate) { - if (pubDate == null) return null; - //Locale for pubDate is always en_US, regardless of device locale - return DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US').parse(pubDate); - } } diff --git a/lib/domain/rss_item_itunes.dart b/lib/domain/rss_item_itunes.dart deleted file mode 100644 index 3d89cc5..0000000 --- a/lib/domain/rss_item_itunes.dart +++ /dev/null @@ -1,83 +0,0 @@ -import 'package:webfeed/util/helpers.dart'; -import 'package:xml/xml.dart'; - -import 'rss_itunes_category.dart'; -import 'rss_itunes_episode_type.dart'; -import 'rss_itunes_image.dart'; - -class RssItemItunes { - final String title; - final int episode; - final int season; - final Duration duration; - final RssItunesEpisodeType episodeType; - final String author; - final String summary; - final bool explicit; - final String subtitle; - final List keywords; - final RssItunesImage image; - final RssItunesCategory category; - final bool block; - - RssItemItunes({ - this.title, - this.episode, - this.season, - this.duration, - this.episodeType, - this.author, - this.summary, - this.explicit, - this.subtitle, - this.keywords, - this.image, - this.category, - this.block, - }); - - factory RssItemItunes.parse(XmlElement element) { - if (element == null) { - return null; - } - var episodeStr = findElementOrNull(element, "itunes:episode")?.text?.trim(); - var seasonStr = findElementOrNull(element, "itunes:season")?.text?.trim(); - var durationStr = findElementOrNull(element, "itunes:duration")?.text?.trim(); - - return RssItemItunes( - title: findElementOrNull(element, "itunes:title")?.text?.trim(), - episode: episodeStr == null ? null : int.parse(episodeStr), - season: seasonStr == null ? null : int.parse(seasonStr), - duration: durationStr == null ? null : parseDuration(durationStr), - episodeType: newRssItunesEpisodeType(findElementOrNull(element, "itunes:episodeType")), - author: findElementOrNull(element, "itunes:author")?.text?.trim(), - summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), - explicit: parseBoolLiteral(element, "itunes:explicit"), - subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), - keywords: findElementOrNull(element, "itunes:keywords")?.text?.split(",")?.map((keyword) => keyword.trim())?.toList(), - image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), - category: RssItunesCategory.parse( - findElementOrNull(element, "itunes:category")), - block: parseBoolLiteral(element, "itunes:block"), - ); - } -} - -Duration parseDuration(String s) { - var hours = 0; - var minutes = 0; - var seconds = 0; - var parts = s.split(':'); - if (parts.length > 2) { - hours = int.parse(parts[parts.length - 3]); - } - if (parts.length > 1) { - minutes = int.parse(parts[parts.length - 2]); - } - seconds = int.parse(parts[parts.length - 1]); - return Duration( - hours: hours, - minutes: minutes, - seconds: seconds, - ); -} diff --git a/lib/domain/rss_itunes.dart b/lib/domain/rss_itunes.dart deleted file mode 100644 index c58ad66..0000000 --- a/lib/domain/rss_itunes.dart +++ /dev/null @@ -1,69 +0,0 @@ -import 'package:xml/xml.dart'; - -import 'package:webfeed/util/helpers.dart'; - -import 'rss_itunes_category.dart'; -import 'rss_itunes_image.dart'; -import 'rss_itunes_owner.dart'; -import 'rss_itunes_type.dart'; - -class RssItunes { - final String author; - final String summary; - final bool explicit; - final String title; - final String subtitle; - final RssItunesOwner owner; - final List keywords; - final RssItunesImage image; - final List categories; - final RssItunesType type; - final String newFeedUrl; - final bool block; - final bool complete; - - RssItunes({ - this.author, - this.summary, - this.explicit, - this.title, - this.subtitle, - this.owner, - this.keywords, - this.image, - this.categories, - this.type, - this.newFeedUrl, - this.block, - this.complete, - }); - - factory RssItunes.parse(XmlElement element) { - if (element == null) { - return null; - } - return RssItunes( - author: findElementOrNull(element, "itunes:author")?.text?.trim(), - summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), - explicit: parseBoolLiteral(element, "itunes:explicit"), - title: findElementOrNull(element, "itunes:title")?.text?.trim(), - subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), - owner: RssItunesOwner.parse(findElementOrNull(element, "itunes:owner")), - keywords: findElementOrNull(element, "itunes:keywords") - ?.text - ?.split(",") - ?.map((keyword) => keyword.trim()) - ?.toList(), - image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), - 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"), - ); - } -} - diff --git a/lib/domain/rss_itunes_category.dart b/lib/domain/rss_itunes_category.dart deleted file mode 100644 index b79f339..0000000 --- a/lib/domain/rss_itunes_category.dart +++ /dev/null @@ -1,24 +0,0 @@ -import 'package:xml/xml.dart'; - -class RssItunesCategory { - final String category; - final List subCategories; - - RssItunesCategory({this.category, this.subCategories}); - - factory RssItunesCategory.parse(XmlElement element) { - if (element == null) return null; - - Iterable subCategories; - try { - subCategories = element.findElements("itunes:category"); - } on StateError { - subCategories = null; - } - return RssItunesCategory( - category: element.getAttribute("text")?.trim(), - subCategories: - subCategories?.map((ele) => ele.getAttribute("text")?.trim())?.toList(), - ); - } -} diff --git a/lib/domain/rss_itunes_episode_type.dart b/lib/domain/rss_itunes_episode_type.dart deleted file mode 100644 index 30e639d..0000000 --- a/lib/domain/rss_itunes_episode_type.dart +++ /dev/null @@ -1,19 +0,0 @@ -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; - } -} diff --git a/lib/domain/rss_itunes_image.dart b/lib/domain/rss_itunes_image.dart deleted file mode 100644 index 7b2ef2f..0000000 --- a/lib/domain/rss_itunes_image.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:xml/xml.dart'; - -class RssItunesImage { - final String href; - - RssItunesImage({this.href}); - - factory RssItunesImage.parse(XmlElement element) { - if (element == null) return null; - return RssItunesImage( - href: element.getAttribute("href")?.trim(), - ); - } -} diff --git a/lib/domain/rss_itunes_owner.dart b/lib/domain/rss_itunes_owner.dart deleted file mode 100644 index 4bcadc5..0000000 --- a/lib/domain/rss_itunes_owner.dart +++ /dev/null @@ -1,18 +0,0 @@ -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(), - ); - } -} diff --git a/lib/domain/rss_itunes_type.dart b/lib/domain/rss_itunes_type.dart deleted file mode 100644 index b2cb031..0000000 --- a/lib/domain/rss_itunes_type.dart +++ /dev/null @@ -1,17 +0,0 @@ -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; - } -} diff --git a/lib/domain/rss_source.dart b/lib/domain/rss_source.dart index 6d82be8..056fe7b 100644 --- a/lib/domain/rss_source.dart +++ b/lib/domain/rss_source.dart @@ -10,7 +10,7 @@ class RssSource { if (element == null) { return null; } - var url = element.getAttribute("url"); + var url = element.getAttribute('url'); var value = element.text; return RssSource(url, value); diff --git a/lib/domain/syndication/syndication.dart b/lib/domain/syndication/syndication.dart new file mode 100644 index 0000000..4b05e12 --- /dev/null +++ b/lib/domain/syndication/syndication.dart @@ -0,0 +1,51 @@ +import 'package:webfeed/util/datetime.dart'; +import 'package:webfeed/util/xml.dart'; +import 'package:xml/xml.dart'; + +enum SyndicationUpdatePeriod { hourly, daily, weekly, monthly, yearly } + +class Syndication { + final SyndicationUpdatePeriod updatePeriod; + final int updateFrequency; + final DateTime updateBase; + + Syndication({ + this.updatePeriod, + this.updateFrequency, + this.updateBase, + }); + + factory Syndication.parse(XmlElement element) { + if (element == null) { + return null; + } + SyndicationUpdatePeriod updatePeriod; + switch (findFirstElement(element, 'sy:updatePeriod')?.text) { + case 'hourly': + updatePeriod = SyndicationUpdatePeriod.hourly; + break; + case 'daily': + updatePeriod = SyndicationUpdatePeriod.daily; + break; + case 'weekly': + updatePeriod = SyndicationUpdatePeriod.weekly; + break; + case 'monthly': + updatePeriod = SyndicationUpdatePeriod.monthly; + break; + case 'yearly': + updatePeriod = SyndicationUpdatePeriod.yearly; + break; + default: + updatePeriod = SyndicationUpdatePeriod.daily; + break; + } + return Syndication( + updatePeriod: updatePeriod, + updateFrequency: int.tryParse( + findFirstElement(element, 'sy:updateFrequency')?.text ?? '1'), + updateBase: + parseDateTime(findFirstElement(element, 'sy:updateBase')?.text), + ); + } +} diff --git a/lib/util/datetime.dart b/lib/util/datetime.dart new file mode 100644 index 0000000..8c79901 --- /dev/null +++ b/lib/util/datetime.dart @@ -0,0 +1,24 @@ +import 'package:intl/intl.dart'; + +var rfc822DateFormat = DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US'); + +DateTime parseDateTime(dateString) { + if (dateString == null) return null; + return _parseRfc822DateTime(dateString) ?? _parseIso8601DateTime(dateString); +} + +DateTime _parseRfc822DateTime(dateString) { + try { + return rfc822DateFormat.parse(dateString); + } on FormatException { + return null; + } +} + +DateTime _parseIso8601DateTime(dateString) { + try { + return DateTime.parse(dateString); + } on FormatException { + return null; + } +} diff --git a/lib/util/helpers.dart b/lib/util/helpers.dart deleted file mode 100644 index 179926c..0000000 --- a/lib/util/helpers.dart +++ /dev/null @@ -1,28 +0,0 @@ -import 'dart:core'; - -import 'package:xml/xml.dart'; - -XmlElement findElementOrNull(XmlElement element, String name, - {String namespace}) { - try { - return element.findAllElements(name, namespace: namespace).first; - } on StateError { - return null; - } -} - -List 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); -} - diff --git a/lib/util/xml.dart b/lib/util/xml.dart new file mode 100644 index 0000000..460ff93 --- /dev/null +++ b/lib/util/xml.dart @@ -0,0 +1,40 @@ +import 'dart:core'; + +import 'package:xml/xml.dart'; + +XmlElement findFirstElement( + XmlNode node, + String name, { + bool recursive = false, + String namespace, +}) { + try { + return findElements(node, name, recursive: recursive, namespace: namespace) + ?.first; + } on StateError { + return null; + } +} + +Iterable findElements( + XmlNode node, + String name, { + bool recursive = false, + String namespace, +}) { + try { + if (recursive) { + return node.findAllElements(name, namespace: namespace); + } else { + return node.findElements(name, namespace: namespace); + } + } on StateError { + return null; + } +} + +bool parseBoolLiteral(XmlElement element, String tagName) { + var v = findFirstElement(element, tagName)?.text?.toLowerCase()?.trim(); + if (v == null) return false; + return ['yes', 'true'].contains(v); +} diff --git a/pubspec.yaml b/pubspec.yaml index 85aa596..78ec0ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,12 +1,11 @@ name: webfeed -version: 0.4.2 -description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. -author: Wito Chandra +version: 0.6.0 +description: webfeed is a dart package for parsing RSS and Atom feeds. Media, DublinCore, iTunes, Syndication namespaces are also supported. homepage: https://github.com/witochandra/webfeed environment: sdk: ">=2.0.0 <3.0.0" dependencies: - xml: "^3.0.0" + xml: "^4.2.0" intl: "^0.16.0" dev_dependencies: test: ^1.3.0 diff --git a/test/atom_test.dart b/test/atom_test.dart index e7ba377..1cd24fc 100644 --- a/test/atom_test.dart +++ b/test/atom_test.dart @@ -5,113 +5,113 @@ import 'package:test/test.dart'; import 'package:webfeed/webfeed.dart'; void main() { - test("parse Invalid.xml", () { - var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); + test('parse Invalid.xml', () { + var xmlString = File('test/xml/Invalid.xml').readAsStringSync(); try { - new AtomFeed.parse(xmlString); - fail("Should throw Argument Error"); + AtomFeed.parse(xmlString); + fail('Should throw Argument Error'); } on ArgumentError {} }); - test("parse Atom.xml", () { - var xmlString = new File("test/xml/Atom.xml").readAsStringSync(); + test('parse Atom.xml', () { + var xmlString = File('test/xml/Atom.xml').readAsStringSync(); - var feed = new AtomFeed.parse(xmlString); + var feed = AtomFeed.parse(xmlString); - expect(feed.id, "foo-bar-id"); - expect(feed.title, "Foo bar news"); - expect(feed.updated, "2018-04-06T13:02:46Z"); + expect(feed.id, 'foo-bar-id'); + expect(feed.title, 'Foo bar news'); + expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); expect(feed.links.length, 2); - expect(feed.links.first.rel, "foo"); - expect(feed.links.first.type, "text/html"); - expect(feed.links.first.hreflang, "en"); - expect(feed.links.first.href, "http://foo.bar.news/"); - expect(feed.links.first.title, "Foo bar news html"); + expect(feed.links.first.rel, 'foo'); + expect(feed.links.first.type, 'text/html'); + expect(feed.links.first.hreflang, 'en'); + expect(feed.links.first.href, 'http://foo.bar.news/'); + expect(feed.links.first.title, 'Foo bar news html'); expect(feed.links.first.length, 1000); expect(feed.authors.length, 2); - expect(feed.authors.first.name, "Alice"); - expect(feed.authors.first.uri, "http://foo.bar.news/people/alice"); - expect(feed.authors.first.email, "alice@foo.bar.news"); + expect(feed.authors.first.name, 'Alice'); + expect(feed.authors.first.uri, 'http://foo.bar.news/people/alice'); + expect(feed.authors.first.email, 'alice@foo.bar.news'); expect(feed.contributors.length, 2); - expect(feed.contributors.first.name, "Charlie"); - expect(feed.contributors.first.uri, "http://foo.bar.news/people/charlie"); - expect(feed.contributors.first.email, "charlie@foo.bar.news"); + expect(feed.contributors.first.name, 'Charlie'); + expect(feed.contributors.first.uri, 'http://foo.bar.news/people/charlie'); + expect(feed.contributors.first.email, 'charlie@foo.bar.news'); expect(feed.categories.length, 2); - expect(feed.categories.first.term, "foo category"); - expect(feed.categories.first.scheme, "this-is-foo-scheme"); - expect(feed.categories.first.label, "this is foo label"); + expect(feed.categories.first.term, 'foo category'); + expect(feed.categories.first.scheme, 'this-is-foo-scheme'); + expect(feed.categories.first.label, 'this is foo label'); - expect(feed.generator.uri, "http://foo.bar.news/generator"); - expect(feed.generator.version, "1.0"); - expect(feed.generator.value, "Foo bar generator"); + expect(feed.generator.uri, 'http://foo.bar.news/generator'); + expect(feed.generator.version, '1.0'); + expect(feed.generator.value, 'Foo bar generator'); - expect(feed.icon, "http://foo.bar.news/icon.png"); - expect(feed.logo, "http://foo.bar.news/logo.png"); - expect(feed.subtitle, "This is subtitle"); + expect(feed.icon, 'http://foo.bar.news/icon.png'); + expect(feed.logo, 'http://foo.bar.news/logo.png'); + expect(feed.subtitle, 'This is subtitle'); expect(feed.items.length, 2); var item = feed.items.first; - expect(item.id, "foo-bar-entry-id-1"); - expect(item.title, "Foo bar item 1"); - expect(item.updated, "2018-04-06T13:02:47Z"); + expect(item.id, 'foo-bar-entry-id-1'); + expect(item.title, 'Foo bar item 1'); + expect(item.updated, DateTime.utc(2018, 4, 6, 13, 2, 40)); expect(item.authors.length, 2); - expect(item.authors.first.name, "Ellie"); - expect(item.authors.first.uri, "http://foo.bar.news/people/ellie"); - expect(item.authors.first.email, "ellie@foo.bar.news"); + expect(item.authors.first.name, 'Ellie'); + expect(item.authors.first.uri, 'http://foo.bar.news/people/ellie'); + expect(item.authors.first.email, 'ellie@foo.bar.news'); expect(item.links.length, 2); - expect(item.links.first.rel, "foo entry"); - expect(item.links.first.type, "text/html"); - expect(item.links.first.hreflang, "en"); - expect(item.links.first.href, "http://foo.bar.news/entry"); - expect(item.links.first.title, "Foo bar news html"); + expect(item.links.first.rel, 'foo entry'); + expect(item.links.first.type, 'text/html'); + expect(item.links.first.hreflang, 'en'); + expect(item.links.first.href, 'http://foo.bar.news/entry'); + expect(item.links.first.title, 'Foo bar news html'); expect(item.links.first.length, 1000); expect(item.categories.length, 2); - expect(item.categories.first.term, "foo entry category"); - expect(item.categories.first.scheme, "this-is-foo-entry-scheme"); - expect(item.categories.first.label, "this is foo entry label"); + expect(item.categories.first.term, 'foo entry category'); + expect(item.categories.first.scheme, 'this-is-foo-entry-scheme'); + expect(item.categories.first.label, 'this is foo entry label'); expect(item.contributors.length, 2); - expect(item.contributors.first.name, "Gin"); - expect(item.contributors.first.uri, "http://foo.bar.news/people/gin"); - expect(item.contributors.first.email, "gin@foo.bar.news"); - - expect(item.published, "2018-04-06T13:02:49Z"); - expect(item.summary, "This is summary 1"); - expect(item.content, "This is content 1"); - expect(item.rights, "This is rights 1"); + expect(item.contributors.first.name, 'Gin'); + expect(item.contributors.first.uri, 'http://foo.bar.news/people/gin'); + expect(item.contributors.first.email, 'gin@foo.bar.news'); + + expect(item.published, '2018-04-06T13:02:49Z'); + expect(item.summary, 'This is summary 1'); + expect(item.content, 'This is content 1'); + expect(item.rights, 'This is rights 1'); }); - test("parse Atom-Media.xml", (){ - var xmlString = new File("test/xml/Atom-Media.xml").readAsStringSync(); + test('parse Atom-Media.xml', () { + var xmlString = File('test/xml/Atom-Media.xml').readAsStringSync(); - var feed = new AtomFeed.parse(xmlString); - expect(feed.id, "foo-bar-id"); - expect(feed.title, "Foo bar news"); - expect(feed.updated, "2018-04-06T13:02:46Z"); + var feed = AtomFeed.parse(xmlString); + expect(feed.id, 'foo-bar-id'); + expect(feed.title, 'Foo bar news'); + expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); expect(feed.items.length, 1); - + var item = feed.items.first; expect(item.media.group.contents.length, 5); expect(item.media.group.credits.length, 2); - expect(item.media.group.category.value, "music/artist name/album/song"); - expect(item.media.group.rating.value, "nonadult"); + expect(item.media.group.category.value, 'music/artist name/album/song'); + expect(item.media.group.rating.value, 'nonadult'); expect(item.media.contents.length, 2); var mediaContent = item.media.contents.first; - expect(mediaContent.url, "http://www.foo.com/video.mov"); - expect(mediaContent.type, "video/quicktime"); + expect(mediaContent.url, 'http://www.foo.com/video.mov'); + expect(mediaContent.type, 'video/quicktime'); expect(mediaContent.fileSize, 2000); - expect(mediaContent.medium, "video"); + expect(mediaContent.medium, 'video'); expect(mediaContent.isDefault, true); - expect(mediaContent.expression, "full"); + expect(mediaContent.expression, 'full'); expect(mediaContent.bitrate, 128); expect(mediaContent.framerate, 25); expect(mediaContent.samplingrate, 44.1); @@ -119,52 +119,54 @@ void main() { expect(item.media.credits.length, 2); var mediaCredit = item.media.credits.first; - expect(mediaCredit.role, "owner1"); - expect(mediaCredit.scheme, "urn:yvs"); - expect(mediaCredit.value, "copyright holder of the entity"); + expect(mediaCredit.role, 'owner1'); + expect(mediaCredit.scheme, 'urn:yvs'); + expect(mediaCredit.value, 'copyright holder of the entity'); - expect(item.media.category.scheme, "http://search.yahoo.com/mrss/category_ schema"); - expect(item.media.category.label, "Music"); - expect(item.media.category.value, "music/artist/album/song"); + expect(item.media.category.scheme, + 'http://search.yahoo.com/mrss/category_ schema'); + expect(item.media.category.label, 'Music'); + expect(item.media.category.value, 'music/artist/album/song'); - expect(item.media.rating.scheme, "urn:simple"); - expect(item.media.rating.value, "adult"); + expect(item.media.rating.scheme, 'urn:simple'); + expect(item.media.rating.value, 'adult'); - expect(item.media.title.type, "plain"); + expect(item.media.title.type, 'plain'); expect(item.media.title.value, "The Judy's -- The Moo Song"); - 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.keywords, "kitty, cat, big dog, yarn, fluffy"); - + 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.keywords, 'kitty, cat, big dog, yarn, fluffy'); + expect(item.media.thumbnails.length, 2); var mediaThumbnail = item.media.thumbnails.first; - expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); - expect(mediaThumbnail.width, "75"); - expect(mediaThumbnail.height, "50"); - expect(mediaThumbnail.time, "12:05:01.123"); + expect(mediaThumbnail.url, 'http://www.foo.com/keyframe1.jpg'); + expect(mediaThumbnail.width, '75'); + expect(mediaThumbnail.height, '50'); + expect(mediaThumbnail.time, '12:05:01.123'); - expect(item.media.hash.algo, "md5"); - expect(item.media.hash.value, "dfdec888b72151965a34b4b59031290a"); + expect(item.media.hash.algo, 'md5'); + expect(item.media.hash.value, 'dfdec888b72151965a34b4b59031290a'); - expect(item.media.player.url, "http://www.foo.com/player?id=1111"); + expect(item.media.player.url, 'http://www.foo.com/player?id=1111'); expect(item.media.player.width, 400); expect(item.media.player.height, 200); - expect(item.media.player.value, ""); + expect(item.media.player.value, ''); - expect(item.media.copyright.url, "http://blah.com/additional-info.html"); - expect(item.media.copyright.value, "2005 FooBar Media"); + expect(item.media.copyright.url, 'http://blah.com/additional-info.html'); + expect(item.media.copyright.value, '2005 FooBar Media'); - expect(item.media.text.type, "plain"); - expect(item.media.text.lang, "en"); - expect(item.media.text.start, "00:00:03.000"); - expect(item.media.text.end, "00:00:10.000"); - expect(item.media.text.value, " Oh, say, can you see"); + expect(item.media.text.type, 'plain'); + expect(item.media.text.lang, 'en'); + expect(item.media.text.start, '00:00:03.000'); + expect(item.media.text.end, '00:00:10.000'); + expect(item.media.text.value, ' Oh, say, can you see'); - expect(item.media.restriction.relationship, "allow"); - expect(item.media.restriction.type, "country"); - expect(item.media.restriction.value, "au us"); + expect(item.media.restriction.relationship, 'allow'); + expect(item.media.restriction.type, 'country'); + expect(item.media.restriction.value, 'au us'); expect(item.media.community.starRating.average, 3.5); expect(item.media.community.starRating.count, 20); @@ -172,56 +174,58 @@ void main() { expect(item.media.community.starRating.max, 10); expect(item.media.community.statistics.views, 5); expect(item.media.community.statistics.favorites, 4); - expect(item.media.community.tags.tags, "news: 5, abc:3"); + expect(item.media.community.tags.tags, 'news: 5, abc:3'); expect(item.media.community.tags.weight, 1); expect(item.media.comments.length, 2); - expect(item.media.comments.first, "comment1"); - expect(item.media.comments.last, "comment2"); + expect(item.media.comments.first, 'comment1'); + expect(item.media.comments.last, 'comment2'); - expect(item.media.embed.url, "http://www.foo.com/player.swf"); + expect(item.media.embed.url, 'http://www.foo.com/player.swf'); expect(item.media.embed.width, 512); expect(item.media.embed.height, 323); expect(item.media.embed.params.length, 5); - 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.name, 'type'); + expect( + item.media.embed.params.first.value, 'application/x-shockwave-flash'); expect(item.media.responses.length, 2); - expect(item.media.responses.first, "http://www.response1.com"); - expect(item.media.responses.last, "http://www.response2.com"); + expect(item.media.responses.first, 'http://www.response1.com'); + expect(item.media.responses.last, 'http://www.response2.com'); expect(item.media.backLinks.length, 2); - expect(item.media.backLinks.first, "http://www.backlink1.com"); - expect(item.media.backLinks.last, "http://www.backlink2.com"); + expect(item.media.backLinks.first, 'http://www.backlink1.com'); + expect(item.media.backLinks.last, 'http://www.backlink2.com'); - expect(item.media.status.state, "active"); + expect(item.media.status.state, 'active'); expect(item.media.status.reason, null); expect(item.media.prices.length, 2); expect(item.media.prices.first.price, 19.99); - 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.currency, "EUR"); + 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.currency, 'EUR'); - expect(item.media.license.type, "text/html"); - expect(item.media.license.href, "http://www.licensehost.com/license"); - expect(item.media.license.value, " Sample license for a video"); + expect(item.media.license.type, 'text/html'); + expect(item.media.license.href, 'http://www.licensehost.com/license'); + expect(item.media.license.value, ' Sample license for a video'); - expect(item.media.peerLink.type, "application/x-bittorrent"); - expect(item.media.peerLink.href, "http://www.foo.org/sampleFile.torrent"); - expect(item.media.peerLink.value, ""); + expect(item.media.peerLink.type, 'application/x-bittorrent'); + expect(item.media.peerLink.href, 'http://www.foo.org/sampleFile.torrent'); + expect(item.media.peerLink.value, ''); - expect(item.media.rights.status, "official"); + expect(item.media.rights.status, 'official'); expect(item.media.scenes.length, 2); - expect(item.media.scenes.first.title, "sceneTitle1"); - expect(item.media.scenes.first.description, "sceneDesc1"); - expect(item.media.scenes.first.startTime, "00:15"); - expect(item.media.scenes.first.endTime, "00:45"); + expect(item.media.scenes.first.title, 'sceneTitle1'); + expect(item.media.scenes.first.description, 'sceneDesc1'); + expect(item.media.scenes.first.startTime, '00:15'); + expect(item.media.scenes.first.endTime, '00:45'); }); - test("parse Atom-Empty.xml", () { - var xmlString = File("test/xml/Atom-Empty.xml").readAsStringSync(); + test('parse Atom-Empty.xml', () { + var xmlString = File('test/xml/Atom-Empty.xml').readAsStringSync(); var feed = AtomFeed.parse(xmlString); diff --git a/test/rss_test.dart b/test/rss_test.dart index 60cd46c..44eb9b2 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -2,60 +2,60 @@ import 'dart:core'; import 'dart:io'; import 'package:test/test.dart'; +import 'package:webfeed/domain/itunes/itunes_episode_type.dart'; +import 'package:webfeed/domain/itunes/itunes_type.dart'; +import 'package:webfeed/domain/syndication/syndication.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() { - test("parse Invalid.xml", () { - var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); + test('parse Invalid.xml', () { + var xmlString = File('test/xml/Invalid.xml').readAsStringSync(); try { - new RssFeed.parse(xmlString); - fail("Should throw Argument Error"); + RssFeed.parse(xmlString); + fail('Should throw Argument Error'); } on ArgumentError {} }); - test("parse RSS.xml", () { - var xmlString = new File("test/xml/RSS.xml").readAsStringSync(); + test('parse RSS.xml', () { + var xmlString = File('test/xml/RSS.xml').readAsStringSync(); - var feed = new RssFeed.parse(xmlString); + var feed = 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.link, "https://foo.bar.news/"); - expect(feed.author, "hello@world.net"); - expect(feed.language, "en-US"); - expect(feed.lastBuildDate, "Mon, 26 Mar 2018 14:00:00 PDT"); - expect(feed.generator, "Custom"); - expect(feed.copyright, "Copyright 2018, Foo bar Inc."); - expect(feed.docs, "https://foo.bar.news/docs"); - expect(feed.managingEditor, "alice@foo.bar.news"); - expect(feed.rating, "The PICS rating of the feed"); - expect(feed.webMaster, "webmaster@foo.bar.news"); + 'Foo bar News and Updates feed provided by Foo bar, Inc.'); + expect(feed.link, 'https://foo.bar.news/'); + expect(feed.author, 'hello@world.net'); + expect(feed.language, 'en-US'); + expect(feed.lastBuildDate, 'Mon, 26 Mar 2018 14:00:00 PDT'); + expect(feed.generator, 'Custom'); + expect(feed.copyright, 'Copyright 2018, Foo bar Inc.'); + expect(feed.docs, 'https://foo.bar.news/docs'); + expect(feed.managingEditor, 'alice@foo.bar.news'); + expect(feed.rating, 'The PICS rating of the feed'); + expect(feed.webMaster, 'webmaster@foo.bar.news'); expect(feed.ttl, 60); - expect(feed.image.title, "Foo bar News"); - expect(feed.image.url, "https://foo.bar.news/logo.gif"); - expect(feed.image.link, "https://foo.bar.news/"); + expect(feed.image.title, 'Foo bar News'); + expect(feed.image.url, 'https://foo.bar.news/logo.gif'); + expect(feed.image.link, 'https://foo.bar.news/'); - expect(feed.cloud.domain, "radio.foo.bar.news"); - expect(feed.cloud.port, "80"); - expect(feed.cloud.path, "/RPC2"); - expect(feed.cloud.registerProcedure, "foo.bar.rssPleaseNotify"); - expect(feed.cloud.protocol, "xml-rpc"); + expect(feed.cloud.domain, 'radio.foo.bar.news'); + expect(feed.cloud.port, '80'); + expect(feed.cloud.path, '/RPC2'); + expect(feed.cloud.registerProcedure, 'foo.bar.rssPleaseNotify'); + expect(feed.cloud.protocol, 'xml-rpc'); expect(feed.categories.length, 2); expect(feed.categories[0].domain, null); - expect(feed.categories[0].value, "Ipsum"); - expect(feed.categories[1].domain, "news"); - expect(feed.categories[1].value, "Lorem Ipsum"); + expect(feed.categories[0].value, 'Ipsum'); + expect(feed.categories[1].domain, 'news'); + expect(feed.categories[1].value, 'Lorem Ipsum'); expect(feed.skipDays.length, 3); - expect(feed.skipDays.contains("Monday"), true); - expect(feed.skipDays.contains("Tuesday"), true); - expect(feed.skipDays.contains("Sunday"), true); + expect(feed.skipDays.contains('Monday'), true); + expect(feed.skipDays.contains('Tuesday'), true); + expect(feed.skipDays.contains('Sunday'), true); expect(feed.skipHours.length, 5); expect(feed.skipHours.contains(0), true); @@ -67,56 +67,58 @@ void main() { expect(feed.items.length, 2); expect(feed.items.first.title, - "The standard Lorem Ipsum passage, used since the 1500s"); + '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.guid, "https://foo.bar.news/1?guid"); - expect(feed.items.first.pubDate, DateTime(2018, 03, 26, 14)); //Mon, 26 Mar 2018 14:00:00 PDT - expect(feed.items.first.categories.first.domain, "news"); - expect(feed.items.first.categories.first.value, "Lorem"); - expect(feed.items.first.author, "alice@foo.bar.news"); - expect(feed.items.first.source.url, "https://foo.bar.news/1?source"); - expect(feed.items.first.source.value, "Foo Bar"); - expect(feed.items.first.comments, "https://foo.bar.news/1/comments"); + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'); + 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.pubDate, + DateTime(2018, 03, 26, 14)); //Mon, 26 Mar 2018 14:00:00 PDT + expect(feed.items.first.categories.first.domain, 'news'); + expect(feed.items.first.categories.first.value, 'Lorem'); + expect(feed.items.first.author, 'alice@foo.bar.news'); + expect(feed.items.first.source.url, 'https://foo.bar.news/1?source'); + expect(feed.items.first.source.value, 'Foo Bar'); + expect(feed.items.first.comments, 'https://foo.bar.news/1/comments'); expect(feed.items.first.enclosure.url, - "http://www.scripting.com/mp3s/weatherReportSuite.mp3"); + 'http://www.scripting.com/mp3s/weatherReportSuite.mp3'); 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, - " Test content
"); + ' Test content
'); expect( - feed.items.first.content.images.first, "https://test.com/image_link"); + feed.items.first.content.images.first, 'https://test.com/image_link'); }); - test("parse RSS-Media.xml", () { - var xmlString = new File("test/xml/RSS-Media.xml").readAsStringSync(); + test('parse RSS-Media.xml', () { + var xmlString = File('test/xml/RSS-Media.xml').readAsStringSync(); - var feed = new RssFeed.parse(xmlString); - expect(feed.title, "Song Site"); + var feed = RssFeed.parse(xmlString); + expect(feed.title, 'Song Site'); expect( - feed.description, "Media RSS example with new fields added in v1.5.0"); + feed.description, 'Media RSS example with new fields added in v1.5.0'); expect(feed.items.length, 1); var item = feed.items.first; expect(item.title, null); - expect(item.link, "http://www.foo.com"); - expect(item.pubDate, DateTime(2001, 08, 27, 16, 08, 56)); //Mon, 27 Aug 2001 16:08:56 PST + expect(item.link, 'http://www.foo.com'); + expect(item.pubDate, + DateTime(2001, 08, 27, 16, 08, 56)); //Mon, 27 Aug 2001 16:08:56 PST expect(item.media.group.contents.length, 5); expect(item.media.group.credits.length, 2); - expect(item.media.group.category.value, "music/artist name/album/song"); - expect(item.media.group.rating.value, "nonadult"); + expect(item.media.group.category.value, 'music/artist name/album/song'); + expect(item.media.group.rating.value, 'nonadult'); expect(item.media.contents.length, 2); var mediaContent = item.media.contents.first; - expect(mediaContent.url, "http://www.foo.com/video.mov"); - expect(mediaContent.type, "video/quicktime"); + expect(mediaContent.url, 'http://www.foo.com/video.mov'); + expect(mediaContent.type, 'video/quicktime'); expect(mediaContent.fileSize, 2000); - expect(mediaContent.medium, "video"); + expect(mediaContent.medium, 'video'); expect(mediaContent.isDefault, true); - expect(mediaContent.expression, "full"); + expect(mediaContent.expression, 'full'); expect(mediaContent.bitrate, 128); expect(mediaContent.framerate, 25); expect(mediaContent.samplingrate, 44.1); @@ -124,54 +126,54 @@ void main() { expect(item.media.credits.length, 2); var mediaCredit = item.media.credits.first; - expect(mediaCredit.role, "owner1"); - expect(mediaCredit.scheme, "urn:yvs"); - expect(mediaCredit.value, "copyright holder of the entity"); + expect(mediaCredit.role, 'owner1'); + expect(mediaCredit.scheme, 'urn:yvs'); + expect(mediaCredit.value, 'copyright holder of the entity'); expect(item.media.category.scheme, - "http://search.yahoo.com/mrss/category_ schema"); - expect(item.media.category.label, "Music"); - expect(item.media.category.value, "music/artist/album/song"); + 'http://search.yahoo.com/mrss/category_ schema'); + expect(item.media.category.label, 'Music'); + expect(item.media.category.value, 'music/artist/album/song'); - expect(item.media.rating.scheme, "urn:simple"); - expect(item.media.rating.value, "adult"); + expect(item.media.rating.scheme, 'urn:simple'); + expect(item.media.rating.value, 'adult'); - expect(item.media.title.type, "plain"); + expect(item.media.title.type, 'plain'); 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."); + '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); var mediaThumbnail = item.media.thumbnails.first; - expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); - expect(mediaThumbnail.width, "75"); - expect(mediaThumbnail.height, "50"); - expect(mediaThumbnail.time, "12:05:01.123"); + expect(mediaThumbnail.url, 'http://www.foo.com/keyframe1.jpg'); + expect(mediaThumbnail.width, '75'); + expect(mediaThumbnail.height, '50'); + expect(mediaThumbnail.time, '12:05:01.123'); - expect(item.media.hash.algo, "md5"); - expect(item.media.hash.value, "dfdec888b72151965a34b4b59031290a"); + expect(item.media.hash.algo, 'md5'); + expect(item.media.hash.value, 'dfdec888b72151965a34b4b59031290a'); - expect(item.media.player.url, "http://www.foo.com/player?id=1111"); + expect(item.media.player.url, 'http://www.foo.com/player?id=1111'); expect(item.media.player.width, 400); expect(item.media.player.height, 200); - expect(item.media.player.value, ""); + expect(item.media.player.value, ''); - expect(item.media.copyright.url, "http://blah.com/additional-info.html"); - expect(item.media.copyright.value, "2005 FooBar Media"); + expect(item.media.copyright.url, 'http://blah.com/additional-info.html'); + expect(item.media.copyright.value, '2005 FooBar Media'); - expect(item.media.text.type, "plain"); - expect(item.media.text.lang, "en"); - expect(item.media.text.start, "00:00:03.000"); - expect(item.media.text.end, "00:00:10.000"); - expect(item.media.text.value, " Oh, say, can you see"); + expect(item.media.text.type, 'plain'); + expect(item.media.text.lang, 'en'); + expect(item.media.text.start, '00:00:03.000'); + expect(item.media.text.end, '00:00:10.000'); + expect(item.media.text.value, ' Oh, say, can you see'); - expect(item.media.restriction.relationship, "allow"); - expect(item.media.restriction.type, "country"); - expect(item.media.restriction.value, "au us"); + expect(item.media.restriction.relationship, 'allow'); + expect(item.media.restriction.type, 'country'); + expect(item.media.restriction.value, 'au us'); expect(item.media.community.starRating.average, 3.5); expect(item.media.community.starRating.count, 20); @@ -179,95 +181,99 @@ void main() { expect(item.media.community.starRating.max, 10); expect(item.media.community.statistics.views, 5); expect(item.media.community.statistics.favorites, 4); - expect(item.media.community.tags.tags, "news: 5, abc:3"); + expect(item.media.community.tags.tags, 'news: 5, abc:3'); expect(item.media.community.tags.weight, 1); expect(item.media.comments.length, 2); - expect(item.media.comments.first, "comment1"); - expect(item.media.comments.last, "comment2"); + expect(item.media.comments.first, 'comment1'); + expect(item.media.comments.last, 'comment2'); - expect(item.media.embed.url, "http://www.foo.com/player.swf"); + expect(item.media.embed.url, 'http://www.foo.com/player.swf'); expect(item.media.embed.width, 512); expect(item.media.embed.height, 323); 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"); + item.media.embed.params.first.value, 'application/x-shockwave-flash'); expect(item.media.responses.length, 2); - expect(item.media.responses.first, "http://www.response1.com"); - expect(item.media.responses.last, "http://www.response2.com"); + expect(item.media.responses.first, 'http://www.response1.com'); + expect(item.media.responses.last, 'http://www.response2.com'); expect(item.media.backLinks.length, 2); - expect(item.media.backLinks.first, "http://www.backlink1.com"); - expect(item.media.backLinks.last, "http://www.backlink2.com"); + expect(item.media.backLinks.first, 'http://www.backlink1.com'); + expect(item.media.backLinks.last, 'http://www.backlink2.com'); - expect(item.media.status.state, "active"); + expect(item.media.status.state, 'active'); expect(item.media.status.reason, null); expect(item.media.prices.length, 2); 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.currency, "EUR"); + item.media.prices.first.info, 'http://www.dummy.jp/package_info.html'); + expect(item.media.prices.first.currency, 'EUR'); - expect(item.media.license.type, "text/html"); - expect(item.media.license.href, "http://www.licensehost.com/license"); - expect(item.media.license.value, " Sample license for a video"); + expect(item.media.license.type, 'text/html'); + expect(item.media.license.href, 'http://www.licensehost.com/license'); + expect(item.media.license.value, ' Sample license for a video'); - expect(item.media.peerLink.type, "application/x-bittorrent"); - expect(item.media.peerLink.href, "http://www.foo.org/sampleFile.torrent"); - expect(item.media.peerLink.value, ""); + expect(item.media.peerLink.type, 'application/x-bittorrent'); + expect(item.media.peerLink.href, 'http://www.foo.org/sampleFile.torrent'); + expect(item.media.peerLink.value, ''); - expect(item.media.rights.status, "official"); + expect(item.media.rights.status, 'official'); expect(item.media.scenes.length, 2); - expect(item.media.scenes.first.title, "sceneTitle1"); - expect(item.media.scenes.first.description, "sceneDesc1"); - expect(item.media.scenes.first.startTime, "00:15"); - expect(item.media.scenes.first.endTime, "00:45"); + expect(item.media.scenes.first.title, 'sceneTitle1'); + expect(item.media.scenes.first.description, 'sceneDesc1'); + expect(item.media.scenes.first.startTime, '00:15'); + expect(item.media.scenes.first.endTime, '00:45'); }); - test("parse RSS-DC.xml", () { - var xmlString = File("test/xml/RSS-DC.xml").readAsStringSync(); + test('parse RSS-DC.xml', () { + var xmlString = File('test/xml/RSS-DC.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.dc.title, "title"); - expect(feed.dc.creator, "creator"); - expect(feed.dc.subject, "subject"); - expect(feed.dc.description, "description"); - expect(feed.dc.publisher, "publisher"); - expect(feed.dc.contributor, "contributor"); - expect(feed.dc.date, "2000-01-01T12:00+00:00"); - expect(feed.dc.type, "type"); - expect(feed.dc.format, "format"); - expect(feed.dc.identifier, "identifier"); - expect(feed.dc.source, "source"); - expect(feed.dc.language, "language"); - expect(feed.dc.relation, "relation"); - expect(feed.dc.coverage, "coverage"); - expect(feed.dc.rights, "rights"); - - expect(feed.items.first.dc.title, "title"); - expect(feed.items.first.dc.creator, "creator"); - expect(feed.items.first.dc.subject, "subject"); - expect(feed.items.first.dc.description, "description"); - expect(feed.items.first.dc.publisher, "publisher"); - expect(feed.items.first.dc.contributor, "contributor"); - expect(feed.items.first.dc.date, "2000-01-01T12:00+00:00"); - expect(feed.items.first.dc.type, "type"); - expect(feed.items.first.dc.format, "format"); - expect(feed.items.first.dc.identifier, "identifier"); - expect(feed.items.first.dc.source, "source"); - expect(feed.items.first.dc.language, "language"); - expect(feed.items.first.dc.relation, "relation"); - expect(feed.items.first.dc.coverage, "coverage"); - expect(feed.items.first.dc.rights, "rights"); + expect(feed.dc.title, 'title'); + expect(feed.dc.creator, 'creator'); + expect(feed.dc.subject, 'subject'); + expect(feed.dc.description, 'description'); + expect(feed.dc.publisher, 'publisher'); + expect(feed.dc.contributor, 'contributor'); + expect(feed.dc.date, DateTime.utc(2000, 1, 1, 12)); + expect(feed.dc.created, DateTime.utc(2000, 1, 1, 13)); + expect(feed.dc.modified, DateTime.utc(2000, 1, 1, 14)); + expect(feed.dc.type, 'type'); + expect(feed.dc.format, 'format'); + expect(feed.dc.identifier, 'identifier'); + expect(feed.dc.source, 'source'); + expect(feed.dc.language, 'language'); + expect(feed.dc.relation, 'relation'); + expect(feed.dc.coverage, 'coverage'); + expect(feed.dc.rights, 'rights'); + + expect(feed.items.first.dc.title, 'title'); + expect(feed.items.first.dc.creator, 'creator'); + expect(feed.items.first.dc.subject, 'subject'); + expect(feed.items.first.dc.description, 'description'); + expect(feed.items.first.dc.publisher, 'publisher'); + expect(feed.items.first.dc.contributor, 'contributor'); + expect(feed.items.first.dc.date, DateTime.utc(2000, 1, 2, 12)); + expect(feed.items.first.dc.created, DateTime.utc(2000, 1, 2, 13)); + expect(feed.items.first.dc.modified, DateTime.utc(2000, 1, 2, 14)); + expect(feed.items.first.dc.type, 'type'); + expect(feed.items.first.dc.format, 'format'); + expect(feed.items.first.dc.identifier, 'identifier'); + expect(feed.items.first.dc.source, 'source'); + expect(feed.items.first.dc.language, 'language'); + expect(feed.items.first.dc.relation, 'relation'); + expect(feed.items.first.dc.coverage, 'coverage'); + expect(feed.items.first.dc.rights, 'rights'); }); - test("parse RSS-Empty.xml", () { - var xmlString = File("test/xml/RSS-Empty.xml").readAsStringSync(); + test('parse RSS-Empty.xml', () { + var xmlString = File('test/xml/RSS-Empty.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); @@ -310,58 +316,96 @@ void main() { expect(feed.items.first.content, null); }); - test("parse RSS-Itunes.xml", () { - var xmlString = File("test/xml/RSS-Itunes.xml").readAsStringSync(); + test('parse RSS-Itunes.xml', () { + var xmlString = File('test/xml/RSS-Itunes.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.itunes.author, "Changelog Media"); - expect(feed.itunes.summary, "Foo"); + expect(feed.itunes.author, 'Changelog Media'); + expect(feed.itunes.summary, 'Foo'); expect(feed.itunes.explicit, false); expect(feed.itunes.image.href, - "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); + '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.email, "editors@changelog.com"); + 'go,golang,open source,software,development'.split(',')); + expect(feed.itunes.owner.name, 'Changelog Media'); + expect(feed.itunes.owner.email, 'editors@changelog.com'); expect( Set.from([ feed.itunes.categories[0].category, feed.itunes.categories[1].category ]), - ["Technology", "Foo"]); + ['Technology', 'Foo']); for (var category in feed.itunes.categories) { switch (category.category) { - case "Foo": - expect(category.subCategories, ["Bar", "Baz"]); + case 'Foo': + expect(category.subCategories, ['Bar', 'Baz']); break; - case "Technology": - expect(category.subCategories, ["Software How-To", "Tech News"]); + 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.title, 'Go Time'); + expect(feed.itunes.type, ItunesType.serial); + expect(feed.itunes.newFeedUrl, 'wubawuba'); expect(feed.itunes.block, true); expect(feed.itunes.complete, true); var item = feed.items[0]; - expect(item.itunes.episodeType, RssItunesEpisodeType.full); + expect(item.itunes.episodeType, ItunesEpisodeType.full); expect(item.itunes.episode, 1); expect(item.itunes.season, 1); expect(item.itunes.image.href, - "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); + 'https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357'); expect(item.itunes.duration, Duration(minutes: 32, seconds: 30)); expect(item.itunes.explicit, false); expect(item.itunes.keywords, - "go,golang,open source,software,development".split(",")); - expect(item.itunes.subtitle, "with Erik, Carlisia, and Brian"); - expect(item.itunes.summary, "Foo"); + 'go,golang,open source,software,development'.split(',')); + expect(item.itunes.subtitle, 'with Erik, Carlisia, and Brian'); + expect(item.itunes.summary, 'Foo'); expect(item.itunes.author, - "Erik St. Martin, Carlisia Pinto, and Brian Ketelsen"); + 'Erik St. Martin, Carlisia Pinto, and Brian Ketelsen'); expect(item.itunes.explicit, false); - expect(item.itunes.title, "awesome title"); + expect(item.itunes.title, 'awesome title'); expect(item.itunes.block, false); }); + + test('parse RSS-RDF.xml', () { + var xmlString = File('test/xml/RSS-RDF.xml').readAsStringSync(); + + var feed = RssFeed.parse(xmlString); + + expect(feed.title, 'Mozilla Dot Org'); + expect(feed.link, 'http://www.mozilla.org'); + expect(feed.description, 'the Mozilla Organization web site'); + expect(feed.image.title, 'Mozilla'); + expect(feed.image.url, 'http://www.mozilla.org/images/moz.gif'); + expect(feed.image.link, 'http://www.mozilla.org'); + expect(feed.items.length, 5); + expect(feed.items.first.title, 'New Status Updates'); + expect(feed.items.first.link, 'http://www.mozilla.org/status/'); + }); + + test('parse RSS-Syndication.xml', () { + var xmlString = File('test/xml/RSS-Syndication.xml').readAsStringSync(); + + var feed = RssFeed.parse(xmlString); + + expect(feed.title, 'Meerkat'); + expect(feed.link, 'http://meerkat.oreillynet.com'); + expect(feed.description, 'Meerkat: An Open Wire Service'); + expect(feed.image.title, 'Meerkat Powered!'); + expect(feed.image.url, + 'http://meerkat.oreillynet.com/icons/meerkat-powered.jpg'); + expect(feed.image.link, 'http://meerkat.oreillynet.com'); + expect(feed.syndication.updatePeriod, SyndicationUpdatePeriod.hourly); + expect(feed.syndication.updateFrequency, 2); + expect(feed.syndication.updateBase, DateTime.utc(2001, 1, 1, 12, 1)); + expect(feed.items.length, 1); + expect(feed.items.first.title, 'XML: A Disruptive Technology'); + expect(feed.items.first.description, + 'XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.'); + expect(feed.items.first.link, 'http://c.moreover.com/click/here.pl?r123'); + }); } diff --git a/test/xml/Atom.xml b/test/xml/Atom.xml index e88eb12..02f02bf 100644 --- a/test/xml/Atom.xml +++ b/test/xml/Atom.xml @@ -35,7 +35,7 @@ foo-bar-entry-id-1 Foo bar item 1 - 2018-04-06T13:02:47Z + 2018-04-06T13:02:40Z Ellie http://foo.bar.news/people/ellie diff --git a/test/xml/RSS-DC.xml b/test/xml/RSS-DC.xml index 6f1242d..8ffcd38 100644 --- a/test/xml/RSS-DC.xml +++ b/test/xml/RSS-DC.xml @@ -9,6 +9,8 @@ publisher contributor 2000-01-01T12:00+00:00 + 2000-01-01T13:00+00:00 + 2000-01-01T14:00+00:00 type format identifier @@ -24,7 +26,9 @@ description publisher contributor - 2000-01-01T12:00+00:00 + 2000-01-02T12:00+00:00 + 2000-01-02T13:00+00:00 + 2000-01-02T14:00+00:00 type format identifier diff --git a/test/xml/RSS-Itunes.xml b/test/xml/RSS-Itunes.xml index 237b564..bb2a6a3 100644 --- a/test/xml/RSS-Itunes.xml +++ b/test/xml/RSS-Itunes.xml @@ -45,12 +45,9 @@ go, golang, open source, software, development with Erik, Carlisia, and Brian Foo - - Erik St. Martin, Carlisia Pinto, and Brian Ketelsen + Erik St. Martin, Carlisia Pinto, and Brian Ketelsen - - Erik St. Martin, Carlisia Pinto, and Brian Ketelsen - + Erik St. Martin, Carlisia Pinto, and Brian Ketelsen \ No newline at end of file diff --git a/test/xml/RSS-RDF.xml b/test/xml/RSS-RDF.xml new file mode 100644 index 0000000..63a5d03 --- /dev/null +++ b/test/xml/RSS-RDF.xml @@ -0,0 +1,35 @@ + + + + Mozilla Dot Org + http://www.mozilla.org + the Mozilla Organization web site + + + Mozilla + http://www.mozilla.org/images/moz.gif + http://www.mozilla.org + + + New Status Updates + http://www.mozilla.org/status/ + + + Bugzilla Reorganized + http://www.mozilla.org/bugs/ + + + Mozilla Party, 2.0! + http://www.mozilla.org/party/1999/ + + + Unix Platform Parity + http://www.mozilla.org/build/unix.html + + + NPL 1.0M published + http://www.mozilla.org/NPL/NPL-1.0M.html + + \ No newline at end of file diff --git a/test/xml/RSS-Syndication.xml b/test/xml/RSS-Syndication.xml new file mode 100644 index 0000000..2fcd356 --- /dev/null +++ b/test/xml/RSS-Syndication.xml @@ -0,0 +1,24 @@ + + + + Meerkat + http://meerkat.oreillynet.com + Meerkat: An Open Wire Service + hourly + 2 + 2001-01-01T12:01+00:00 + + + + Meerkat Powered! + http://meerkat.oreillynet.com/icons/meerkat-powered.jpg + http://meerkat.oreillynet.com + + + XML: A Disruptive Technology + http://c.moreover.com/click/here.pl?r123 + XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet. + +