| @@ -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 | |||||
| @@ -1,10 +1,27 @@ | |||||
| # Changelog | # 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) | ## [0.4.2](https://pub.dartlang.org/packages/webfeed/versions/0.4.2) | ||||
| ### Fixed | ### Fixed | ||||
| - Bad import in `rss_content.dart` & `rss_source.dart` | - Bad import in `rss_content.dart` & `rss_source.dart` | ||||
| ## [0.4.1](https://pub.dartlang.org/packages/webfeed/versions/0.4.1) | ## [0.4.1](https://pub.dartlang.org/packages/webfeed/versions/0.4.1) | ||||
| ### Added | ### Added | ||||
| - Support `author` in RssFeed | - Support `author` in RssFeed | ||||
| ## [0.4.0](https://pub.dartlang.org/packages/webfeed/versions/0.4.0) | ## [0.4.0](https://pub.dartlang.org/packages/webfeed/versions/0.4.0) | ||||
| ### Added | ### Added | ||||
| - Support for dublin core namespace | - Support for dublin core namespace | ||||
| @@ -7,17 +7,19 @@ A dart package for parsing RSS and Atom feed. | |||||
| ### Features | ### Features | ||||
| - [x] RSS | |||||
| - [x] RSS (0.9, 1.0, & 2.0) | |||||
| - [x] Atom | - [x] Atom | ||||
| - [x] Namespaces | - [x] Namespaces | ||||
| - [x] Media RSS | - [x] Media RSS | ||||
| - [x] Dublin Core | - [x] Dublin Core | ||||
| - [x] iTunes | |||||
| - [x] Syndication | |||||
| ### Installing | ### Installing | ||||
| Add this line into your `pubspec.yaml` | Add this line into your `pubspec.yaml` | ||||
| ``` | ``` | ||||
| webfeed: ^0.4.2 | |||||
| webfeed: ^0.6.0 | |||||
| ``` | ``` | ||||
| Import the package into your dart code using: | Import the package into your dart code using: | ||||
| @@ -29,8 +31,8 @@ import 'package:webfeed/webfeed.dart'; | |||||
| To parse string into `RssFeed` object use: | 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 | ### Preview | ||||
| @@ -1,7 +1,4 @@ | |||||
| analyzer: | analyzer: | ||||
| language: | |||||
| enablePreviewDart2: true | |||||
| strong-mode: true | |||||
| errors: | errors: | ||||
| unused_import: error | unused_import: error | ||||
| unused_local_variable: error | unused_local_variable: error | ||||
| @@ -35,3 +32,5 @@ linter: | |||||
| - prefer_typing_uninitialized_variables | - prefer_typing_uninitialized_variables | ||||
| - slash_for_doc_comments | - slash_for_doc_comments | ||||
| - type_init_formals | - type_init_formals | ||||
| - unnecessary_new | |||||
| - prefer_single_quotes | |||||
| @@ -1,24 +1,19 @@ | |||||
| import 'package:http/http.dart' as http; | import 'package:http/http.dart' as http; | ||||
| import 'package:webfeed/webfeed.dart'; | import 'package:webfeed/webfeed.dart'; | ||||
| void main() { | |||||
| var client = new http.Client(); | |||||
| void main() async { | |||||
| var client = http.Client(); | |||||
| // RSS feed | // 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 | // 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(); | |||||
| } | } | ||||
| @@ -8,9 +8,9 @@ class AtomCategory { | |||||
| AtomCategory(this.term, this.scheme, this.label); | AtomCategory(this.term, this.scheme, this.label); | ||||
| factory AtomCategory.parse(XmlElement element) { | 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); | return AtomCategory(term, scheme, label); | ||||
| } | } | ||||
| } | } | ||||
| @@ -3,13 +3,14 @@ import 'package:webfeed/domain/atom_generator.dart'; | |||||
| import 'package:webfeed/domain/atom_item.dart'; | import 'package:webfeed/domain/atom_item.dart'; | ||||
| import 'package:webfeed/domain/atom_link.dart'; | import 'package:webfeed/domain/atom_link.dart'; | ||||
| import 'package:webfeed/domain/atom_person.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'; | import 'package:xml/xml.dart'; | ||||
| class AtomFeed { | class AtomFeed { | ||||
| final String id; | final String id; | ||||
| final String title; | final String title; | ||||
| final String updated; | |||||
| final DateTime updated; | |||||
| final List<AtomItem> items; | final List<AtomItem> items; | ||||
| final List<AtomLink> links; | final List<AtomLink> links; | ||||
| @@ -39,39 +40,42 @@ class AtomFeed { | |||||
| }); | }); | ||||
| factory AtomFeed.parse(String xmlString) { | 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( | 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: | 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, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -11,9 +11,9 @@ class AtomGenerator { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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; | var value = element.text; | ||||
| return new AtomGenerator(uri, version, value); | |||||
| return AtomGenerator(uri, version, value); | |||||
| } | } | ||||
| } | } | ||||
| @@ -3,13 +3,14 @@ import 'package:webfeed/domain/atom_link.dart'; | |||||
| import 'package:webfeed/domain/atom_person.dart'; | import 'package:webfeed/domain/atom_person.dart'; | ||||
| import 'package:webfeed/domain/atom_source.dart'; | import 'package:webfeed/domain/atom_source.dart'; | ||||
| import 'package:webfeed/domain/media/media.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'; | import 'package:xml/xml.dart'; | ||||
| class AtomItem { | class AtomItem { | ||||
| final String id; | final String id; | ||||
| final String title; | final String title; | ||||
| final String updated; | |||||
| final DateTime updated; | |||||
| final List<AtomPerson> authors; | final List<AtomPerson> authors; | ||||
| final List<AtomLink> links; | final List<AtomLink> links; | ||||
| @@ -40,26 +41,28 @@ class AtomItem { | |||||
| factory AtomItem.parse(XmlElement element) { | factory AtomItem.parse(XmlElement element) { | ||||
| return AtomItem( | 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), | media: Media.parse(element), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -18,14 +18,14 @@ class AtomLink { | |||||
| ); | ); | ||||
| factory AtomLink.parse(XmlElement element) { | 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; | 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); | return AtomLink(href, rel, type, hreflang, title, length); | ||||
| } | } | ||||
| @@ -1,4 +1,4 @@ | |||||
| import 'package:webfeed/util/helpers.dart'; | |||||
| import 'package:webfeed/util/xml.dart'; | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| class AtomPerson { | class AtomPerson { | ||||
| @@ -6,12 +6,13 @@ class AtomPerson { | |||||
| final String uri; | final String uri; | ||||
| final String email; | final String email; | ||||
| AtomPerson(this.name, this.uri, this.email); | |||||
| AtomPerson({this.name, this.uri, this.email}); | |||||
| factory AtomPerson.parse(XmlElement element) { | 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, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,4 @@ | |||||
| import 'package:webfeed/util/helpers.dart'; | |||||
| import 'package:webfeed/util/xml.dart'; | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| class AtomSource { | class AtomSource { | ||||
| @@ -6,16 +6,20 @@ class AtomSource { | |||||
| final String title; | final String title; | ||||
| final String updated; | final String updated; | ||||
| AtomSource(this.id, this.title, this.updated); | |||||
| AtomSource({ | |||||
| this.id, | |||||
| this.title, | |||||
| this.updated, | |||||
| }); | |||||
| factory AtomSource.parse(XmlElement element) { | factory AtomSource.parse(XmlElement element) { | ||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -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'; | import 'package:xml/xml.dart'; | ||||
| class DublinCore { | class DublinCore { | ||||
| @@ -8,7 +9,9 @@ class DublinCore { | |||||
| final String subject; | final String subject; | ||||
| final String publisher; | final String publisher; | ||||
| final String contributor; | final String contributor; | ||||
| final String date; | |||||
| final DateTime date; | |||||
| final DateTime created; | |||||
| final DateTime modified; | |||||
| final String type; | final String type; | ||||
| final String format; | final String format; | ||||
| final String identifier; | final String identifier; | ||||
| @@ -26,6 +29,8 @@ class DublinCore { | |||||
| this.publisher, | this.publisher, | ||||
| this.contributor, | this.contributor, | ||||
| this.date, | this.date, | ||||
| this.created, | |||||
| this.modified, | |||||
| this.type, | this.type, | ||||
| this.format, | this.format, | ||||
| this.identifier, | this.identifier, | ||||
| @@ -41,21 +46,23 @@ class DublinCore { | |||||
| return null; | return null; | ||||
| } | } | ||||
| return DublinCore( | 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, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -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<String> keywords; | |||||
| final ItunesImage image; | |||||
| final List<ItunesCategory> 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, | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,20 @@ | |||||
| import 'package:xml/xml.dart'; | |||||
| class ItunesCategory { | |||||
| final String category; | |||||
| final List<String> 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() ?? | |||||
| [], | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -15,9 +15,9 @@ class Category { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| import 'package:webfeed/domain/media/star_rating.dart'; | import 'package:webfeed/domain/media/star_rating.dart'; | ||||
| import 'package:webfeed/domain/media/statistics.dart'; | import 'package:webfeed/domain/media/statistics.dart'; | ||||
| import 'package:webfeed/domain/media/tags.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'; | import 'package:xml/xml.dart'; | ||||
| class Community { | class Community { | ||||
| @@ -19,15 +19,15 @@ class Community { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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'), | |||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -34,23 +34,23 @@ class Content { | |||||
| }); | }); | ||||
| factory Content.parse(XmlElement element) { | 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( | 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'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -13,8 +13,8 @@ class Copyright { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Copyright( | |||||
| url: element.getAttribute("url"), | |||||
| return Copyright( | |||||
| url: element.getAttribute('url'), | |||||
| value: element.text, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -12,9 +12,9 @@ class Credit { | |||||
| }); | }); | ||||
| factory Credit.parse(XmlElement element) { | 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -13,8 +13,8 @@ class Description { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Description( | |||||
| type: element.getAttribute("type"), | |||||
| return Description( | |||||
| type: element.getAttribute('type'), | |||||
| value: element.text, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -18,12 +18,12 @@ class Embed { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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(), | }).toList(), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -2,7 +2,7 @@ import 'package:webfeed/domain/media/category.dart'; | |||||
| import 'package:webfeed/domain/media/content.dart'; | import 'package:webfeed/domain/media/content.dart'; | ||||
| import 'package:webfeed/domain/media/credit.dart'; | import 'package:webfeed/domain/media/credit.dart'; | ||||
| import 'package:webfeed/domain/media/rating.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'; | import 'package:xml/xml.dart'; | ||||
| class Group { | class Group { | ||||
| @@ -22,18 +22,18 @@ class Group { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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(), | }).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(), | }).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'), | |||||
| ), | ), | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -13,8 +13,8 @@ class Hash { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Hash( | |||||
| algo: element.getAttribute("algo"), | |||||
| return Hash( | |||||
| algo: element.getAttribute('algo'), | |||||
| value: element.text, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -15,9 +15,9 @@ class License { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -19,7 +19,7 @@ import 'package:webfeed/domain/media/status.dart'; | |||||
| import 'package:webfeed/domain/media/text.dart'; | import 'package:webfeed/domain/media/text.dart'; | ||||
| import 'package:webfeed/domain/media/thumbnail.dart'; | import 'package:webfeed/domain/media/thumbnail.dart'; | ||||
| import 'package:webfeed/domain/media/title.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'; | import 'package:xml/xml.dart'; | ||||
| class Media { | class Media { | ||||
| @@ -78,90 +78,90 @@ class Media { | |||||
| }); | }); | ||||
| factory Media.parse(XmlElement element) { | 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(), | }).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(), | }).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(), | }).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) { | ?.map((e) { | ||||
| return e.text; | return e.text; | ||||
| })?.toList() ?? | })?.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) { | ?.map((e) { | ||||
| return e.text; | return e.text; | ||||
| })?.toList() ?? | })?.toList() ?? | ||||
| [], | [], | ||||
| backLinks: findElementOrNull(element, "media:backLinks") | |||||
| ?.findElements("media:backLink") | |||||
| backLinks: findFirstElement(element, 'media:backLinks') | |||||
| ?.findElements('media:backLink') | |||||
| ?.map((e) { | ?.map((e) { | ||||
| return e.text; | return e.text; | ||||
| })?.toList() ?? | })?.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(), | }).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) { | ?.map((e) { | ||||
| return new Scene.parse(e); | |||||
| return Scene.parse(e); | |||||
| })?.toList() ?? | })?.toList() ?? | ||||
| [], | [], | ||||
| ); | ); | ||||
| @@ -13,8 +13,8 @@ class Param { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Param( | |||||
| name: element.getAttribute("name"), | |||||
| return Param( | |||||
| name: element.getAttribute('name'), | |||||
| value: element.text, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -15,9 +15,9 @@ class PeerLink { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -17,10 +17,10 @@ class Player { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -14,11 +14,11 @@ class Price { | |||||
| }); | }); | ||||
| factory Price.parse(XmlElement element) { | 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'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -13,8 +13,8 @@ class Rating { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Rating( | |||||
| scheme: element.getAttribute("scheme"), | |||||
| return Rating( | |||||
| scheme: element.getAttribute('scheme'), | |||||
| value: element.text, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -15,9 +15,9 @@ class Restriction { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -11,8 +11,8 @@ class Rights { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Rights( | |||||
| status: element.getAttribute("status"), | |||||
| return Rights( | |||||
| status: element.getAttribute('status'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,4 @@ | |||||
| import 'package:webfeed/util/helpers.dart'; | |||||
| import 'package:webfeed/util/xml.dart'; | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| class Scene { | class Scene { | ||||
| @@ -18,11 +18,11 @@ class Scene { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -14,11 +14,11 @@ class StarRating { | |||||
| }); | }); | ||||
| factory StarRating.parse(XmlElement element) { | 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'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -10,9 +10,9 @@ class Statistics { | |||||
| }); | }); | ||||
| factory Statistics.parse(XmlElement element) { | 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'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -13,9 +13,9 @@ class Status { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Status( | |||||
| state: element.getAttribute("state"), | |||||
| reason: element.getAttribute("reason"), | |||||
| return Status( | |||||
| state: element.getAttribute('state'), | |||||
| reason: element.getAttribute('reason'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -13,9 +13,9 @@ class Tags { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Tags( | |||||
| return Tags( | |||||
| tags: element.text, | tags: element.text, | ||||
| weight: int.tryParse(element.getAttribute("weight") ?? "1"), | |||||
| weight: int.tryParse(element.getAttribute('weight') ?? '1'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -19,11 +19,11 @@ class Text { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -14,11 +14,11 @@ class Thumbnail { | |||||
| }); | }); | ||||
| factory Thumbnail.parse(XmlElement element) { | 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'), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -13,8 +13,8 @@ class Title { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| return new Title( | |||||
| type: element.getAttribute("type"), | |||||
| return Title( | |||||
| type: element.getAttribute('type'), | |||||
| value: element.text, | value: element.text, | ||||
| ); | ); | ||||
| } | } | ||||
| @@ -10,7 +10,7 @@ class RssCategory { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| var domain = element.getAttribute("domain"); | |||||
| var domain = element.getAttribute('domain'); | |||||
| var value = element.text; | var value = element.text; | ||||
| return RssCategory(domain, value); | return RssCategory(domain, value); | ||||
| @@ -19,11 +19,11 @@ class RssCloud { | |||||
| if (node == null) { | if (node == null) { | ||||
| return 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); | return RssCloud(domain, port, path, registerProcedure, protocol); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,6 +1,6 @@ | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| final _imagesRegExp = new RegExp( | |||||
| final _imagesRegExp = RegExp( | |||||
| "<img\\s.*?src=(?:'|\")([^'\">]+)(?:'|\")", | "<img\\s.*?src=(?:'|\")([^'\">]+)(?:'|\")", | ||||
| multiLine: true, | multiLine: true, | ||||
| caseSensitive: false, | caseSensitive: false, | ||||
| @@ -11,9 +11,9 @@ class RssEnclosure { | |||||
| if (element == null) { | if (element == null) { | ||||
| return 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); | return RssEnclosure(url, type, length); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,15 @@ | |||||
| import 'dart:core'; | import 'dart:core'; | ||||
| import 'package:webfeed/domain/dublin_core/dublin_core.dart'; | 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_category.dart'; | ||||
| import 'package:webfeed/domain/rss_cloud.dart'; | import 'package:webfeed/domain/rss_cloud.dart'; | ||||
| import 'package:webfeed/domain/rss_image.dart'; | import 'package:webfeed/domain/rss_image.dart'; | ||||
| import 'package:webfeed/domain/rss_item.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 'package:xml/xml.dart'; | ||||
| import 'rss_itunes.dart'; | |||||
| class RssFeed { | class RssFeed { | ||||
| final String title; | final String title; | ||||
| final String author; | final String author; | ||||
| @@ -32,7 +32,8 @@ class RssFeed { | |||||
| final String webMaster; | final String webMaster; | ||||
| final int ttl; | final int ttl; | ||||
| final DublinCore dc; | final DublinCore dc; | ||||
| final RssItunes itunes; | |||||
| final Itunes itunes; | |||||
| final Syndication syndication; | |||||
| RssFeed({ | RssFeed({ | ||||
| this.title, | this.title, | ||||
| @@ -56,53 +57,58 @@ class RssFeed { | |||||
| this.ttl, | this.ttl, | ||||
| this.dc, | this.dc, | ||||
| this.itunes, | this.itunes, | ||||
| this.syndication, | |||||
| }); | }); | ||||
| factory RssFeed.parse(String xmlString) { | 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( | 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), | dc: DublinCore.parse(channelElement), | ||||
| itunes: RssItunes.parse(channelElement), | |||||
| itunes: Itunes.parse(channelElement), | |||||
| syndication: Syndication.parse(channelElement), | |||||
| ); | ); | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,4 +1,4 @@ | |||||
| import 'package:webfeed/util/helpers.dart'; | |||||
| import 'package:webfeed/util/xml.dart'; | |||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| class RssImage { | class RssImage { | ||||
| @@ -6,16 +6,16 @@ class RssImage { | |||||
| final String url; | final String url; | ||||
| final String link; | final String link; | ||||
| RssImage(this.title, this.url, this.link); | |||||
| RssImage({this.title, this.url, this.link}); | |||||
| factory RssImage.parse(XmlElement element) { | factory RssImage.parse(XmlElement element) { | ||||
| if (element == null) { | if (element == null) { | ||||
| return 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, | |||||
| ); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,15 +1,14 @@ | |||||
| import 'package:intl/intl.dart'; | |||||
| import 'package:webfeed/domain/dublin_core/dublin_core.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/media/media.dart'; | ||||
| import 'package:webfeed/domain/rss_category.dart'; | import 'package:webfeed/domain/rss_category.dart'; | ||||
| import 'package:webfeed/domain/rss_content.dart'; | import 'package:webfeed/domain/rss_content.dart'; | ||||
| import 'package:webfeed/domain/rss_enclosure.dart'; | import 'package:webfeed/domain/rss_enclosure.dart'; | ||||
| import 'package:webfeed/domain/rss_source.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 'package:xml/xml.dart'; | ||||
| import 'rss_item_itunes.dart'; | |||||
| class RssItem { | class RssItem { | ||||
| final String title; | final String title; | ||||
| final String description; | final String description; | ||||
| @@ -25,7 +24,7 @@ class RssItem { | |||||
| final Media media; | final Media media; | ||||
| final RssEnclosure enclosure; | final RssEnclosure enclosure; | ||||
| final DublinCore dc; | final DublinCore dc; | ||||
| final RssItemItunes itunes; | |||||
| final Itunes itunes; | |||||
| RssItem({ | RssItem({ | ||||
| this.title, | this.title, | ||||
| @@ -33,7 +32,7 @@ class RssItem { | |||||
| this.link, | this.link, | ||||
| this.categories, | this.categories, | ||||
| this.guid, | this.guid, | ||||
| String pubDate, | |||||
| this.pubDate, | |||||
| this.author, | this.author, | ||||
| this.comments, | this.comments, | ||||
| this.source, | this.source, | ||||
| @@ -42,33 +41,27 @@ class RssItem { | |||||
| this.enclosure, | this.enclosure, | ||||
| this.dc, | this.dc, | ||||
| this.itunes, | this.itunes, | ||||
| }) | |||||
| : this.pubDate = _parsePubDate(pubDate); | |||||
| }); | |||||
| factory RssItem.parse(XmlElement element) { | factory RssItem.parse(XmlElement element) { | ||||
| return RssItem( | 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), | media: Media.parse(element), | ||||
| enclosure: RssEnclosure.parse(findElementOrNull(element, "enclosure")), | |||||
| enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')), | |||||
| dc: DublinCore.parse(element), | 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); | |||||
| } | |||||
| } | } | ||||
| @@ -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<String> 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, | |||||
| ); | |||||
| } | |||||
| @@ -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<String> keywords; | |||||
| final RssItunesImage image; | |||||
| final List<RssItunesCategory> 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"), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -1,24 +0,0 @@ | |||||
| import 'package:xml/xml.dart'; | |||||
| class RssItunesCategory { | |||||
| final String category; | |||||
| final List<String> subCategories; | |||||
| RssItunesCategory({this.category, this.subCategories}); | |||||
| factory RssItunesCategory.parse(XmlElement element) { | |||||
| if (element == null) return null; | |||||
| Iterable<XmlElement> 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(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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(), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -10,7 +10,7 @@ class RssSource { | |||||
| if (element == null) { | if (element == null) { | ||||
| return null; | return null; | ||||
| } | } | ||||
| var url = element.getAttribute("url"); | |||||
| var url = element.getAttribute('url'); | |||||
| var value = element.text; | var value = element.text; | ||||
| return RssSource(url, value); | return RssSource(url, value); | ||||
| @@ -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), | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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<XmlElement> findAllDirectElementsOrNull(XmlElement element, String name, | |||||
| {String namespace}) { | |||||
| try { | |||||
| return element.findElements(name, namespace: namespace).toList(); | |||||
| } on StateError { | |||||
| return null; | |||||
| } | |||||
| } | |||||
| bool parseBoolLiteral(XmlElement element, String tagName) { | |||||
| var v = findElementOrNull(element, tagName)?.text?.toLowerCase()?.trim(); | |||||
| if (v == null) return null; | |||||
| return ["yes", "true"].contains(v); | |||||
| } | |||||
| @@ -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<XmlElement> 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); | |||||
| } | |||||
| @@ -1,12 +1,11 @@ | |||||
| name: webfeed | 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 <wito.c.91@gmail.com> | |||||
| 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 | homepage: https://github.com/witochandra/webfeed | ||||
| environment: | environment: | ||||
| sdk: ">=2.0.0 <3.0.0" | sdk: ">=2.0.0 <3.0.0" | ||||
| dependencies: | dependencies: | ||||
| xml: "^3.0.0" | |||||
| xml: "^4.2.0" | |||||
| intl: "^0.16.0" | intl: "^0.16.0" | ||||
| dev_dependencies: | dev_dependencies: | ||||
| test: ^1.3.0 | test: ^1.3.0 | ||||
| @@ -5,113 +5,113 @@ import 'package:test/test.dart'; | |||||
| import 'package:webfeed/webfeed.dart'; | import 'package:webfeed/webfeed.dart'; | ||||
| void main() { | 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 { | try { | ||||
| new AtomFeed.parse(xmlString); | |||||
| fail("Should throw Argument Error"); | |||||
| AtomFeed.parse(xmlString); | |||||
| fail('Should throw Argument Error'); | |||||
| } on ArgumentError {} | } 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.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.links.first.length, 1000); | ||||
| expect(feed.authors.length, 2); | 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.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.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); | expect(feed.items.length, 2); | ||||
| var item = feed.items.first; | 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.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.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.links.first.length, 1000); | ||||
| expect(item.categories.length, 2); | 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.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); | expect(feed.items.length, 1); | ||||
| var item = feed.items.first; | var item = feed.items.first; | ||||
| expect(item.media.group.contents.length, 5); | expect(item.media.group.contents.length, 5); | ||||
| expect(item.media.group.credits.length, 2); | 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); | expect(item.media.contents.length, 2); | ||||
| var mediaContent = item.media.contents.first; | 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.fileSize, 2000); | ||||
| expect(mediaContent.medium, "video"); | |||||
| expect(mediaContent.medium, 'video'); | |||||
| expect(mediaContent.isDefault, true); | expect(mediaContent.isDefault, true); | ||||
| expect(mediaContent.expression, "full"); | |||||
| expect(mediaContent.expression, 'full'); | |||||
| expect(mediaContent.bitrate, 128); | expect(mediaContent.bitrate, 128); | ||||
| expect(mediaContent.framerate, 25); | expect(mediaContent.framerate, 25); | ||||
| expect(mediaContent.samplingrate, 44.1); | expect(mediaContent.samplingrate, 44.1); | ||||
| @@ -119,52 +119,54 @@ void main() { | |||||
| expect(item.media.credits.length, 2); | expect(item.media.credits.length, 2); | ||||
| var mediaCredit = item.media.credits.first; | 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.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); | expect(item.media.thumbnails.length, 2); | ||||
| var mediaThumbnail = item.media.thumbnails.first; | var mediaThumbnail = item.media.thumbnails.first; | ||||
| expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); | |||||
| expect(mediaThumbnail.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.width, 400); | ||||
| expect(item.media.player.height, 200); | 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.average, 3.5); | ||||
| expect(item.media.community.starRating.count, 20); | expect(item.media.community.starRating.count, 20); | ||||
| @@ -172,56 +174,58 @@ void main() { | |||||
| expect(item.media.community.starRating.max, 10); | expect(item.media.community.starRating.max, 10); | ||||
| expect(item.media.community.statistics.views, 5); | expect(item.media.community.statistics.views, 5); | ||||
| expect(item.media.community.statistics.favorites, 4); | 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.community.tags.weight, 1); | ||||
| expect(item.media.comments.length, 2); | 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.width, 512); | ||||
| expect(item.media.embed.height, 323); | expect(item.media.embed.height, 323); | ||||
| expect(item.media.embed.params.length, 5); | expect(item.media.embed.params.length, 5); | ||||
| expect(item.media.embed.params.first.name, "type"); | |||||
| expect(item.media.embed.params.first.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.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.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.status.reason, null); | ||||
| expect(item.media.prices.length, 2); | expect(item.media.prices.length, 2); | ||||
| expect(item.media.prices.first.price, 19.99); | expect(item.media.prices.first.price, 19.99); | ||||
| expect(item.media.prices.first.type, "rent"); | |||||
| expect(item.media.prices.first.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.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); | var feed = AtomFeed.parse(xmlString); | ||||
| @@ -2,60 +2,60 @@ import 'dart:core'; | |||||
| import 'dart:io'; | import 'dart:io'; | ||||
| import 'package:test/test.dart'; | 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/webfeed.dart'; | ||||
| import 'package:webfeed/domain/rss_itunes_type.dart'; | |||||
| import 'package:webfeed/domain/rss_itunes_episode_type.dart'; | |||||
| void main() { | void main() { | ||||
| test("parse Invalid.xml", () { | |||||
| var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); | |||||
| test('parse Invalid.xml', () { | |||||
| var xmlString = File('test/xml/Invalid.xml').readAsStringSync(); | |||||
| try { | try { | ||||
| new RssFeed.parse(xmlString); | |||||
| fail("Should throw Argument Error"); | |||||
| RssFeed.parse(xmlString); | |||||
| fail('Should throw Argument Error'); | |||||
| } on ArgumentError {} | } 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, | 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.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.length, 2); | ||||
| expect(feed.categories[0].domain, null); | 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.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.length, 5); | ||||
| expect(feed.skipHours.contains(0), true); | expect(feed.skipHours.contains(0), true); | ||||
| @@ -67,56 +67,58 @@ void main() { | |||||
| expect(feed.items.length, 2); | expect(feed.items.length, 2); | ||||
| expect(feed.items.first.title, | 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, | 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, | 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.length, 12216320); | ||||
| expect(feed.items.first.enclosure.type, "audio/mpeg"); | |||||
| expect(feed.items.first.enclosure.type, 'audio/mpeg'); | |||||
| expect(feed.items.first.content.value, | expect(feed.items.first.content.value, | ||||
| "<img width=\"1000\" height=\"690\" src=\"https://test.com/image_link\"/> Test content<br />"); | |||||
| '<img width="1000" height="690" src="https://test.com/image_link"/> Test content<br />'); | |||||
| expect( | 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( | 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); | expect(feed.items.length, 1); | ||||
| var item = feed.items.first; | var item = feed.items.first; | ||||
| expect(item.title, null); | expect(item.title, null); | ||||
| expect(item.link, "http://www.foo.com"); | |||||
| expect(item.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.contents.length, 5); | ||||
| expect(item.media.group.credits.length, 2); | 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); | expect(item.media.contents.length, 2); | ||||
| var mediaContent = item.media.contents.first; | 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.fileSize, 2000); | ||||
| expect(mediaContent.medium, "video"); | |||||
| expect(mediaContent.medium, 'video'); | |||||
| expect(mediaContent.isDefault, true); | expect(mediaContent.isDefault, true); | ||||
| expect(mediaContent.expression, "full"); | |||||
| expect(mediaContent.expression, 'full'); | |||||
| expect(mediaContent.bitrate, 128); | expect(mediaContent.bitrate, 128); | ||||
| expect(mediaContent.framerate, 25); | expect(mediaContent.framerate, 25); | ||||
| expect(mediaContent.samplingrate, 44.1); | expect(mediaContent.samplingrate, 44.1); | ||||
| @@ -124,54 +126,54 @@ void main() { | |||||
| expect(item.media.credits.length, 2); | expect(item.media.credits.length, 2); | ||||
| var mediaCredit = item.media.credits.first; | 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, | 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.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, | 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); | expect(item.media.thumbnails.length, 2); | ||||
| var mediaThumbnail = item.media.thumbnails.first; | var mediaThumbnail = item.media.thumbnails.first; | ||||
| expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); | |||||
| expect(mediaThumbnail.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.width, 400); | ||||
| expect(item.media.player.height, 200); | 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.average, 3.5); | ||||
| expect(item.media.community.starRating.count, 20); | expect(item.media.community.starRating.count, 20); | ||||
| @@ -179,95 +181,99 @@ void main() { | |||||
| expect(item.media.community.starRating.max, 10); | expect(item.media.community.starRating.max, 10); | ||||
| expect(item.media.community.statistics.views, 5); | expect(item.media.community.statistics.views, 5); | ||||
| expect(item.media.community.statistics.favorites, 4); | 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.community.tags.weight, 1); | ||||
| expect(item.media.comments.length, 2); | 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.width, 512); | ||||
| expect(item.media.embed.height, 323); | expect(item.media.embed.height, 323); | ||||
| expect(item.media.embed.params.length, 5); | expect(item.media.embed.params.length, 5); | ||||
| expect(item.media.embed.params.first.name, "type"); | |||||
| expect(item.media.embed.params.first.name, 'type'); | |||||
| expect( | 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.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.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.status.reason, null); | ||||
| expect(item.media.prices.length, 2); | expect(item.media.prices.length, 2); | ||||
| expect(item.media.prices.first.price, 19.99); | expect(item.media.prices.first.price, 19.99); | ||||
| expect(item.media.prices.first.type, "rent"); | |||||
| expect(item.media.prices.first.type, 'rent'); | |||||
| expect( | 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.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); | 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); | var feed = RssFeed.parse(xmlString); | ||||
| @@ -310,58 +316,96 @@ void main() { | |||||
| expect(feed.items.first.content, null); | 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); | 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.explicit, false); | ||||
| expect(feed.itunes.image.href, | 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, | 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( | expect( | ||||
| Set.from([ | Set.from([ | ||||
| feed.itunes.categories[0].category, | feed.itunes.categories[0].category, | ||||
| feed.itunes.categories[1].category | feed.itunes.categories[1].category | ||||
| ]), | ]), | ||||
| ["Technology", "Foo"]); | |||||
| ['Technology', 'Foo']); | |||||
| for (var category in feed.itunes.categories) { | for (var category in feed.itunes.categories) { | ||||
| switch (category.category) { | switch (category.category) { | ||||
| case "Foo": | |||||
| expect(category.subCategories, ["Bar", "Baz"]); | |||||
| case 'Foo': | |||||
| expect(category.subCategories, ['Bar', 'Baz']); | |||||
| break; | break; | ||||
| case "Technology": | |||||
| expect(category.subCategories, ["Software How-To", "Tech News"]); | |||||
| case 'Technology': | |||||
| expect(category.subCategories, ['Software How-To', 'Tech News']); | |||||
| break; | 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.block, true); | ||||
| expect(feed.itunes.complete, true); | expect(feed.itunes.complete, true); | ||||
| var item = feed.items[0]; | 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.episode, 1); | ||||
| expect(item.itunes.season, 1); | expect(item.itunes.season, 1); | ||||
| expect(item.itunes.image.href, | 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.duration, Duration(minutes: 32, seconds: 30)); | ||||
| expect(item.itunes.explicit, false); | expect(item.itunes.explicit, false); | ||||
| expect(item.itunes.keywords, | 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, | 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.explicit, false); | ||||
| expect(item.itunes.title, "awesome title"); | |||||
| expect(item.itunes.title, 'awesome title'); | |||||
| expect(item.itunes.block, false); | 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'); | |||||
| }); | |||||
| } | } | ||||
| @@ -35,7 +35,7 @@ | |||||
| <entry> | <entry> | ||||
| <id>foo-bar-entry-id-1</id> | <id>foo-bar-entry-id-1</id> | ||||
| <title>Foo bar item 1</title> | <title>Foo bar item 1</title> | ||||
| <updated>2018-04-06T13:02:47Z</updated> | |||||
| <updated>2018-04-06T13:02:40Z</updated> | |||||
| <author> | <author> | ||||
| <name>Ellie</name> | <name>Ellie</name> | ||||
| <uri>http://foo.bar.news/people/ellie</uri> | <uri>http://foo.bar.news/people/ellie</uri> | ||||
| @@ -9,6 +9,8 @@ | |||||
| <dc:publisher>publisher</dc:publisher> | <dc:publisher>publisher</dc:publisher> | ||||
| <dc:contributor>contributor</dc:contributor> | <dc:contributor>contributor</dc:contributor> | ||||
| <dc:date>2000-01-01T12:00+00:00</dc:date> | <dc:date>2000-01-01T12:00+00:00</dc:date> | ||||
| <dc:created>2000-01-01T13:00+00:00</dc:created> | |||||
| <dc:modified>2000-01-01T14:00+00:00</dc:modified> | |||||
| <dc:type>type</dc:type> | <dc:type>type</dc:type> | ||||
| <dc:format>format</dc:format> | <dc:format>format</dc:format> | ||||
| <dc:identifier>identifier</dc:identifier> | <dc:identifier>identifier</dc:identifier> | ||||
| @@ -24,7 +26,9 @@ | |||||
| <dc:description>description</dc:description> | <dc:description>description</dc:description> | ||||
| <dc:publisher>publisher</dc:publisher> | <dc:publisher>publisher</dc:publisher> | ||||
| <dc:contributor>contributor</dc:contributor> | <dc:contributor>contributor</dc:contributor> | ||||
| <dc:date>2000-01-01T12:00+00:00</dc:date> | |||||
| <dc:date>2000-01-02T12:00+00:00</dc:date> | |||||
| <dc:created>2000-01-02T13:00+00:00</dc:created> | |||||
| <dc:modified>2000-01-02T14:00+00:00</dc:modified> | |||||
| <dc:type>type</dc:type> | <dc:type>type</dc:type> | ||||
| <dc:format>format</dc:format> | <dc:format>format</dc:format> | ||||
| <dc:identifier>identifier</dc:identifier> | <dc:identifier>identifier</dc:identifier> | ||||
| @@ -45,12 +45,9 @@ | |||||
| <itunes:keywords>go, golang, open source, software, development</itunes:keywords> | <itunes:keywords>go, golang, open source, software, development</itunes:keywords> | ||||
| <itunes:subtitle>with Erik, Carlisia, and Brian</itunes:subtitle> | <itunes:subtitle>with Erik, Carlisia, and Brian</itunes:subtitle> | ||||
| <itunes:summary>Foo</itunes:summary> | <itunes:summary>Foo</itunes:summary> | ||||
| <dc:creator> | |||||
| Erik St. Martin, Carlisia Pinto, and Brian Ketelsen | |||||
| <dc:creator>Erik St. Martin, Carlisia Pinto, and Brian Ketelsen | |||||
| </dc:creator> | </dc:creator> | ||||
| <itunes:author> | |||||
| Erik St. Martin, Carlisia Pinto, and Brian Ketelsen | |||||
| </itunes:author> | |||||
| <itunes:author>Erik St. Martin, Carlisia Pinto, and Brian Ketelsen</itunes:author> | |||||
| </item> | </item> | ||||
| </channel> | </channel> | ||||
| </rss> | </rss> | ||||
| @@ -0,0 +1,35 @@ | |||||
| <?xml version="1.0"?> | |||||
| <rdf:RDF | |||||
| xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns="http://channel.netscape.com/rdf/simple/0.9/"> | |||||
| <channel> | |||||
| <title>Mozilla Dot Org</title> | |||||
| <link>http://www.mozilla.org</link> | |||||
| <description>the Mozilla Organization web site</description> | |||||
| </channel> | |||||
| <image> | |||||
| <title>Mozilla</title> | |||||
| <url>http://www.mozilla.org/images/moz.gif</url> | |||||
| <link>http://www.mozilla.org</link> | |||||
| </image> | |||||
| <item> | |||||
| <title>New Status Updates</title> | |||||
| <link>http://www.mozilla.org/status/</link> | |||||
| </item> | |||||
| <item> | |||||
| <title>Bugzilla Reorganized</title> | |||||
| <link>http://www.mozilla.org/bugs/</link> | |||||
| </item> | |||||
| <item> | |||||
| <title>Mozilla Party, 2.0!</title> | |||||
| <link>http://www.mozilla.org/party/1999/</link> | |||||
| </item> | |||||
| <item> | |||||
| <title>Unix Platform Parity</title> | |||||
| <link>http://www.mozilla.org/build/unix.html</link> | |||||
| </item> | |||||
| <item> | |||||
| <title>NPL 1.0M published</title> | |||||
| <link>http://www.mozilla.org/NPL/NPL-1.0M.html</link> | |||||
| </item> | |||||
| </rdf:RDF> | |||||
| @@ -0,0 +1,24 @@ | |||||
| <?xml version="1.0" encoding="utf-8"?> | |||||
| <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" | |||||
| xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" | |||||
| xmlns="http://purl.org/rss/1.0/"> | |||||
| <channel rdf:about="http://meerkat.oreillynet.com/?_fl=rss1.0"> | |||||
| <title>Meerkat</title> | |||||
| <link>http://meerkat.oreillynet.com</link> | |||||
| <description>Meerkat: An Open Wire Service</description> | |||||
| <sy:updatePeriod>hourly</sy:updatePeriod> | |||||
| <sy:updateFrequency>2</sy:updateFrequency> | |||||
| <sy:updateBase>2001-01-01T12:01+00:00</sy:updateBase> | |||||
| <image rdf:resource="http://meerkat.oreillynet.com/icons/meerkat-powered.jpg"/> | |||||
| </channel> | |||||
| <image rdf:about="http://meerkat.oreillynet.com/icons/meerkat-powered.jpg"> | |||||
| <title>Meerkat Powered!</title> | |||||
| <url>http://meerkat.oreillynet.com/icons/meerkat-powered.jpg</url> | |||||
| <link>http://meerkat.oreillynet.com</link> | |||||
| </image> | |||||
| <item rdf:about="http://c.moreover.com/click/here.pl?r123"> | |||||
| <title>XML: A Disruptive Technology</title> | |||||
| <link>http://c.moreover.com/click/here.pl?r123</link> | |||||
| <description>XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.</description> | |||||
| </item> | |||||
| </rdf:RDF> | |||||