diff --git a/.gitignore b/.gitignore index e284d7a..0a4e5a3 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ doc/api/ .idea .dart_tool + +.vscode/ \ No newline at end of file diff --git a/example/main.dart b/example/main.dart index 7a4500c..5ec2b7f 100644 --- a/example/main.dart +++ b/example/main.dart @@ -1,17 +1,22 @@ -import 'package:http/http.dart' as http; +import 'dart:io'; + +import 'package:http/io_client.dart'; import 'package:webfeed/webfeed.dart'; void main() async { - var client = http.Client(); + final client = IOClient(HttpClient() + ..badCertificateCallback = + ((X509Certificate cert, String host, int port) => true)); // RSS feed - var response = await client - .get('https://developer.apple.com/news/releases/rss/releases.rss'); + var response = await client.get( + Uri.parse('https://developer.apple.com/news/releases/rss/releases.rss')); var channel = RssFeed.parse(response.body); print(channel); // Atom feed - response = await client.get('https://www.theverge.com/rss/index.xml'); + response = + await client.get(Uri.parse('https://www.theverge.com/rss/index.xml')); var feed = AtomFeed.parse(response.body); print(feed); diff --git a/lib/domain/atom_category.dart b/lib/domain/atom_category.dart index acd5b58..c0825a6 100644 --- a/lib/domain/atom_category.dart +++ b/lib/domain/atom_category.dart @@ -1,9 +1,9 @@ import 'package:xml/xml.dart'; class AtomCategory { - final String term; - final String scheme; - final String label; + final String? term; + final String? scheme; + final String? label; AtomCategory(this.term, this.scheme, this.label); diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 128ed30..f48a3c0 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -4,24 +4,24 @@ import 'package:webfeed/domain/atom_item.dart'; import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; import 'package:webfeed/util/datetime.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class AtomFeed { - final String id; - final String title; - final DateTime updated; - final List items; + final String? id; + final String? title; + final DateTime? updated; + final List? items; - final List links; - final List authors; - final List contributors; - final List categories; - final AtomGenerator generator; - final String icon; - final String logo; - final String rights; - final String subtitle; + final List? links; + final List? authors; + final List? contributors; + final List? categories; + final AtomGenerator? generator; + final String? icon; + final String? logo; + final String? rights; + final String? subtitle; AtomFeed({ this.id, @@ -41,15 +41,16 @@ class AtomFeed { factory AtomFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - var feedElement = findFirstElement(document, 'feed'); + var feedElement = document.findElements('feed').firstOrNull; if (feedElement == null) { throw ArgumentError('feed not found'); } return AtomFeed( - id: findFirstElement(feedElement, 'id')?.text, - title: findFirstElement(feedElement, 'title')?.text, - updated: parseDateTime(findFirstElement(feedElement, 'updated')?.text), + id: feedElement.findElements('id').firstOrNull?.text, + title: feedElement.findElements('title').firstOrNull?.text, + updated: + parseDateTime(feedElement.findElements('updated').firstOrNull?.text), items: feedElement .findElements('entry') .map((e) => AtomItem.parse(e)) @@ -70,12 +71,14 @@ class AtomFeed { .findElements('category') .map((e) => AtomCategory.parse(e)) .toList(), - generator: - 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, + generator: feedElement + .findElements('generator') + .map((e) => AtomGenerator.parse(e)) + .firstOrNull, + icon: feedElement.findElements('icon').firstOrNull?.text, + logo: feedElement.findElements('logo').firstOrNull?.text, + rights: feedElement.findElements('rights').firstOrNull?.text, + subtitle: feedElement.findElements('subtitle').firstOrNull?.text, ); } } diff --git a/lib/domain/atom_generator.dart b/lib/domain/atom_generator.dart index b3a0b5f..63377c0 100644 --- a/lib/domain/atom_generator.dart +++ b/lib/domain/atom_generator.dart @@ -1,16 +1,13 @@ import 'package:xml/xml.dart'; class AtomGenerator { - final String uri; - final String version; - final String value; + final String? uri; + final String? version; + final String? value; AtomGenerator(this.uri, this.version, this.value); factory AtomGenerator.parse(XmlElement element) { - if (element == null) { - return null; - } var uri = element.getAttribute('uri'); var version = element.getAttribute('version'); var value = element.text; diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index a5efa08..ff9681e 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -4,24 +4,24 @@ import 'package:webfeed/domain/atom_person.dart'; import 'package:webfeed/domain/atom_source.dart'; import 'package:webfeed/domain/media/media.dart'; import 'package:webfeed/util/datetime.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class AtomItem { - final String id; - final String title; - final DateTime updated; + final String? id; + final String? title; + final DateTime? updated; - final List authors; - final List links; - final List categories; - final List contributors; - final AtomSource source; - final String published; - final String content; - final String summary; - final String rights; - final Media media; + final List? authors; + final List? links; + final List? categories; + final List? contributors; + final AtomSource? source; + final String? published; + final String? content; + final String? summary; + final String? rights; + final Media? media; AtomItem({ this.id, @@ -41,9 +41,9 @@ class AtomItem { factory AtomItem.parse(XmlElement element) { return AtomItem( - id: findFirstElement(element, 'id')?.text, - title: findFirstElement(element, 'title')?.text, - updated: parseDateTime(findFirstElement(element, 'updated')?.text), + id: element.findElements('id').firstOrNull?.text, + title: element.findElements('title').firstOrNull?.text, + updated: parseDateTime(element.findElements('updated').firstOrNull?.text), authors: element .findElements('author') .map((e) => AtomPerson.parse(e)) @@ -58,11 +58,14 @@ class AtomItem { .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, + source: element + .findElements('source') + .map((e) => AtomSource.parse(e)) + .firstOrNull, + published: element.findElements('published').firstOrNull?.text, + content: element.findElements('content').firstOrNull?.text, + summary: element.findElements('summary').firstOrNull?.text, + rights: element.findElements('rights').firstOrNull?.text, media: Media.parse(element), ); } diff --git a/lib/domain/atom_link.dart b/lib/domain/atom_link.dart index 9b68ac2..2efbe38 100644 --- a/lib/domain/atom_link.dart +++ b/lib/domain/atom_link.dart @@ -1,11 +1,11 @@ import 'package:xml/xml.dart'; class AtomLink { - final String href; - final String rel; - final String type; - final String hreflang; - final String title; + final String? href; + final String? rel; + final String? type; + final String? hreflang; + final String? title; final int length; AtomLink( @@ -25,7 +25,7 @@ class AtomLink { var hreflang = element.getAttribute('hreflang'); var length = 0; if (element.getAttribute('length') != null) { - length = int.parse(element.getAttribute('length')); + length = int.parse(element.getAttribute('length')!); } return AtomLink(href, rel, type, hreflang, title, length); } diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart index 749e7e0..cac9457 100644 --- a/lib/domain/atom_person.dart +++ b/lib/domain/atom_person.dart @@ -1,18 +1,18 @@ -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class AtomPerson { - final String name; - final String uri; - final String email; + final String? name; + final String? uri; + final String? email; AtomPerson({this.name, this.uri, this.email}); factory AtomPerson.parse(XmlElement element) { return AtomPerson( - name: findFirstElement(element, 'name')?.text, - uri: findFirstElement(element, 'uri')?.text, - email: findFirstElement(element, 'email')?.text, + name: element.findElements('name').firstOrNull?.text, + uri: element.findElements('uri').firstOrNull?.text, + email: element.findElements('email').firstOrNull?.text, ); } } diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart index b917f14..f5f5f56 100644 --- a/lib/domain/atom_source.dart +++ b/lib/domain/atom_source.dart @@ -1,10 +1,10 @@ -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class AtomSource { - final String id; - final String title; - final String updated; + final String? id; + final String? title; + final String? updated; AtomSource({ this.id, @@ -13,13 +13,10 @@ class AtomSource { }); factory AtomSource.parse(XmlElement element) { - if (element == null) { - return null; - } return AtomSource( - id: findFirstElement(element, 'id')?.text, - title: findFirstElement(element, 'title')?.text, - updated: findFirstElement(element, 'updated')?.text, + id: element.findElements('id').firstOrNull?.text, + title: element.findElements('title').firstOrNull?.text, + updated: element.findElements('updated').firstOrNull?.text, ); } } diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index d297df5..9cdfaa2 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -1,25 +1,25 @@ import 'package:webfeed/util/datetime.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class DublinCore { - final String title; - final String description; - final String creator; - final String subject; - final String publisher; - final String contributor; - final DateTime date; - final DateTime created; - final DateTime modified; - final String type; - final String format; - final String identifier; - final String source; - final String language; - final String relation; - final String coverage; - final String rights; + final String? title; + final String? description; + final String? creator; + final String? subject; + final String? publisher; + final String? contributor; + final DateTime? date; + final DateTime? created; + final DateTime? modified; + final String? type; + final String? format; + final String? identifier; + final String? source; + final String? language; + final String? relation; + final String? coverage; + final String? rights; DublinCore({ this.title, @@ -42,27 +42,26 @@ class DublinCore { }); factory DublinCore.parse(XmlElement element) { - if (element == null) { - return null; - } return DublinCore( - 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, + title: element.findElements('dc:title').firstOrNull?.text, + description: element.findElements('dc:description').firstOrNull?.text, + creator: element.findElements('dc:creator').firstOrNull?.text, + subject: element.findElements('dc:subject').firstOrNull?.text, + publisher: element.findElements('dc:publisher').firstOrNull?.text, + contributor: element.findElements('dc:contributor').firstOrNull?.text, + date: parseDateTime(element.findElements('dc:date').firstOrNull?.text), + created: + parseDateTime(element.findElements('dc:created').firstOrNull?.text), + modified: + parseDateTime(element.findElements('dc:modified').firstOrNull?.text), + type: element.findElements('dc:type').firstOrNull?.text, + format: element.findElements('dc:format').firstOrNull?.text, + identifier: element.findElements('dc:identifier').firstOrNull?.text, + source: element.findElements('dc:source').firstOrNull?.text, + language: element.findElements('dc:language').firstOrNull?.text, + relation: element.findElements('dc:relation').firstOrNull?.text, + coverage: element.findElements('dc:coverage').firstOrNull?.text, + rights: element.findElements('dc:rights').firstOrNull?.text, ); } } diff --git a/lib/domain/itunes/itunes.dart b/lib/domain/itunes/itunes.dart index 5426f7d..486de06 100644 --- a/lib/domain/itunes/itunes.dart +++ b/lib/domain/itunes/itunes.dart @@ -4,27 +4,28 @@ 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/string.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Itunes { - final String author; - final String summary; - final bool explicit; - final String title; - final String subtitle; - final ItunesOwner owner; - final List keywords; - final ItunesImage image; - final List categories; - final ItunesType type; - final String newFeedUrl; - final bool block; - final bool complete; - final int episode; - final int season; - final Duration duration; - final ItunesEpisodeType episodeType; + final String? author; + final String? summary; + final bool? explicit; + final String? title; + final String? subtitle; + final ItunesOwner? owner; + final List? keywords; + final ItunesImage? image; + final List? categories; + final ItunesType? type; + final String? newFeedUrl; + final bool? block; + final bool? complete; + final int? episode; + final int? season; + final Duration? duration; + final ItunesEpisodeType? episodeType; Itunes({ this.author, @@ -47,38 +48,50 @@ class Itunes { }); 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; + final episodeStr = element.findElements('itunes:episode').firstOrNull?.text; + final seasonStr = element.findElements('itunes:season').firstOrNull?.text; + final durationStr = + element.findElements('itunes:duration').firstOrNull?.text; return Itunes( - author: findFirstElement(element, 'itunes:author')?.text, - summary: findFirstElement(element, 'itunes:summary')?.text, + author: element.findElements('itunes:author').firstOrNull?.text, + summary: element.findElements('itunes:summary').firstOrNull?.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') + title: element.findElements('itunes:title').firstOrNull?.text, + subtitle: element.findElements('itunes:subtitle').firstOrNull?.text, + owner: element + .findElements('itunes:owner') + .map((e) => ItunesOwner.parse(e)) + .firstOrNull, + keywords: element + .findElements('itunes:keywords') + .firstOrNull ?.text - ?.split(',') - ?.map((keyword) => keyword.trim()) - ?.toList() ?? + .split(',') + .map((keyword) => keyword.trim()) + .toList() ?? [], - image: ItunesImage.parse(findFirstElement(element, 'itunes:image')), - categories: findElements(element, 'itunes:category') + image: element + .findElements('itunes:image') + .map((e) => ItunesImage.parse(e)) + .firstOrNull, + categories: element + .findElements('itunes:category') .map((e) => ItunesCategory.parse(e)) .toList(), - type: newItunesType(findFirstElement(element, 'itunes:type')), - newFeedUrl: findFirstElement(element, 'itunes:new-feed-url')?.text, + type: element + .findElements('itunes:type') + .map((e) => newItunesType(e)) + .firstOrNull, + newFeedUrl: element.findElements('itunes:new-feed-url').firstOrNull?.text, block: parseBoolLiteral(element, 'itunes:block'), complete: parseBoolLiteral(element, 'itunes:complete'), - episode: isNullOrEmpty(episodeStr) ? null : int.parse(episodeStr), - season: isNullOrEmpty(seasonStr) ? null : int.parse(seasonStr), + episode: isNullOrEmpty(episodeStr) ? null : int.tryParse(episodeStr), + season: isNullOrEmpty(seasonStr) ? null : int.tryParse(seasonStr), duration: isNullOrEmpty(durationStr) ? null : _parseDuration(durationStr), - episodeType: - newItunesEpisodeType(findFirstElement(element, 'itunes:episodeType')), + episodeType: element + .findElements('itunes:episodeType') + .map((e) => newItunesEpisodeType(e)) + .firstOrNull, ); } @@ -88,12 +101,12 @@ class Itunes { var seconds = 0; var parts = s.split(':'); if (parts.length > 2) { - hours = int.parse(parts[parts.length - 3]); + hours = int.tryParse(parts[parts.length - 3]) ?? 0; } if (parts.length > 1) { - minutes = int.parse(parts[parts.length - 2]); + minutes = int.tryParse(parts[parts.length - 2]) ?? 0; } - seconds = int.parse(parts[parts.length - 1]); + seconds = int.tryParse(parts[parts.length - 1]) ?? 0; return Duration( hours: hours, minutes: minutes, diff --git a/lib/domain/itunes/itunes_category.dart b/lib/domain/itunes/itunes_category.dart index 2bfc792..8b7b4be 100644 --- a/lib/domain/itunes/itunes_category.dart +++ b/lib/domain/itunes/itunes_category.dart @@ -1,20 +1,17 @@ import 'package:xml/xml.dart'; class ItunesCategory { - final String category; - final List subCategories; + final String? category; + final List? subCategories; ItunesCategory({this.category, this.subCategories}); factory ItunesCategory.parse(XmlElement element) { - if (element == null) return null; return ItunesCategory( - category: element.getAttribute('text')?.trim(), - subCategories: element - .findElements('itunes:category') - ?.map((e) => e.getAttribute('text')?.trim()) - ?.toList() ?? - [], - ); + category: element.getAttribute('text')?.trim(), + subCategories: element + .findElements('itunes:category') + .map((e) => e.getAttribute('text')?.trim() ?? '') + .toList()); } } diff --git a/lib/domain/itunes/itunes_episode_type.dart b/lib/domain/itunes/itunes_episode_type.dart index fc84b39..31e2ad9 100644 --- a/lib/domain/itunes/itunes_episode_type.dart +++ b/lib/domain/itunes/itunes_episode_type.dart @@ -3,7 +3,7 @@ import 'package:xml/xml.dart'; enum ItunesEpisodeType { full, trailer, bonus, unknown } ItunesEpisodeType newItunesEpisodeType(XmlElement element) { - switch (element?.text) { + switch (element.text) { case 'full': return ItunesEpisodeType.full; case 'trailer': diff --git a/lib/domain/itunes/itunes_image.dart b/lib/domain/itunes/itunes_image.dart index 4ae61ca..065c098 100644 --- a/lib/domain/itunes/itunes_image.dart +++ b/lib/domain/itunes/itunes_image.dart @@ -1,12 +1,11 @@ import 'package:xml/xml.dart'; class ItunesImage { - final String href; + final String? href; ItunesImage({this.href}); factory ItunesImage.parse(XmlElement element) { - if (element == null) return null; return ItunesImage( href: element.getAttribute('href')?.trim(), ); diff --git a/lib/domain/itunes/itunes_owner.dart b/lib/domain/itunes/itunes_owner.dart index 2aa3f3a..0a40578 100644 --- a/lib/domain/itunes/itunes_owner.dart +++ b/lib/domain/itunes/itunes_owner.dart @@ -1,17 +1,16 @@ -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class ItunesOwner { - final String name; - final String email; + 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(), + name: element.findElements('itunes:name').firstOrNull?.text.trim(), + email: element.findElements('itunes:email').firstOrNull?.text.trim(), ); } } diff --git a/lib/domain/itunes/itunes_type.dart b/lib/domain/itunes/itunes_type.dart index b32f6bd..741b3e6 100644 --- a/lib/domain/itunes/itunes_type.dart +++ b/lib/domain/itunes/itunes_type.dart @@ -3,7 +3,7 @@ import 'package:xml/xml.dart'; enum ItunesType { episodic, serial, unknown } ItunesType newItunesType(XmlElement element) { - switch (element?.text) { + switch (element.text) { case 'episodic': return ItunesType.episodic; case 'serial': diff --git a/lib/domain/media/category.dart b/lib/domain/media/category.dart index 967e0a2..70b3d9a 100644 --- a/lib/domain/media/category.dart +++ b/lib/domain/media/category.dart @@ -1,9 +1,9 @@ import 'package:xml/xml.dart'; class Category { - final String scheme; - final String label; - final String value; + final String? scheme; + final String? label; + final String? value; Category({ this.scheme, @@ -12,9 +12,6 @@ class Category { }); factory Category.parse(XmlElement element) { - if (element == null) { - return null; - } return Category( scheme: element.getAttribute('scheme'), label: element.getAttribute('label'), diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index a29ed1e..9c49c22 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -1,13 +1,13 @@ import 'package:webfeed/domain/media/star_rating.dart'; import 'package:webfeed/domain/media/statistics.dart'; import 'package:webfeed/domain/media/tags.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class Community { - final StarRating starRating; - final Statistics statistics; - final Tags tags; + final StarRating? starRating; + final Statistics? statistics; + final Tags? tags; Community({ this.starRating, @@ -16,19 +16,19 @@ class Community { }); factory Community.parse(XmlElement element) { - if (element == null) { - return null; - } return Community( - starRating: StarRating.parse( - findFirstElement(element, 'media:starRating'), - ), - statistics: Statistics.parse( - findFirstElement(element, 'media:statistics'), - ), - tags: Tags.parse( - findFirstElement(element, 'media:tags'), - ), + starRating: element + .findElements('media:starRating') + .map((e) => StarRating.parse(e)) + .firstOrNull, + statistics: element + .findElements('media:statistics') + .map((e) => Statistics.parse(e)) + .firstOrNull, + tags: element + .findElements('media:tags') + .map((e) => Tags.parse(e)) + .firstOrNull, ); } } diff --git a/lib/domain/media/content.dart b/lib/domain/media/content.dart index 061119c..e7dc0c4 100644 --- a/lib/domain/media/content.dart +++ b/lib/domain/media/content.dart @@ -1,20 +1,20 @@ import 'package:xml/xml.dart'; class Content { - final String url; - final String type; - final int fileSize; - final String medium; - final bool isDefault; - final String expression; - final int bitrate; - final double framerate; - final double samplingrate; - final int channels; - final int duration; - final int height; - final int width; - final String lang; + final String? url; + final String? type; + final int? fileSize; + final String? medium; + final bool? isDefault; + final String? expression; + final int? bitrate; + final double? framerate; + final double? samplingrate; + final int? channels; + final int? duration; + final int? height; + final int? width; + final String? lang; Content({ this.url, diff --git a/lib/domain/media/copyright.dart b/lib/domain/media/copyright.dart index e40c4c7..e1ec675 100644 --- a/lib/domain/media/copyright.dart +++ b/lib/domain/media/copyright.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Copyright { - final String url; - final String value; + final String? url; + final String? value; Copyright({ this.url, @@ -10,9 +10,6 @@ class Copyright { }); factory Copyright.parse(XmlElement element) { - if (element == null) { - return null; - } return Copyright( url: element.getAttribute('url'), value: element.text, diff --git a/lib/domain/media/credit.dart b/lib/domain/media/credit.dart index 3f0838b..4fc8e9e 100644 --- a/lib/domain/media/credit.dart +++ b/lib/domain/media/credit.dart @@ -1,9 +1,9 @@ import 'package:xml/xml.dart'; class Credit { - final String role; - final String scheme; - final String value; + final String? role; + final String? scheme; + final String? value; Credit({ this.role, diff --git a/lib/domain/media/description.dart b/lib/domain/media/description.dart index 29866d0..2e0aa82 100644 --- a/lib/domain/media/description.dart +++ b/lib/domain/media/description.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Description { - final String type; - final String value; + final String? type; + final String? value; Description({ this.type, @@ -10,9 +10,6 @@ class Description { }); factory Description.parse(XmlElement element) { - if (element == null) { - return null; - } return Description( type: element.getAttribute('type'), value: element.text, diff --git a/lib/domain/media/embed.dart b/lib/domain/media/embed.dart index 81555be..60d0b23 100644 --- a/lib/domain/media/embed.dart +++ b/lib/domain/media/embed.dart @@ -2,10 +2,10 @@ import 'package:webfeed/domain/media/param.dart'; import 'package:xml/xml.dart'; class Embed { - final String url; - final int width; - final int height; - final List params; + final String? url; + final int? width; + final int? height; + final List? params; Embed({ this.url, @@ -15,16 +15,14 @@ class Embed { }); factory Embed.parse(XmlElement element) { - if (element == null) { - return null; - } 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(), + params: element + .findElements('media:param') + .map((e) => Param.parse(e)) + .toList(), ); } } diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 8f82f7b..fddecef 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -2,14 +2,14 @@ import 'package:webfeed/domain/media/category.dart'; import 'package:webfeed/domain/media/content.dart'; import 'package:webfeed/domain/media/credit.dart'; import 'package:webfeed/domain/media/rating.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class Group { - final List contents; - final List credits; - final Category category; - final Rating rating; + final List? contents; + final List? credits; + final Category? category; + final Rating? rating; Group({ this.contents, @@ -19,22 +19,23 @@ class Group { }); factory Group.parse(XmlElement element) { - if (element == null) { - return null; - } return Group( - contents: element.findElements('media:content').map((e) { - return Content.parse(e); - }).toList(), - credits: element.findElements('media:credit').map((e) { - return Credit.parse(e); - }).toList(), - category: Category.parse( - findFirstElement(element, 'media:category'), - ), - rating: Rating.parse( - findFirstElement(element, 'media:rating'), - ), + contents: element + .findElements('media:content') + .map((e) => Content.parse(e)) + .toList(), + credits: element + .findElements('media:credit') + .map((e) => Credit.parse(e)) + .toList(), + category: element + .findElements('media:category') + .map((e) => Category.parse(e)) + .firstOrNull, + rating: element + .findElements('media:rating') + .map((e) => Rating.parse(e)) + .firstOrNull, ); } } diff --git a/lib/domain/media/hash.dart b/lib/domain/media/hash.dart index bfcbd72..7387e22 100644 --- a/lib/domain/media/hash.dart +++ b/lib/domain/media/hash.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Hash { - final String algo; - final String value; + final String? algo; + final String? value; Hash({ this.algo, @@ -10,9 +10,6 @@ class Hash { }); factory Hash.parse(XmlElement element) { - if (element == null) { - return null; - } return Hash( algo: element.getAttribute('algo'), value: element.text, diff --git a/lib/domain/media/license.dart b/lib/domain/media/license.dart index e3990db..18f50f8 100644 --- a/lib/domain/media/license.dart +++ b/lib/domain/media/license.dart @@ -1,9 +1,9 @@ import 'package:xml/xml.dart'; class License { - final String type; - final String href; - final String value; + final String? type; + final String? href; + final String? value; License({ this.type, @@ -12,9 +12,6 @@ class License { }); factory License.parse(XmlElement element) { - if (element == null) { - return null; - } return License( type: element.getAttribute('type'), href: element.getAttribute('href'), diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index 2ee0cba..e95cb48 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -20,34 +20,35 @@ import 'package:webfeed/domain/media/text.dart'; import 'package:webfeed/domain/media/thumbnail.dart'; import 'package:webfeed/domain/media/title.dart'; import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class Media { - final Group group; - final List contents; - final List credits; - final Category category; - final Rating rating; - final Title title; - final Description description; - final String keywords; - final List thumbnails; - final Hash hash; - final Player player; - final Copyright copyright; - final Text text; - final Restriction restriction; - final Community community; - final List comments; - final Embed embed; - final List responses; - final List backLinks; - final Status status; - final List prices; - final License license; - final PeerLink peerLink; - final Rights rights; - final List scenes; + final Group? group; + final List? contents; + final List? credits; + final Category? category; + final Rating? rating; + final Title? title; + final Description? description; + final String? keywords; + final List? thumbnails; + final Hash? hash; + final Player? player; + final Copyright? copyright; + final Text? text; + final Restriction? restriction; + final Community? community; + final List? comments; + final Embed? embed; + final List? responses; + final List? backLinks; + final Status? status; + final List? prices; + final License? license; + final PeerLink? peerLink; + final Rights? rights; + final List? scenes; Media({ this.group, @@ -79,90 +80,113 @@ class Media { factory Media.parse(XmlElement element) { return Media( - group: Group.parse( - findFirstElement(element, 'media:group'), - ), - contents: element.findElements('media:content').map((e) { - return Content.parse(e); - }).toList(), - credits: element.findElements('media:credit').map((e) { - return Credit.parse(e); - }).toList(), - category: Category.parse( - findFirstElement(element, 'media:category'), - ), - rating: Rating.parse( - findFirstElement(element, 'media:rating'), - ), - title: Title.parse( - findFirstElement(element, 'media:title'), - ), - description: Description.parse( - findFirstElement(element, 'media:description'), - ), - keywords: findFirstElement(element, 'media:keywords')?.text, - thumbnails: element.findElements('media:thumbnail').map((e) { - return Thumbnail.parse(e); - }).toList(), - hash: Hash.parse( - findFirstElement(element, 'media:hash'), - ), - player: Player.parse( - findFirstElement(element, 'media:player'), - ), - copyright: Copyright.parse( - findFirstElement(element, 'media:copyright'), - ), - text: Text.parse( - findFirstElement(element, 'media:text'), - ), - restriction: Restriction.parse( - findFirstElement(element, 'media:restriction'), - ), - community: Community.parse( - findFirstElement(element, 'media:community'), - ), - comments: findFirstElement(element, 'media:comments') + group: element + .findElements('media:group') + .map((e) => Group.parse(e)) + .firstOrNull, + contents: element + .findElements('media:content') + .map((e) => Content.parse(e)) + .toList(), + credits: element + .findElements('media:credit') + .map((e) => Credit.parse(e)) + .toList(), + category: element + .findElements('media:category') + .map((e) => Category.parse(e)) + .firstOrNull, + rating: element + .findElements('media:rating') + .map((e) => Rating.parse(e)) + .firstOrNull, + title: findElements(element, 'media:title') + ?.map((e) => Title.parse(e)) + .firstOrNull, + description: element + .findElements('media:description') + .map((e) => Description.parse(e)) + .firstOrNull, + keywords: element.findElements('media:keywords').firstOrNull?.text, + thumbnails: element + .findElements('media:thumbnail') + .map((e) => Thumbnail.parse(e)) + .toList(), + hash: element + .findElements('media:hash') + .map((e) => Hash.parse(e)) + .firstOrNull, + player: element + .findElements('media:player') + .map((e) => Player.parse(e)) + .firstOrNull, + copyright: element + .findElements('media:copyright') + .map((e) => Copyright.parse(e)) + .firstOrNull, + text: element + .findElements('media:text') + .map((e) => Text.parse(e)) + .firstOrNull, + restriction: element + .findElements('media:restriction') + .map((e) => Restriction.parse(e)) + .firstOrNull, + community: element + .findElements('media:community') + .map((e) => Community.parse(e)) + .firstOrNull, + comments: element + .findElements('media:comments') + .firstOrNull ?.findElements('media:comment') - ?.map((e) { - return e.text; - })?.toList() ?? + .map((e) => e.text) + .toList() ?? [], - embed: Embed.parse( - findFirstElement(element, 'media:embed'), - ), - responses: findFirstElement(element, 'media:responses') + embed: element + .findElements('media:embed') + .map((e) => Embed.parse(e)) + .firstOrNull, + responses: element + .findElements('media:responses') + .firstOrNull ?.findElements('media:response') - ?.map((e) { - return e.text; - })?.toList() ?? + .map((e) => e.text) + .toList() ?? [], - backLinks: findFirstElement(element, 'media:backLinks') + backLinks: element + .findElements('media:backLinks') + .firstOrNull ?.findElements('media:backLink') - ?.map((e) { - return e.text; - })?.toList() ?? + .map((e) => e.text) + .toList() ?? [], - status: Status.parse( - findFirstElement(element, 'media:status'), - ), - prices: element.findElements('media:price').map((e) { - return Price.parse(e); - }).toList(), - license: License.parse( - findFirstElement(element, 'media:license'), - ), - peerLink: PeerLink.parse( - findFirstElement(element, 'media:peerLink'), - ), - rights: Rights.parse( - findFirstElement(element, 'media:rights'), - ), - scenes: findFirstElement(element, 'media:scenes') + status: element + .findElements('media:status') + .map((e) => Status.parse(e)) + .firstOrNull, + prices: element + .findElements('media:price') + .map((e) => Price.parse(e)) + .toList(), + license: element + .findElements('media:license') + .map((e) => License.parse(e)) + .firstOrNull, + peerLink: element + .findElements('media:peerLink') + .map((e) => PeerLink.parse(e)) + .firstOrNull, + rights: element + .findElements('media:rights') + .map((e) => Rights.parse(e)) + .firstOrNull, + scenes: element + .findElements('media:scenes') + .firstOrNull ?.findElements('media:scene') - ?.map((e) { - return Scene.parse(e); - })?.toList() ?? + .map((e) => Scene.parse(e)) + .toList() ?? [], ); } diff --git a/lib/domain/media/param.dart b/lib/domain/media/param.dart index ac42675..0e8b969 100644 --- a/lib/domain/media/param.dart +++ b/lib/domain/media/param.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Param { - final String name; - final String value; + final String? name; + final String? value; Param({ this.name, @@ -10,9 +10,6 @@ class Param { }); factory Param.parse(XmlElement element) { - if (element == null) { - return null; - } return Param( name: element.getAttribute('name'), value: element.text, diff --git a/lib/domain/media/peer_link.dart b/lib/domain/media/peer_link.dart index 08a5524..d8bec62 100644 --- a/lib/domain/media/peer_link.dart +++ b/lib/domain/media/peer_link.dart @@ -1,9 +1,9 @@ import 'package:xml/xml.dart'; class PeerLink { - final String type; - final String href; - final String value; + final String? type; + final String? href; + final String? value; PeerLink({ this.type, @@ -12,9 +12,6 @@ class PeerLink { }); factory PeerLink.parse(XmlElement element) { - if (element == null) { - return null; - } return PeerLink( type: element.getAttribute('type'), href: element.getAttribute('href'), diff --git a/lib/domain/media/player.dart b/lib/domain/media/player.dart index 2036445..102c081 100644 --- a/lib/domain/media/player.dart +++ b/lib/domain/media/player.dart @@ -1,10 +1,10 @@ import 'package:xml/xml.dart'; class Player { - final String url; - final int width; - final int height; - final String value; + final String? url; + final int? width; + final int? height; + final String? value; Player({ this.url, @@ -14,9 +14,6 @@ class Player { }); factory Player.parse(XmlElement element) { - if (element == null) { - return null; - } return Player( url: element.getAttribute('url'), width: int.tryParse(element.getAttribute('width') ?? '0'), diff --git a/lib/domain/media/price.dart b/lib/domain/media/price.dart index 4ac9059..80fb60a 100644 --- a/lib/domain/media/price.dart +++ b/lib/domain/media/price.dart @@ -1,10 +1,10 @@ import 'package:xml/xml.dart'; class Price { - final double price; - final String type; - final String info; - final String currency; + final double? price; + final String? type; + final String? info; + final String? currency; Price({ this.price, diff --git a/lib/domain/media/rating.dart b/lib/domain/media/rating.dart index 7924cdd..a9212c1 100644 --- a/lib/domain/media/rating.dart +++ b/lib/domain/media/rating.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Rating { - final String scheme; - final String value; + final String? scheme; + final String? value; Rating({ this.scheme, @@ -10,9 +10,6 @@ class Rating { }); factory Rating.parse(XmlElement element) { - if (element == null) { - return null; - } return Rating( scheme: element.getAttribute('scheme'), value: element.text, diff --git a/lib/domain/media/restriction.dart b/lib/domain/media/restriction.dart index cc896e9..85f7dbf 100644 --- a/lib/domain/media/restriction.dart +++ b/lib/domain/media/restriction.dart @@ -1,9 +1,9 @@ import 'package:xml/xml.dart'; class Restriction { - final String relationship; - final String type; - final String value; + final String? relationship; + final String? type; + final String? value; Restriction({ this.relationship, @@ -12,9 +12,6 @@ class Restriction { }); factory Restriction.parse(XmlElement element) { - if (element == null) { - return null; - } return Restriction( relationship: element.getAttribute('relationship'), type: element.getAttribute('type'), diff --git a/lib/domain/media/rights.dart b/lib/domain/media/rights.dart index 2dfd20b..50b41d5 100644 --- a/lib/domain/media/rights.dart +++ b/lib/domain/media/rights.dart @@ -1,16 +1,13 @@ import 'package:xml/xml.dart'; class Rights { - final String status; + final String? status; Rights({ this.status, }); factory Rights.parse(XmlElement element) { - if (element == null) { - return null; - } return Rights( status: element.getAttribute('status'), ); diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index f327a87..32a9df4 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -1,11 +1,11 @@ -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class Scene { - final String title; - final String description; - final String startTime; - final String endTime; + final String? title; + final String? description; + final String? startTime; + final String? endTime; Scene({ this.title, @@ -15,14 +15,11 @@ class Scene { }); factory Scene.parse(XmlElement element) { - if (element == null) { - return null; - } return Scene( - title: findFirstElement(element, 'sceneTitle')?.text, - description: findFirstElement(element, 'sceneDescription')?.text, - startTime: findFirstElement(element, 'sceneStartTime')?.text, - endTime: findFirstElement(element, 'sceneEndTime')?.text, + title: element.findElements('sceneTitle').firstOrNull?.text, + description: element.findElements('sceneDescription').firstOrNull?.text, + startTime: element.findElements('sceneStartTime').firstOrNull?.text, + endTime: element.findElements('sceneEndTime').firstOrNull?.text, ); } } diff --git a/lib/domain/media/star_rating.dart b/lib/domain/media/star_rating.dart index 9348a5a..f70f7e3 100644 --- a/lib/domain/media/star_rating.dart +++ b/lib/domain/media/star_rating.dart @@ -1,10 +1,10 @@ import 'package:xml/xml.dart'; class StarRating { - final double average; - final int count; - final int min; - final int max; + final double? average; + final int? count; + final int? min; + final int? max; StarRating({ this.average, @@ -13,12 +13,12 @@ class StarRating { this.max, }); - factory StarRating.parse(XmlElement element) { + factory StarRating.parse(XmlElement? element) { 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'), + average: double.tryParse(element?.getAttribute('average') ?? '0'), + count: int.tryParse(element?.getAttribute('count') ?? '0'), + min: int.tryParse(element?.getAttribute('min') ?? '0'), + max: int.tryParse(element?.getAttribute('max') ?? '0'), ); } } diff --git a/lib/domain/media/statistics.dart b/lib/domain/media/statistics.dart index 01ade1e..2e6f41e 100644 --- a/lib/domain/media/statistics.dart +++ b/lib/domain/media/statistics.dart @@ -1,18 +1,18 @@ import 'package:xml/xml.dart'; class Statistics { - final int views; - final int favorites; + final int? views; + final int? favorites; Statistics({ this.views, this.favorites, }); - factory Statistics.parse(XmlElement element) { + factory Statistics.parse(XmlElement? element) { return Statistics( - views: int.tryParse(element.getAttribute('views') ?? '0'), - favorites: int.tryParse(element.getAttribute('favorites') ?? '0'), + views: int.tryParse(element?.getAttribute('views') ?? '0'), + favorites: int.tryParse(element?.getAttribute('favorites') ?? '0'), ); } } diff --git a/lib/domain/media/status.dart b/lib/domain/media/status.dart index a5f0b15..1875d2e 100644 --- a/lib/domain/media/status.dart +++ b/lib/domain/media/status.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Status { - final String state; - final String reason; + final String? state; + final String? reason; Status({ this.state, @@ -10,9 +10,6 @@ class Status { }); factory Status.parse(XmlElement element) { - if (element == null) { - return null; - } return Status( state: element.getAttribute('state'), reason: element.getAttribute('reason'), diff --git a/lib/domain/media/tags.dart b/lib/domain/media/tags.dart index b3f747d..d52c316 100644 --- a/lib/domain/media/tags.dart +++ b/lib/domain/media/tags.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Tags { - final String tags; - final int weight; + final String? tags; + final int? weight; Tags({ this.tags, @@ -10,9 +10,6 @@ class Tags { }); factory Tags.parse(XmlElement element) { - if (element == null) { - return null; - } return Tags( tags: element.text, weight: int.tryParse(element.getAttribute('weight') ?? '1'), diff --git a/lib/domain/media/text.dart b/lib/domain/media/text.dart index 58e8d21..b91ba67 100644 --- a/lib/domain/media/text.dart +++ b/lib/domain/media/text.dart @@ -1,11 +1,11 @@ import 'package:xml/xml.dart'; class Text { - final String type; - final String lang; - final String start; - final String end; - final String value; + final String? type; + final String? lang; + final String? start; + final String? end; + final String? value; Text({ this.type, @@ -16,9 +16,6 @@ class Text { }); factory Text.parse(XmlElement element) { - if (element == null) { - return null; - } return Text( type: element.getAttribute('type'), lang: element.getAttribute('lang'), diff --git a/lib/domain/media/thumbnail.dart b/lib/domain/media/thumbnail.dart index 85d81e7..9aa5970 100644 --- a/lib/domain/media/thumbnail.dart +++ b/lib/domain/media/thumbnail.dart @@ -1,10 +1,10 @@ import 'package:xml/xml.dart'; class Thumbnail { - final String url; - final String width; - final String height; - final String time; + final String? url; + final String? width; + final String? height; + final String? time; Thumbnail({ this.url, diff --git a/lib/domain/media/title.dart b/lib/domain/media/title.dart index 9968bce..4b523bf 100644 --- a/lib/domain/media/title.dart +++ b/lib/domain/media/title.dart @@ -1,8 +1,8 @@ import 'package:xml/xml.dart'; class Title { - final String type; - final String value; + final String? type; + final String? value; Title({ this.type, @@ -10,9 +10,6 @@ class Title { }); factory Title.parse(XmlElement element) { - if (element == null) { - return null; - } return Title( type: element.getAttribute('type'), value: element.text, diff --git a/lib/domain/rss_category.dart b/lib/domain/rss_category.dart index a3ca7d7..6196776 100644 --- a/lib/domain/rss_category.dart +++ b/lib/domain/rss_category.dart @@ -1,15 +1,12 @@ import 'package:xml/xml.dart'; class RssCategory { - final String domain; + final String? domain; final String value; RssCategory(this.domain, this.value); factory RssCategory.parse(XmlElement element) { - if (element == null) { - return null; - } var domain = element.getAttribute('domain'); var value = element.text; diff --git a/lib/domain/rss_cloud.dart b/lib/domain/rss_cloud.dart index 73f3c32..a51ee79 100644 --- a/lib/domain/rss_cloud.dart +++ b/lib/domain/rss_cloud.dart @@ -1,11 +1,11 @@ import 'package:xml/xml.dart'; class RssCloud { - final String domain; - final String port; - final String path; - final String registerProcedure; - final String protocol; + final String? domain; + final String? port; + final String? path; + final String? registerProcedure; + final String? protocol; RssCloud( this.domain, @@ -16,9 +16,6 @@ class RssCloud { ); factory RssCloud.parse(XmlElement node) { - if (node == null) { - return null; - } var domain = node.getAttribute('domain'); var port = node.getAttribute('port'); var path = node.getAttribute('path'); diff --git a/lib/domain/rss_content.dart b/lib/domain/rss_content.dart index 5dacce1..531c9ed 100644 --- a/lib/domain/rss_content.dart +++ b/lib/domain/rss_content.dart @@ -17,13 +17,10 @@ class RssContent { RssContent(this.value, this.images); factory RssContent.parse(XmlElement element) { - if (element == null) { - return null; - } - final content = element.text; + final dynamic? content = element.text; final images = []; _imagesRegExp.allMatches(content).forEach((match) { - images.add(match.group(1)); + images.add(match.group(1)!); }); return RssContent(content, images); } diff --git a/lib/domain/rss_enclosure.dart b/lib/domain/rss_enclosure.dart index dd303c7..b1fbee6 100644 --- a/lib/domain/rss_enclosure.dart +++ b/lib/domain/rss_enclosure.dart @@ -1,16 +1,13 @@ import 'package:xml/xml.dart'; class RssEnclosure { - final String url; - final String type; - final int length; + final String? url; + final String? type; + final int? length; RssEnclosure(this.url, this.type, this.length); factory RssEnclosure.parse(XmlElement element) { - if (element == null) { - return null; - } var url = element.getAttribute('url'); var type = element.getAttribute('type'); var length = int.tryParse(element.getAttribute('length') ?? '0'); diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index a2e66c2..4408f37 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -7,33 +7,33 @@ import 'package:webfeed/domain/rss_cloud.dart'; import 'package:webfeed/domain/rss_image.dart'; import 'package:webfeed/domain/rss_item.dart'; import 'package:webfeed/domain/syndication/syndication.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class RssFeed { - final String title; - final String author; - final String description; - final String link; - final List items; + final String? title; + final String? author; + final String? description; + final String? link; + final List? items; - final RssImage image; - final RssCloud cloud; - final List categories; - final List skipDays; - final List skipHours; - final String lastBuildDate; - final String language; - final String generator; - final String copyright; - final String docs; - final String managingEditor; - final String rating; - final String webMaster; - final int ttl; - final DublinCore dc; - final Itunes itunes; - final Syndication syndication; + final RssImage? image; + final RssCloud? cloud; + final List? categories; + final List? skipDays; + final List? skipHours; + final String? lastBuildDate; + final String? language; + final String? generator; + final String? copyright; + final String? docs; + final String? managingEditor; + final String? rating; + final String? webMaster; + final int? ttl; + final DublinCore? dc; + final Itunes? itunes; + final Syndication? syndication; RssFeed({ this.title, @@ -62,50 +62,62 @@ class RssFeed { factory RssFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - var rss = findFirstElement(document, 'rss'); - var rdf = findFirstElement(document, 'rdf:RDF'); + var rss = document.findElements('rss').firstOrNull; + var rdf = document.findElements('rdf:RDF').firstOrNull; if (rss == null && rdf == null) { throw ArgumentError('not a rss feed'); } - var channelElement = findFirstElement(rss ?? rdf, 'channel'); + var channelElement = (rss ?? rdf)!.findElements('channel').firstOrNull; if (channelElement == null) { throw ArgumentError('channel not found'); } return RssFeed( - 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) + title: channelElement.findElements('title').firstOrNull?.text, + author: channelElement.findElements('author').firstOrNull?.text, + description: channelElement.findElements('description').firstOrNull?.text, + link: channelElement.findElements('link').firstOrNull?.text, + items: (rdf ?? channelElement) .findElements('item') .map((e) => RssItem.parse(e)) .toList(), - image: RssImage.parse( - findFirstElement(rss != null ? channelElement : rdf, 'image')), - cloud: RssCloud.parse(findFirstElement(channelElement, 'cloud')), + image: (rdf ?? channelElement) + .findElements('image') + .map((e) => RssImage.parse(e)) + .firstOrNull, + cloud: channelElement + .findElements('cloud') + .map((e) => RssCloud.parse(e)) + .firstOrNull, categories: channelElement .findElements('category') .map((e) => RssCategory.parse(e)) .toList(), - skipDays: findFirstElement(channelElement, 'skipDays') + skipDays: channelElement + .findElements('skipDays') + .firstOrNull ?.findAllElements('day') - ?.map((e) => e.text) - ?.toList() ?? + .map((e) => e.text) + .toList() ?? [], - skipHours: findFirstElement(channelElement, 'skipHours') + skipHours: channelElement + .findElements('skipHours') + .firstOrNull ?.findAllElements('hour') - ?.map((e) => int.tryParse(e.text ?? '0')) - ?.toList() ?? + .map((e) => int.tryParse(e.text) ?? 0) + .toList() ?? [], - 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'), + lastBuildDate: + channelElement.findElements('lastBuildDate').firstOrNull?.text, + language: channelElement.findElements('language').firstOrNull?.text, + generator: channelElement.findElements('generator').firstOrNull?.text, + copyright: channelElement.findElements('copyright').firstOrNull?.text, + docs: channelElement.findElements('docs').firstOrNull?.text, + managingEditor: + channelElement.findElements('managingEditor').firstOrNull?.text, + rating: channelElement.findElements('rating').firstOrNull?.text, + webMaster: channelElement.findElements('webMaster').firstOrNull?.text, + ttl: int.tryParse( + channelElement.findElements('ttl').firstOrNull?.text ?? '0'), dc: DublinCore.parse(channelElement), itunes: Itunes.parse(channelElement), syndication: Syndication.parse(channelElement), diff --git a/lib/domain/rss_image.dart b/lib/domain/rss_image.dart index 35e39b3..6e3b1f0 100644 --- a/lib/domain/rss_image.dart +++ b/lib/domain/rss_image.dart @@ -1,21 +1,18 @@ -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class RssImage { - final String title; - final String url; - final String link; + final String? title; + final String? url; + final String? link; RssImage({this.title, this.url, this.link}); factory RssImage.parse(XmlElement element) { - if (element == null) { - return null; - } return RssImage( - title: findFirstElement(element, 'title')?.text, - url: findFirstElement(element, 'url')?.text, - link: findFirstElement(element, 'link')?.text, + title: element.findElements('title').firstOrNull?.text, + url: element.findElements('url').firstOrNull?.text, + link: element.findElements('link').firstOrNull?.text, ); } } diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 15fa909..ef9ff20 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -6,25 +6,25 @@ import 'package:webfeed/domain/rss_content.dart'; import 'package:webfeed/domain/rss_enclosure.dart'; import 'package:webfeed/domain/rss_source.dart'; import 'package:webfeed/util/datetime.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; class RssItem { - final String title; - final String description; - final String link; + final String? title; + final String? description; + final String? link; - final List categories; - final String guid; - final DateTime pubDate; - final String author; - final String comments; - final RssSource source; - final RssContent content; - final Media media; - final RssEnclosure enclosure; - final DublinCore dc; - final Itunes itunes; + final List? categories; + final String? guid; + final DateTime? pubDate; + final String? author; + final String? comments; + final RssSource? source; + final RssContent? content; + final Media? media; + final RssEnclosure? enclosure; + final DublinCore? dc; + final Itunes? itunes; RssItem({ this.title, @@ -45,21 +45,30 @@ class RssItem { factory RssItem.parse(XmlElement element) { return RssItem( - title: findFirstElement(element, 'title')?.text, - description: findFirstElement(element, 'description')?.text, - link: findFirstElement(element, 'link')?.text, + title: element.findElements('title').firstOrNull?.text, + description: element.findElements('description').firstOrNull?.text, + link: element.findElements('link').firstOrNull?.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')), + guid: element.findElements('guid').firstOrNull?.text, + pubDate: parseDateTime(element.findElements('pubDate').firstOrNull?.text), + author: element.findElements('author').firstOrNull?.text, + comments: element.findElements('comments').firstOrNull?.text, + source: element + .findElements('source') + .map((e) => RssSource.parse(e)) + .firstOrNull, + content: element + .findElements('content:encoded') + .map((e) => RssContent.parse(e)) + .firstOrNull, media: Media.parse(element), - enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')), + enclosure: element + .findElements('enclosure') + .map((e) => RssEnclosure.parse(e)) + .firstOrNull, dc: DublinCore.parse(element), itunes: Itunes.parse(element), ); diff --git a/lib/domain/rss_source.dart b/lib/domain/rss_source.dart index 056fe7b..3b94b8a 100644 --- a/lib/domain/rss_source.dart +++ b/lib/domain/rss_source.dart @@ -1,15 +1,12 @@ import 'package:xml/xml.dart'; class RssSource { - final String url; - final String value; + final String? url; + final String? value; RssSource(this.url, this.value); factory RssSource.parse(XmlElement element) { - if (element == null) { - return null; - } var url = element.getAttribute('url'); var value = element.text; diff --git a/lib/domain/syndication/syndication.dart b/lib/domain/syndication/syndication.dart index 4b05e12..8c42f3d 100644 --- a/lib/domain/syndication/syndication.dart +++ b/lib/domain/syndication/syndication.dart @@ -1,13 +1,13 @@ import 'package:webfeed/util/datetime.dart'; -import 'package:webfeed/util/xml.dart'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; enum SyndicationUpdatePeriod { hourly, daily, weekly, monthly, yearly } class Syndication { - final SyndicationUpdatePeriod updatePeriod; - final int updateFrequency; - final DateTime updateBase; + final SyndicationUpdatePeriod? updatePeriod; + final int? updateFrequency; + final DateTime? updateBase; Syndication({ this.updatePeriod, @@ -16,11 +16,8 @@ class Syndication { }); factory Syndication.parse(XmlElement element) { - if (element == null) { - return null; - } SyndicationUpdatePeriod updatePeriod; - switch (findFirstElement(element, 'sy:updatePeriod')?.text) { + switch (element.findElements('sy:updatePeriod').firstOrNull?.text) { case 'hourly': updatePeriod = SyndicationUpdatePeriod.hourly; break; @@ -43,9 +40,9 @@ class Syndication { return Syndication( updatePeriod: updatePeriod, updateFrequency: int.tryParse( - findFirstElement(element, 'sy:updateFrequency')?.text ?? '1'), - updateBase: - parseDateTime(findFirstElement(element, 'sy:updateBase')?.text), + element.findElements('sy:updateFrequency').firstOrNull?.text ?? '1'), + updateBase: parseDateTime( + element.findElements('sy:updateBase').firstOrNull?.text), ); } } diff --git a/lib/util/datetime.dart b/lib/util/datetime.dart index 050d869..6b41fff 100644 --- a/lib/util/datetime.dart +++ b/lib/util/datetime.dart @@ -2,15 +2,15 @@ import 'package:intl/intl.dart'; const rfc822DatePattern = 'EEE, dd MMM yyyy HH:mm:ss Z'; -DateTime parseDateTime(dateString) { +DateTime? parseDateTime(dateString) { if (dateString == null) return null; return _parseRfc822DateTime(dateString) ?? _parseIso8601DateTime(dateString); } -DateTime _parseRfc822DateTime(String dateString) { +DateTime? _parseRfc822DateTime(String dateString) { try { - final length = dateString?.length?.clamp(0, rfc822DatePattern.length); - final trimmedPattern = rfc822DatePattern.substring(0, length); //Some feeds use a shortened RFC 822 date, e.g. 'Tue, 04 Aug 2020' + final num? length = dateString.length.clamp(0, rfc822DatePattern.length); + final trimmedPattern = rfc822DatePattern.substring(0, length as int?); //Some feeds use a shortened RFC 822 date, e.g. 'Tue, 04 Aug 2020' final format = DateFormat(trimmedPattern, 'en_US'); return format.parse(dateString); } on FormatException { @@ -18,7 +18,7 @@ DateTime _parseRfc822DateTime(String dateString) { } } -DateTime _parseIso8601DateTime(dateString) { +DateTime? _parseIso8601DateTime(dateString) { try { return DateTime.parse(dateString); } on FormatException { diff --git a/lib/util/function.dart b/lib/util/function.dart new file mode 100644 index 0000000..e69de29 diff --git a/lib/util/iterable.dart b/lib/util/iterable.dart new file mode 100644 index 0000000..6f98f19 --- /dev/null +++ b/lib/util/iterable.dart @@ -0,0 +1,3 @@ +extension WebFeedIterable on Iterable { + T? get firstOrNull => isEmpty ? null : first; +} diff --git a/lib/util/xml.dart b/lib/util/xml.dart index 460ff93..4f1ad78 100644 --- a/lib/util/xml.dart +++ b/lib/util/xml.dart @@ -1,32 +1,19 @@ import 'dart:core'; +import 'package:webfeed/util/iterable.dart'; import 'package:xml/xml.dart'; -XmlElement findFirstElement( - XmlNode node, +Iterable? findElements( + XmlNode? node, String name, { bool recursive = false, - String namespace, -}) { - try { - return findElements(node, name, recursive: recursive, namespace: namespace) - ?.first; - } on StateError { - return null; - } -} - -Iterable findElements( - XmlNode node, - String name, { - bool recursive = false, - String namespace, + String? namespace, }) { try { if (recursive) { - return node.findAllElements(name, namespace: namespace); + return node?.findAllElements(name, namespace: namespace); } else { - return node.findElements(name, namespace: namespace); + return node?.findElements(name, namespace: namespace); } } on StateError { return null; @@ -34,7 +21,7 @@ Iterable findElements( } bool parseBoolLiteral(XmlElement element, String tagName) { - var v = findFirstElement(element, tagName)?.text?.toLowerCase()?.trim(); + var v = element.findElements(tagName).firstOrNull?.text.toLowerCase().trim(); if (v == null) return false; return ['yes', 'true'].contains(v); } diff --git a/pubspec.yaml b/pubspec.yaml index 78ec0ad..8c58613 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,10 +3,10 @@ version: 0.6.0 description: webfeed is a dart package for parsing RSS and Atom feeds. Media, DublinCore, iTunes, Syndication namespaces are also supported. homepage: https://github.com/witochandra/webfeed environment: - sdk: ">=2.0.0 <3.0.0" + sdk: '>=2.12.0 <3.0.0' dependencies: - xml: "^4.2.0" - intl: "^0.16.0" + xml: "^5.0.2" + intl: "^0.17.0" dev_dependencies: test: ^1.3.0 - http: "^0.11.3+16" + http: "^0.13.0" diff --git a/test/atom_test.dart b/test/atom_test.dart index 1cd24fc..5814efc 100644 --- a/test/atom_test.dart +++ b/test/atom_test.dart @@ -23,65 +23,65 @@ void main() { expect(feed.title, 'Foo bar news'); expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); - expect(feed.links.length, 2); - expect(feed.links.first.rel, 'foo'); - expect(feed.links.first.type, 'text/html'); - expect(feed.links.first.hreflang, 'en'); - expect(feed.links.first.href, 'http://foo.bar.news/'); - expect(feed.links.first.title, 'Foo bar news html'); - expect(feed.links.first.length, 1000); - - expect(feed.authors.length, 2); - expect(feed.authors.first.name, 'Alice'); - expect(feed.authors.first.uri, 'http://foo.bar.news/people/alice'); - expect(feed.authors.first.email, 'alice@foo.bar.news'); - - expect(feed.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.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.generator.uri, 'http://foo.bar.news/generator'); - expect(feed.generator.version, '1.0'); - expect(feed.generator.value, 'Foo bar generator'); + 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.length, 1000); + + expect(feed.authors!.length, 2); + expect(feed.authors!.first.name, 'Alice'); + expect(feed.authors!.first.uri, 'http://foo.bar.news/people/alice'); + expect(feed.authors!.first.email, 'alice@foo.bar.news'); + + expect(feed.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.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.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.items.length, 2); - var item = feed.items.first; + expect(feed.items!.length, 2); + var item = feed.items!.first; expect(item.id, 'foo-bar-entry-id-1'); expect(item.title, 'Foo bar item 1'); expect(item.updated, DateTime.utc(2018, 4, 6, 13, 2, 40)); - expect(item.authors.length, 2); - expect(item.authors.first.name, 'Ellie'); - expect(item.authors.first.uri, 'http://foo.bar.news/people/ellie'); - expect(item.authors.first.email, 'ellie@foo.bar.news'); - - expect(item.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.length, 1000); - - expect(item.categories.length, 2); - expect(item.categories.first.term, 'foo entry category'); - expect(item.categories.first.scheme, 'this-is-foo-entry-scheme'); - expect(item.categories.first.label, 'this is foo entry label'); - - expect(item.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.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.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.length, 1000); + + expect(item.categories!.length, 2); + expect(item.categories!.first.term, 'foo entry category'); + expect(item.categories!.first.scheme, 'this-is-foo-entry-scheme'); + expect(item.categories!.first.label, 'this is foo entry label'); + + expect(item.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'); @@ -96,16 +96,16 @@ void main() { 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; - expect(item.media.group.contents.length, 5); - expect(item.media.group.credits.length, 2); - expect(item.media.group.category.value, 'music/artist name/album/song'); - expect(item.media.group.rating.value, 'nonadult'); + var item = feed.items!.first; + expect(item.media!.group!.contents!.length, 5); + expect(item.media!.group!.credits!.length, 2); + expect(item.media!.group!.category!.value, 'music/artist name/album/song'); + expect(item.media!.group!.rating!.value, 'nonadult'); - expect(item.media.contents.length, 2); - var mediaContent = item.media.contents.first; + expect(item.media!.contents!.length, 2); + var mediaContent = item.media!.contents!.first; expect(mediaContent.url, 'http://www.foo.com/video.mov'); expect(mediaContent.type, 'video/quicktime'); expect(mediaContent.fileSize, 2000); @@ -117,111 +117,111 @@ void main() { expect(mediaContent.samplingrate, 44.1); expect(mediaContent.channels, 2); - expect(item.media.credits.length, 2); - var mediaCredit = item.media.credits.first; + expect(item.media!.credits!.length, 2); + var mediaCredit = item.media!.credits!.first; expect(mediaCredit.role, 'owner1'); expect(mediaCredit.scheme, 'urn:yvs'); expect(mediaCredit.value, 'copyright holder of the entity'); - expect(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'); + 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.value, "The Judy's -- The Moo Song"); + expect(item.media!.title!.type, 'plain'); + expect(item.media!.title!.value, "The Judy's -- The Moo Song"); - expect(item.media.description.type, 'plain'); - expect(item.media.description.value, + 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!.keywords, 'kitty, cat, big dog, yarn, fluffy'); - expect(item.media.thumbnails.length, 2); - var mediaThumbnail = item.media.thumbnails.first; + expect(item.media!.thumbnails!.length, 2); + var mediaThumbnail = item.media!.thumbnails!.first; expect(mediaThumbnail.url, 'http://www.foo.com/keyframe1.jpg'); expect(mediaThumbnail.width, '75'); expect(mediaThumbnail.height, '50'); expect(mediaThumbnail.time, '12:05:01.123'); - expect(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.width, 400); - expect(item.media.player.height, 200); - 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.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.community.starRating.average, 3.5); - expect(item.media.community.starRating.count, 20); - expect(item.media.community.starRating.min, 1); - expect(item.media.community.starRating.max, 10); - expect(item.media.community.statistics.views, 5); - expect(item.media.community.statistics.favorites, 4); - expect(item.media.community.tags.tags, 'news: 5, abc:3'); - expect(item.media.community.tags.weight, 1); - - expect(item.media.comments.length, 2); - 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.width, 512); - expect(item.media.embed.height, 323); - expect(item.media.embed.params.length, 5); - expect(item.media.embed.params.first.name, 'type'); - expect( - item.media.embed.params.first.value, 'application/x-shockwave-flash'); - - expect(item.media.responses.length, 2); - expect(item.media.responses.first, 'http://www.response1.com'); - expect(item.media.responses.last, 'http://www.response2.com'); - - expect(item.media.backLinks.length, 2); - expect(item.media.backLinks.first, 'http://www.backlink1.com'); - expect(item.media.backLinks.last, 'http://www.backlink2.com'); - - expect(item.media.status.state, 'active'); - expect(item.media.status.reason, null); - - expect(item.media.prices.length, 2); - expect(item.media.prices.first.price, 19.99); - expect(item.media.prices.first.type, 'rent'); - expect( - item.media.prices.first.info, 'http://www.dummy.jp/package_info.html'); - expect(item.media.prices.first.currency, 'EUR'); - - expect(item.media.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.rights.status, 'official'); - - expect(item.media.scenes.length, 2); - expect(item.media.scenes.first.title, 'sceneTitle1'); - expect(item.media.scenes.first.description, 'sceneDesc1'); - expect(item.media.scenes.first.startTime, '00:15'); - expect(item.media.scenes.first.endTime, '00:45'); + expect(item.media!.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!.width, 400); + expect(item.media!.player!.height, 200); + 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!.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!.community!.starRating!.average, 3.5); + expect(item.media!.community!.starRating!.count, 20); + expect(item.media!.community!.starRating!.min, 1); + expect(item.media!.community!.starRating!.max, 10); + expect(item.media!.community!.statistics!.views, 5); + expect(item.media!.community!.statistics!.favorites, 4); + expect(item.media!.community!.tags!.tags, 'news: 5, abc:3'); + expect(item.media!.community!.tags!.weight, 1); + + expect(item.media!.comments!.length, 2); + 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!.width, 512); + expect(item.media!.embed!.height, 323); + expect(item.media!.embed!.params!.length, 5); + expect(item.media!.embed!.params!.first.name, 'type'); + expect(item.media!.embed!.params!.first.value, + 'application/x-shockwave-flash'); + + expect(item.media!.responses!.length, 2); + expect(item.media!.responses!.first, 'http://www.response1.com'); + expect(item.media!.responses!.last, 'http://www.response2.com'); + + expect(item.media!.backLinks!.length, 2); + expect(item.media!.backLinks!.first, 'http://www.backlink1.com'); + expect(item.media!.backLinks!.last, 'http://www.backlink2.com'); + + expect(item.media!.status!.state, 'active'); + expect(item.media!.status!.reason, null); + + expect(item.media!.prices!.length, 2); + expect(item.media!.prices!.first.price, 19.99); + expect(item.media!.prices!.first.type, 'rent'); + expect(item.media!.prices!.first.info, + 'http://www.dummy.jp/package_info.html'); + expect(item.media!.prices!.first.currency, 'EUR'); + + expect(item.media!.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!.rights!.status, 'official'); + + expect(item.media!.scenes!.length, 2); + expect(item.media!.scenes!.first.title, 'sceneTitle1'); + expect(item.media!.scenes!.first.description, 'sceneDesc1'); + expect(item.media!.scenes!.first.startTime, '00:15'); + expect(item.media!.scenes!.first.endTime, '00:45'); }); test('parse Atom-Empty.xml', () { @@ -232,25 +232,25 @@ void main() { expect(feed.id, null); expect(feed.title, null); expect(feed.updated, null); - expect(feed.links.length, 0); - expect(feed.authors.length, 0); - expect(feed.contributors.length, 0); - expect(feed.categories.length, 0); + expect(feed.links!.length, 0); + expect(feed.authors!.length, 0); + expect(feed.contributors!.length, 0); + expect(feed.categories!.length, 0); expect(feed.generator, null); expect(feed.icon, null); expect(feed.logo, null); expect(feed.subtitle, null); - expect(feed.items.length, 1); - var item = feed.items.first; + expect(feed.items!.length, 1); + var item = feed.items!.first; - expect(item.authors.length, 0); + expect(item.authors!.length, 0); - expect(item.links.length, 0); + expect(item.links!.length, 0); - expect(item.categories.length, 0); + expect(item.categories!.length, 0); - expect(item.contributors.length, 0); + expect(item.contributors!.length, 0); expect(item.published, null); expect(item.summary, null); diff --git a/test/rss_test.dart b/test/rss_test.dart index f37feee..10087db 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -36,59 +36,59 @@ void main() { expect(feed.webMaster, 'webmaster@foo.bar.news'); expect(feed.ttl, 60); - expect(feed.image.title, 'Foo bar News'); - expect(feed.image.url, 'https://foo.bar.news/logo.gif'); - expect(feed.image.link, 'https://foo.bar.news/'); - - expect(feed.cloud.domain, 'radio.foo.bar.news'); - expect(feed.cloud.port, '80'); - expect(feed.cloud.path, '/RPC2'); - expect(feed.cloud.registerProcedure, 'foo.bar.rssPleaseNotify'); - expect(feed.cloud.protocol, 'xml-rpc'); - - expect(feed.categories.length, 2); - expect(feed.categories[0].domain, null); - expect(feed.categories[0].value, 'Ipsum'); - expect(feed.categories[1].domain, 'news'); - expect(feed.categories[1].value, 'Lorem Ipsum'); - - expect(feed.skipDays.length, 3); - expect(feed.skipDays.contains('Monday'), true); - expect(feed.skipDays.contains('Tuesday'), true); - expect(feed.skipDays.contains('Sunday'), true); - - expect(feed.skipHours.length, 5); - expect(feed.skipHours.contains(0), true); - expect(feed.skipHours.contains(1), true); - expect(feed.skipHours.contains(2), true); - expect(feed.skipHours.contains(3), true); - expect(feed.skipHours.contains(4), true); - - expect(feed.items.length, 2); - - expect(feed.items.first.title, + 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.categories!.length, 2); + expect(feed.categories![0].domain, null); + expect(feed.categories![0].value, 'Ipsum'); + expect(feed.categories![1].domain, 'news'); + expect(feed.categories![1].value, 'Lorem Ipsum'); + + expect(feed.skipDays!.length, 3); + expect(feed.skipDays!.contains('Monday'), true); + expect(feed.skipDays!.contains('Tuesday'), true); + expect(feed.skipDays!.contains('Sunday'), true); + + expect(feed.skipHours!.length, 5); + expect(feed.skipHours!.contains(0), true); + expect(feed.skipHours!.contains(1), true); + expect(feed.skipHours!.contains(2), true); + expect(feed.skipHours!.contains(3), true); + expect(feed.skipHours!.contains(4), true); + + expect(feed.items!.length, 2); + + expect(feed.items!.first.title, '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, + 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.categories!.first.domain, 'news'); + expect(feed.items!.first.categories!.first.value, 'Lorem'); + expect(feed.items!.first.author, 'alice@foo.bar.news'); + expect(feed.items!.first.source!.url, 'https://foo.bar.news/1?source'); + expect(feed.items!.first.source!.value, 'Foo Bar'); + expect(feed.items!.first.comments, 'https://foo.bar.news/1/comments'); + expect(feed.items!.first.enclosure!.url, 'http://www.scripting.com/mp3s/weatherReportSuite.mp3'); - expect(feed.items.first.enclosure.length, 12216320); - expect(feed.items.first.enclosure.type, 'audio/mpeg'); + expect(feed.items!.first.enclosure!.length, 12216320); + expect(feed.items!.first.enclosure!.type, 'audio/mpeg'); - expect(feed.items.first.content.value, + expect(feed.items!.first.content!.value, ' Test content
'); expect( - feed.items.first.content.images.first, 'https://test.com/image_link'); + feed.items!.first.content!.images.first, 'https://test.com/image_link'); }); test('parse RSS-Media.xml', () { var xmlString = File('test/xml/RSS-Media.xml').readAsStringSync(); @@ -98,21 +98,21 @@ void main() { expect( feed.description, 'Media RSS example with new fields added in v1.5.0'); - expect(feed.items.length, 1); + expect(feed.items!.length, 1); - var item = feed.items.first; + var item = feed.items!.first; expect(item.title, null); expect(item.link, 'http://www.foo.com'); expect(item.pubDate, DateTime(2001, 08, 27, 16, 08, 56)); //Mon, 27 Aug 2001 16:08:56 PST - expect(item.media.group.contents.length, 5); - expect(item.media.group.credits.length, 2); - expect(item.media.group.category.value, 'music/artist name/album/song'); - expect(item.media.group.rating.value, 'nonadult'); + expect(item.media!.group!.contents!.length, 5); + expect(item.media!.group!.credits!.length, 2); + expect(item.media!.group!.category!.value, 'music/artist name/album/song'); + expect(item.media!.group!.rating!.value, 'nonadult'); - expect(item.media.contents.length, 2); - var mediaContent = item.media.contents.first; + expect(item.media!.contents!.length, 2); + var mediaContent = item.media!.contents!.first; expect(mediaContent.url, 'http://www.foo.com/video.mov'); expect(mediaContent.type, 'video/quicktime'); expect(mediaContent.fileSize, 2000); @@ -124,152 +124,152 @@ void main() { expect(mediaContent.samplingrate, 44.1); expect(mediaContent.channels, 2); - expect(item.media.credits.length, 2); - var mediaCredit = item.media.credits.first; + expect(item.media!.credits!.length, 2); + var mediaCredit = item.media!.credits!.first; expect(mediaCredit.role, 'owner1'); expect(mediaCredit.scheme, 'urn:yvs'); expect(mediaCredit.value, 'copyright holder of the entity'); - expect(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'); + 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.value, "The Judy's -- The Moo Song"); + expect(item.media!.title!.type, 'plain'); + expect(item.media!.title!.value, "The Judy's -- The Moo Song"); - expect(item.media.description.type, 'plain'); - expect(item.media.description.value, + 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!.keywords, 'kitty, cat, big dog, yarn, fluffy'); - expect(item.media.thumbnails.length, 2); - var mediaThumbnail = item.media.thumbnails.first; + expect(item.media!.thumbnails!.length, 2); + var mediaThumbnail = item.media!.thumbnails!.first; expect(mediaThumbnail.url, 'http://www.foo.com/keyframe1.jpg'); expect(mediaThumbnail.width, '75'); expect(mediaThumbnail.height, '50'); expect(mediaThumbnail.time, '12:05:01.123'); - expect(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.width, 400); - expect(item.media.player.height, 200); - 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.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.community.starRating.average, 3.5); - expect(item.media.community.starRating.count, 20); - expect(item.media.community.starRating.min, 1); - expect(item.media.community.starRating.max, 10); - expect(item.media.community.statistics.views, 5); - expect(item.media.community.statistics.favorites, 4); - expect(item.media.community.tags.tags, 'news: 5, abc:3'); - expect(item.media.community.tags.weight, 1); - - expect(item.media.comments.length, 2); - 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.width, 512); - expect(item.media.embed.height, 323); - expect(item.media.embed.params.length, 5); - expect(item.media.embed.params.first.name, 'type'); - expect( - item.media.embed.params.first.value, 'application/x-shockwave-flash'); - - expect(item.media.responses.length, 2); - expect(item.media.responses.first, 'http://www.response1.com'); - expect(item.media.responses.last, 'http://www.response2.com'); - - expect(item.media.backLinks.length, 2); - expect(item.media.backLinks.first, 'http://www.backlink1.com'); - expect(item.media.backLinks.last, 'http://www.backlink2.com'); - - expect(item.media.status.state, 'active'); - expect(item.media.status.reason, null); - - expect(item.media.prices.length, 2); - expect(item.media.prices.first.price, 19.99); - expect(item.media.prices.first.type, 'rent'); - expect( - item.media.prices.first.info, 'http://www.dummy.jp/package_info.html'); - expect(item.media.prices.first.currency, 'EUR'); - - expect(item.media.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.rights.status, 'official'); - - expect(item.media.scenes.length, 2); - expect(item.media.scenes.first.title, 'sceneTitle1'); - expect(item.media.scenes.first.description, 'sceneDesc1'); - expect(item.media.scenes.first.startTime, '00:15'); - expect(item.media.scenes.first.endTime, '00:45'); + expect(item.media!.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!.width, 400); + expect(item.media!.player!.height, 200); + 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!.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!.community!.starRating!.average, 3.5); + expect(item.media!.community!.starRating!.count, 20); + expect(item.media!.community!.starRating!.min, 1); + expect(item.media!.community!.starRating!.max, 10); + expect(item.media!.community!.statistics!.views, 5); + expect(item.media!.community!.statistics!.favorites, 4); + expect(item.media!.community!.tags!.tags, 'news: 5, abc:3'); + expect(item.media!.community!.tags!.weight, 1); + + expect(item.media!.comments!.length, 2); + 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!.width, 512); + expect(item.media!.embed!.height, 323); + expect(item.media!.embed!.params!.length, 5); + expect(item.media!.embed!.params!.first.name, 'type'); + expect(item.media!.embed!.params!.first.value, + 'application/x-shockwave-flash'); + + expect(item.media!.responses!.length, 2); + expect(item.media!.responses!.first, 'http://www.response1.com'); + expect(item.media!.responses!.last, 'http://www.response2.com'); + + expect(item.media!.backLinks!.length, 2); + expect(item.media!.backLinks!.first, 'http://www.backlink1.com'); + expect(item.media!.backLinks!.last, 'http://www.backlink2.com'); + + expect(item.media!.status!.state, 'active'); + expect(item.media!.status!.reason, null); + + expect(item.media!.prices!.length, 2); + expect(item.media!.prices!.first.price, 19.99); + expect(item.media!.prices!.first.type, 'rent'); + expect(item.media!.prices!.first.info, + 'http://www.dummy.jp/package_info.html'); + expect(item.media!.prices!.first.currency, 'EUR'); + + expect(item.media!.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!.rights!.status, 'official'); + + expect(item.media!.scenes!.length, 2); + expect(item.media!.scenes!.first.title, 'sceneTitle1'); + expect(item.media!.scenes!.first.description, 'sceneDesc1'); + expect(item.media!.scenes!.first.startTime, '00:15'); + expect(item.media!.scenes!.first.endTime, '00:45'); }); test('parse RSS-DC.xml', () { var xmlString = File('test/xml/RSS-DC.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.dc.title, 'title'); - expect(feed.dc.creator, 'creator'); - expect(feed.dc.subject, 'subject'); - expect(feed.dc.description, 'description'); - expect(feed.dc.publisher, 'publisher'); - expect(feed.dc.contributor, 'contributor'); - expect(feed.dc.date, 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'); + 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', () { @@ -294,26 +294,26 @@ void main() { expect(feed.cloud, null); - expect(feed.categories.length, 0); + expect(feed.categories!.length, 0); - expect(feed.skipDays.length, 0); + expect(feed.skipDays!.length, 0); - expect(feed.skipHours.length, 0); + expect(feed.skipHours!.length, 0); - expect(feed.items.length, 1); + expect(feed.items!.length, 1); - expect(feed.items.first.title, null); - expect(feed.items.first.description, null); - expect(feed.items.first.link, null); - expect(feed.items.first.guid, null); - expect(feed.items.first.pubDate, null); - expect(feed.items.first.categories.length, 0); - expect(feed.items.first.author, null); - expect(feed.items.first.source, null); - expect(feed.items.first.comments, null); - expect(feed.items.first.enclosure, null); + expect(feed.items!.first.title, null); + expect(feed.items!.first.description, null); + expect(feed.items!.first.link, null); + expect(feed.items!.first.guid, null); + expect(feed.items!.first.pubDate, null); + expect(feed.items!.first.categories!.length, 0); + expect(feed.items!.first.author, null); + expect(feed.items!.first.source, null); + expect(feed.items!.first.comments, null); + expect(feed.items!.first.enclosure, null); - expect(feed.items.first.content, null); + expect(feed.items!.first.content, null); }); test('parse RSS-Itunes.xml', () { @@ -321,22 +321,22 @@ void main() { var feed = RssFeed.parse(xmlString); - expect(feed.itunes.author, 'Changelog Media'); - expect(feed.itunes.summary, 'Foo'); - expect(feed.itunes.explicit, false); - expect(feed.itunes.image.href, + expect(feed.itunes!.author, 'Changelog Media'); + expect(feed.itunes!.summary, 'Foo'); + expect(feed.itunes!.explicit, false); + expect(feed.itunes!.image!.href, 'https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357'); - 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'); + expect(feed.itunes!.owner!.name, 'Changelog Media'); + expect(feed.itunes!.owner!.email, 'editors@changelog.com'); expect( Set.from([ - feed.itunes.categories[0].category, - feed.itunes.categories[1].category + feed.itunes!.categories![0].category, + feed.itunes!.categories![1].category ]), ['Technology', 'Foo']); - for (var category in feed.itunes.categories) { + for (var category in feed.itunes!.categories!) { switch (category.category) { case 'Foo': expect(category.subCategories, ['Bar', 'Baz']); @@ -346,29 +346,29 @@ void main() { break; } } - expect(feed.itunes.title, 'Go Time'); - expect(feed.itunes.type, ItunesType.serial); - expect(feed.itunes.newFeedUrl, 'wubawuba'); - expect(feed.itunes.block, true); - expect(feed.itunes.complete, true); - - var item = feed.items[0]; - expect(item.itunes.episodeType, ItunesEpisodeType.full); - expect(item.itunes.episode, 1); - expect(item.itunes.season, 1); - expect(item.itunes.image.href, + expect(feed.itunes!.title, 'Go Time'); + expect(feed.itunes!.type, ItunesType.serial); + expect(feed.itunes!.newFeedUrl, 'wubawuba'); + expect(feed.itunes!.block, true); + expect(feed.itunes!.complete, true); + + var item = feed.items![0]; + expect(item.itunes!.episodeType, ItunesEpisodeType.full); + expect(item.itunes!.episode, 1); + expect(item.itunes!.season, 1); + expect(item.itunes!.image!.href, 'https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357'); - expect(item.itunes.duration, Duration(minutes: 32, seconds: 30)); - expect(item.itunes.explicit, false); - expect(item.itunes.keywords, + expect(item.itunes!.duration, Duration(minutes: 32, seconds: 30)); + expect(item.itunes!.explicit, false); + expect(item.itunes!.keywords, 'go,golang,open source,software,development'.split(',')); - expect(item.itunes.subtitle, 'with Erik, Carlisia, and Brian'); - expect(item.itunes.summary, 'Foo'); - expect(item.itunes.author, + expect(item.itunes!.subtitle, 'with Erik, Carlisia, and Brian'); + expect(item.itunes!.summary, 'Foo'); + expect(item.itunes!.author, 'Erik St. Martin, Carlisia Pinto, and Brian Ketelsen'); - expect(item.itunes.explicit, false); - expect(item.itunes.title, 'awesome title'); - expect(item.itunes.block, false); + expect(item.itunes!.explicit, false); + expect(item.itunes!.title, 'awesome title'); + expect(item.itunes!.block, false); }); test('parse RSS-Itunes_item_empty_field.xml with empty duration field', () { @@ -391,12 +391,12 @@ void main() { 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/'); + 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', () { @@ -407,17 +407,17 @@ void main() { 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, + 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, + 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'); + expect(feed.items!.first.link, 'http://c.moreover.com/click/here.pl?r123'); }); }