From 39025c60dcdb748024581ce271247d75ccc8229e Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 00:19:08 +0700 Subject: [PATCH 01/22] rename helpers.dart into xml.dart --- lib/domain/atom_feed.dart | 2 +- lib/domain/atom_item.dart | 2 +- lib/domain/atom_person.dart | 2 +- lib/domain/atom_source.dart | 2 +- lib/domain/dublin_core/dublin_core.dart | 2 +- lib/domain/media/community.dart | 2 +- lib/domain/media/group.dart | 2 +- lib/domain/media/media.dart | 2 +- lib/domain/media/scene.dart | 2 +- lib/domain/rss_feed.dart | 2 +- lib/domain/rss_image.dart | 2 +- lib/domain/rss_item.dart | 8 +++----- lib/domain/rss_item_itunes.dart | 14 ++++++++++---- lib/domain/rss_itunes.dart | 4 +--- lib/domain/rss_itunes_owner.dart | 2 +- lib/util/{helpers.dart => xml.dart} | 0 16 files changed, 26 insertions(+), 24 deletions(-) rename lib/util/{helpers.dart => xml.dart} (100%) diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 92f2cd6..9d8d2c9 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -3,7 +3,7 @@ import 'package:webfeed/domain/atom_generator.dart'; import 'package:webfeed/domain/atom_item.dart'; import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomFeed { diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index 618015b..2badbb0 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -3,7 +3,7 @@ import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; import 'package:webfeed/domain/atom_source.dart'; import 'package:webfeed/domain/media/media.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomItem { diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart index 3eb1e4a..c68fe45 100644 --- a/lib/domain/atom_person.dart +++ b/lib/domain/atom_person.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomPerson { diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart index 37fb619..d632d5a 100644 --- a/lib/domain/atom_source.dart +++ b/lib/domain/atom_source.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomSource { diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index 564bb4c..21b3838 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class DublinCore { diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index b301050..8be70b9 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -1,7 +1,7 @@ import 'package:webfeed/domain/media/star_rating.dart'; import 'package:webfeed/domain/media/statistics.dart'; import 'package:webfeed/domain/media/tags.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Community { diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 1a9a1cb..39e4153 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -2,7 +2,7 @@ import 'package:webfeed/domain/media/category.dart'; import 'package:webfeed/domain/media/content.dart'; import 'package:webfeed/domain/media/credit.dart'; import 'package:webfeed/domain/media/rating.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Group { diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index 2f685c1..39915b3 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -19,7 +19,7 @@ import 'package:webfeed/domain/media/status.dart'; import 'package:webfeed/domain/media/text.dart'; import 'package:webfeed/domain/media/thumbnail.dart'; import 'package:webfeed/domain/media/title.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Media { diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index 9eab8d0..f032e1c 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class Scene { diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 6978ef1..f8ada6e 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -5,7 +5,7 @@ import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_cloud.dart'; import 'package:webfeed/domain/rss_image.dart'; import 'package:webfeed/domain/rss_item.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; import 'rss_itunes.dart'; diff --git a/lib/domain/rss_image.dart b/lib/domain/rss_image.dart index cfc9479..447b628 100644 --- a/lib/domain/rss_image.dart +++ b/lib/domain/rss_image.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class RssImage { diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 783585a..4af2b96 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -4,12 +4,11 @@ import 'package:webfeed/domain/media/media.dart'; import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_content.dart'; import 'package:webfeed/domain/rss_enclosure.dart'; +import 'package:webfeed/domain/rss_item_itunes.dart'; import 'package:webfeed/domain/rss_source.dart'; -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; -import 'rss_item_itunes.dart'; - class RssItem { final String title; final String description; @@ -42,8 +41,7 @@ class RssItem { this.enclosure, this.dc, this.itunes, - }) - : this.pubDate = _parsePubDate(pubDate); + }) : this.pubDate = _parsePubDate(pubDate); factory RssItem.parse(XmlElement element) { return RssItem( diff --git a/lib/domain/rss_item_itunes.dart b/lib/domain/rss_item_itunes.dart index 3d89cc5..19f1c12 100644 --- a/lib/domain/rss_item_itunes.dart +++ b/lib/domain/rss_item_itunes.dart @@ -1,4 +1,4 @@ -import 'package:webfeed/util/helpers.dart'; +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; import 'rss_itunes_category.dart'; @@ -42,19 +42,25 @@ class RssItemItunes { } var episodeStr = findElementOrNull(element, "itunes:episode")?.text?.trim(); var seasonStr = findElementOrNull(element, "itunes:season")?.text?.trim(); - var durationStr = findElementOrNull(element, "itunes:duration")?.text?.trim(); + var durationStr = + findElementOrNull(element, "itunes:duration")?.text?.trim(); return RssItemItunes( title: findElementOrNull(element, "itunes:title")?.text?.trim(), episode: episodeStr == null ? null : int.parse(episodeStr), season: seasonStr == null ? null : int.parse(seasonStr), duration: durationStr == null ? null : parseDuration(durationStr), - episodeType: newRssItunesEpisodeType(findElementOrNull(element, "itunes:episodeType")), + episodeType: newRssItunesEpisodeType( + findElementOrNull(element, "itunes:episodeType")), author: findElementOrNull(element, "itunes:author")?.text?.trim(), summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), explicit: parseBoolLiteral(element, "itunes:explicit"), subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), - keywords: findElementOrNull(element, "itunes:keywords")?.text?.split(",")?.map((keyword) => keyword.trim())?.toList(), + keywords: findElementOrNull(element, "itunes:keywords") + ?.text + ?.split(",") + ?.map((keyword) => keyword.trim()) + ?.toList(), image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), category: RssItunesCategory.parse( findElementOrNull(element, "itunes:category")), diff --git a/lib/domain/rss_itunes.dart b/lib/domain/rss_itunes.dart index c58ad66..e4e7685 100644 --- a/lib/domain/rss_itunes.dart +++ b/lib/domain/rss_itunes.dart @@ -1,7 +1,6 @@ +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; -import 'package:webfeed/util/helpers.dart'; - import 'rss_itunes_category.dart'; import 'rss_itunes_image.dart'; import 'rss_itunes_owner.dart'; @@ -66,4 +65,3 @@ class RssItunes { ); } } - diff --git a/lib/domain/rss_itunes_owner.dart b/lib/domain/rss_itunes_owner.dart index 4bcadc5..2d72294 100644 --- a/lib/domain/rss_itunes_owner.dart +++ b/lib/domain/rss_itunes_owner.dart @@ -1,6 +1,6 @@ import 'package:xml/xml.dart'; -import '../util/helpers.dart'; +import '../util/xml.dart'; class RssItunesOwner { final String name; diff --git a/lib/util/helpers.dart b/lib/util/xml.dart similarity index 100% rename from lib/util/helpers.dart rename to lib/util/xml.dart From 4a096553c1d44b235ec65257c81ee0c039b371a7 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 00:29:02 +0700 Subject: [PATCH 02/22] add datetime.dart --- lib/domain/rss_item.dart | 14 ++++---------- lib/util/datetime.dart | 12 ++++++++++++ 2 files changed, 16 insertions(+), 10 deletions(-) create mode 100644 lib/util/datetime.dart diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 4af2b96..edecd9b 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -1,4 +1,3 @@ -import 'package:intl/intl.dart'; import 'package:webfeed/domain/dublin_core/dublin_core.dart'; import 'package:webfeed/domain/media/media.dart'; import 'package:webfeed/domain/rss_category.dart'; @@ -6,6 +5,7 @@ import 'package:webfeed/domain/rss_content.dart'; import 'package:webfeed/domain/rss_enclosure.dart'; import 'package:webfeed/domain/rss_item_itunes.dart'; import 'package:webfeed/domain/rss_source.dart'; +import 'package:webfeed/util/datetime.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; @@ -32,7 +32,7 @@ class RssItem { this.link, this.categories, this.guid, - String pubDate, + this.pubDate, this.author, this.comments, this.source, @@ -41,7 +41,7 @@ class RssItem { this.enclosure, this.dc, this.itunes, - }) : this.pubDate = _parsePubDate(pubDate); + }); factory RssItem.parse(XmlElement element) { return RssItem( @@ -52,7 +52,7 @@ class RssItem { return RssCategory.parse(element); }).toList(), guid: findElementOrNull(element, "guid")?.text, - pubDate: findElementOrNull(element, "pubDate")?.text, + pubDate: parseDateTime(findElementOrNull(element, "pubDate")?.text), author: findElementOrNull(element, "author")?.text, comments: findElementOrNull(element, "comments")?.text, source: RssSource.parse(findElementOrNull(element, "source")), @@ -63,10 +63,4 @@ class RssItem { itunes: RssItemItunes.parse(element), ); } - - static _parsePubDate(pubDate) { - if (pubDate == null) return null; - //Locale for pubDate is always en_US, regardless of device locale - return DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US').parse(pubDate); - } } diff --git a/lib/util/datetime.dart b/lib/util/datetime.dart new file mode 100644 index 0000000..ef9b289 --- /dev/null +++ b/lib/util/datetime.dart @@ -0,0 +1,12 @@ +import 'package:intl/intl.dart'; + +var rfc822DateFormat = DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US'); + +DateTime parseDateTime(dateString) { + if (dateString == null) return null; + try { + return rfc822DateFormat.parse(dateString); + } on FormatException { + return null; + } +} From edb5fae1178c25fa33f1d0e61b39f69b63faaaf1 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 00:42:49 +0700 Subject: [PATCH 03/22] parse atom date time --- lib/domain/atom_feed.dart | 5 +++-- lib/domain/atom_item.dart | 5 +++-- lib/util/datetime.dart | 12 ++++++++++++ test/atom_test.dart | 26 +++++++++++++++----------- test/xml/Atom.xml | 2 +- 5 files changed, 34 insertions(+), 16 deletions(-) diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 9d8d2c9..1631013 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -3,13 +3,14 @@ import 'package:webfeed/domain/atom_generator.dart'; import 'package:webfeed/domain/atom_item.dart'; import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; +import 'package:webfeed/util/datetime.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomFeed { final String id; final String title; - final String updated; + final DateTime updated; final List items; final List links; @@ -50,7 +51,7 @@ class AtomFeed { return AtomFeed( id: findElementOrNull(feedElement, "id")?.text, title: findElementOrNull(feedElement, "title")?.text, - updated: findElementOrNull(feedElement, "updated")?.text, + updated: parseDateTime(findElementOrNull(feedElement, "updated")?.text), items: feedElement.findElements("entry").map((element) { return AtomItem.parse(element); }).toList(), diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index 2badbb0..f04181f 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -3,13 +3,14 @@ import 'package:webfeed/domain/atom_link.dart'; import 'package:webfeed/domain/atom_person.dart'; import 'package:webfeed/domain/atom_source.dart'; import 'package:webfeed/domain/media/media.dart'; +import 'package:webfeed/util/datetime.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; class AtomItem { final String id; final String title; - final String updated; + final DateTime updated; final List authors; final List links; @@ -42,7 +43,7 @@ class AtomItem { return AtomItem( id: findElementOrNull(element, "id")?.text, title: findElementOrNull(element, "title")?.text, - updated: findElementOrNull(element, "updated")?.text, + updated: parseDateTime(findElementOrNull(element, "updated")?.text), authors: element.findElements("author").map((element) { return AtomPerson.parse(element); }).toList(), diff --git a/lib/util/datetime.dart b/lib/util/datetime.dart index ef9b289..8c79901 100644 --- a/lib/util/datetime.dart +++ b/lib/util/datetime.dart @@ -4,9 +4,21 @@ var rfc822DateFormat = DateFormat('EEE, dd MMM yyyy HH:mm:ss Z', 'en_US'); DateTime parseDateTime(dateString) { if (dateString == null) return null; + return _parseRfc822DateTime(dateString) ?? _parseIso8601DateTime(dateString); +} + +DateTime _parseRfc822DateTime(dateString) { try { return rfc822DateFormat.parse(dateString); } on FormatException { return null; } } + +DateTime _parseIso8601DateTime(dateString) { + try { + return DateTime.parse(dateString); + } on FormatException { + return null; + } +} diff --git a/test/atom_test.dart b/test/atom_test.dart index e7ba377..70b6b0f 100644 --- a/test/atom_test.dart +++ b/test/atom_test.dart @@ -21,7 +21,7 @@ void main() { expect(feed.id, "foo-bar-id"); expect(feed.title, "Foo bar news"); - expect(feed.updated, "2018-04-06T13:02:46Z"); + expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); expect(feed.links.length, 2); expect(feed.links.first.rel, "foo"); @@ -58,7 +58,7 @@ void main() { var item = feed.items.first; expect(item.id, "foo-bar-entry-id-1"); expect(item.title, "Foo bar item 1"); - expect(item.updated, "2018-04-06T13:02:47Z"); + expect(item.updated, DateTime.utc(2018, 4, 6, 13, 2, 40)); expect(item.authors.length, 2); expect(item.authors.first.name, "Ellie"); @@ -88,16 +88,16 @@ void main() { expect(item.content, "This is content 1"); expect(item.rights, "This is rights 1"); }); - test("parse Atom-Media.xml", (){ + test("parse Atom-Media.xml", () { var xmlString = new File("test/xml/Atom-Media.xml").readAsStringSync(); var feed = new AtomFeed.parse(xmlString); expect(feed.id, "foo-bar-id"); expect(feed.title, "Foo bar news"); - expect(feed.updated, "2018-04-06T13:02:46Z"); + expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); expect(feed.items.length, 1); - + var item = feed.items.first; expect(item.media.group.contents.length, 5); expect(item.media.group.credits.length, 2); @@ -123,7 +123,8 @@ void main() { expect(mediaCredit.scheme, "urn:yvs"); expect(mediaCredit.value, "copyright holder of the entity"); - expect(item.media.category.scheme, "http://search.yahoo.com/mrss/category_ schema"); + expect(item.media.category.scheme, + "http://search.yahoo.com/mrss/category_ schema"); expect(item.media.category.label, "Music"); expect(item.media.category.value, "music/artist/album/song"); @@ -134,10 +135,11 @@ void main() { expect(item.media.title.value, "The Judy's -- The Moo Song"); expect(item.media.description.type, "plain"); - expect(item.media.description.value, "This was some really bizarre band I listened to as a young lad."); - + expect(item.media.description.value, + "This was some really bizarre band I listened to as a young lad."); + expect(item.media.keywords, "kitty, cat, big dog, yarn, fluffy"); - + expect(item.media.thumbnails.length, 2); var mediaThumbnail = item.media.thumbnails.first; expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); @@ -184,7 +186,8 @@ void main() { expect(item.media.embed.height, 323); expect(item.media.embed.params.length, 5); expect(item.media.embed.params.first.name, "type"); - expect(item.media.embed.params.first.value, "application/x-shockwave-flash"); + expect( + item.media.embed.params.first.value, "application/x-shockwave-flash"); expect(item.media.responses.length, 2); expect(item.media.responses.first, "http://www.response1.com"); @@ -200,7 +203,8 @@ void main() { 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.info, "http://www.dummy.jp/package_info.html"); expect(item.media.prices.first.currency, "EUR"); expect(item.media.license.type, "text/html"); diff --git a/test/xml/Atom.xml b/test/xml/Atom.xml index e88eb12..02f02bf 100644 --- a/test/xml/Atom.xml +++ b/test/xml/Atom.xml @@ -35,7 +35,7 @@ foo-bar-entry-id-1 Foo bar item 1 - 2018-04-06T13:02:47Z + 2018-04-06T13:02:40Z Ellie http://foo.bar.news/people/ellie From 8ac48d432ba35ef54f9386d6e5d80d7aab561105 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 00:50:23 +0700 Subject: [PATCH 04/22] Create dart.yml integrate with github actions --- .github/workflows/dart.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 .github/workflows/dart.yml diff --git a/.github/workflows/dart.yml b/.github/workflows/dart.yml new file mode 100644 index 0000000..cfd5a3a --- /dev/null +++ b/.github/workflows/dart.yml @@ -0,0 +1,19 @@ +name: Dart CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + +jobs: + build: + runs-on: ubuntu-latest + container: + image: google/dart:latest + steps: + - uses: actions/checkout@v2 + - name: Install dependencies + run: pub get + - name: Run tests + run: pub run test From 1047b1590e1312248f25a593f73df1fa0ae02908 Mon Sep 17 00:00:00 2001 From: Edmon Date: Thu, 20 Feb 2020 13:47:57 -0400 Subject: [PATCH 05/22] Add Created and modified Dublin code attributes --- lib/domain/dublin_core/dublin_core.dart | 6 ++++++ test/rss_test.dart | 2 ++ test/xml/RSS-DC.xml | 2 ++ 3 files changed, 10 insertions(+) diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index 21b3838..d328f8d 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -9,6 +9,8 @@ class DublinCore { final String publisher; final String contributor; final String date; + final String created; + final String modified; final String type; final String format; final String identifier; @@ -26,6 +28,8 @@ class DublinCore { this.publisher, this.contributor, this.date, + this.created, + this.modified, this.type, this.format, this.identifier, @@ -48,6 +52,8 @@ class DublinCore { publisher: findElementOrNull(element, "dc:publisher")?.text, contributor: findElementOrNull(element, "dc:contributor")?.text, date: findElementOrNull(element, "dc:date")?.text, + created: findElementOrNull(element, "dc:created")?.text, + modified: findElementOrNull(element, "dc:modified")?.text, type: findElementOrNull(element, "dc:type")?.text, format: findElementOrNull(element, "dc:format")?.text, identifier: findElementOrNull(element, "dc:identifier")?.text, diff --git a/test/rss_test.dart b/test/rss_test.dart index 60cd46c..8231fa3 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -240,6 +240,8 @@ void main() { expect(feed.dc.publisher, "publisher"); expect(feed.dc.contributor, "contributor"); expect(feed.dc.date, "2000-01-01T12:00+00:00"); + expect(feed.dc.created, "2000-01-01T12:00+00:00"); + expect(feed.dc.modified, "2000-01-01T12:00+00:00"); expect(feed.dc.type, "type"); expect(feed.dc.format, "format"); expect(feed.dc.identifier, "identifier"); diff --git a/test/xml/RSS-DC.xml b/test/xml/RSS-DC.xml index 6f1242d..2e156e2 100644 --- a/test/xml/RSS-DC.xml +++ b/test/xml/RSS-DC.xml @@ -25,6 +25,8 @@ publisher contributor 2000-01-01T12:00+00:00 + 2000-01-01T12:00+00:00 + 2000-01-01T12:00+00:00 type format identifier From 596304b8235044d7e606a04a29351753b685a601 Mon Sep 17 00:00:00 2001 From: Edmon Date: Thu, 20 Feb 2020 13:53:48 -0400 Subject: [PATCH 06/22] bump version --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 85aa596..55f32a9 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: webfeed -version: 0.4.2 +version: 0.4.3 description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. author: Wito Chandra homepage: https://github.com/witochandra/webfeed From 7f82c09e260b3ebcea6a23a97b1f02f47f3c6cdd Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 01:19:04 +0700 Subject: [PATCH 07/22] add DateTime type for dublin core --- lib/domain/dublin_core/dublin_core.dart | 13 +++++++------ pubspec.yaml | 2 +- test/rss_test.dart | 19 ++++++++++--------- test/xml/RSS-DC.xml | 4 ++-- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index d328f8d..53a496c 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -1,3 +1,4 @@ +import 'package:webfeed/util/datetime.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; @@ -8,9 +9,9 @@ class DublinCore { final String subject; final String publisher; final String contributor; - final String date; - final String created; - final String modified; + final DateTime date; + final DateTime created; + final DateTime modified; final String type; final String format; final String identifier; @@ -51,9 +52,9 @@ class DublinCore { subject: findElementOrNull(element, "dc:subject")?.text, publisher: findElementOrNull(element, "dc:publisher")?.text, contributor: findElementOrNull(element, "dc:contributor")?.text, - date: findElementOrNull(element, "dc:date")?.text, - created: findElementOrNull(element, "dc:created")?.text, - modified: findElementOrNull(element, "dc:modified")?.text, + date: parseDateTime(findElementOrNull(element, "dc:date")?.text), + created: parseDateTime(findElementOrNull(element, "dc:created")?.text), + modified: parseDateTime(findElementOrNull(element, "dc:modified")?.text), type: findElementOrNull(element, "dc:type")?.text, format: findElementOrNull(element, "dc:format")?.text, identifier: findElementOrNull(element, "dc:identifier")?.text, diff --git a/pubspec.yaml b/pubspec.yaml index 55f32a9..85aa596 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: webfeed -version: 0.4.3 +version: 0.4.2 description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. author: Wito Chandra homepage: https://github.com/witochandra/webfeed diff --git a/test/rss_test.dart b/test/rss_test.dart index 8231fa3..b97559e 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -2,10 +2,9 @@ import 'dart:core'; import 'dart:io'; import 'package:test/test.dart'; -import 'package:webfeed/webfeed.dart'; - -import 'package:webfeed/domain/rss_itunes_type.dart'; import 'package:webfeed/domain/rss_itunes_episode_type.dart'; +import 'package:webfeed/domain/rss_itunes_type.dart'; +import 'package:webfeed/webfeed.dart'; void main() { test("parse Invalid.xml", () { @@ -72,7 +71,8 @@ void main() { "Lorem ipsum dolor sit amet, consectetur adipiscing elit"); expect(feed.items.first.link, "https://foo.bar.news/1"); expect(feed.items.first.guid, "https://foo.bar.news/1?guid"); - expect(feed.items.first.pubDate, DateTime(2018, 03, 26, 14)); //Mon, 26 Mar 2018 14:00:00 PDT + expect(feed.items.first.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"); @@ -102,7 +102,8 @@ void main() { 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.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); @@ -239,9 +240,9 @@ void main() { expect(feed.dc.description, "description"); expect(feed.dc.publisher, "publisher"); expect(feed.dc.contributor, "contributor"); - expect(feed.dc.date, "2000-01-01T12:00+00:00"); - expect(feed.dc.created, "2000-01-01T12:00+00:00"); - expect(feed.dc.modified, "2000-01-01T12:00+00:00"); + 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"); @@ -257,7 +258,7 @@ void main() { expect(feed.items.first.dc.description, "description"); expect(feed.items.first.dc.publisher, "publisher"); expect(feed.items.first.dc.contributor, "contributor"); - expect(feed.items.first.dc.date, "2000-01-01T12:00+00:00"); + expect(feed.items.first.dc.date, DateTime.utc(2000, 1, 1, 12)); expect(feed.items.first.dc.type, "type"); expect(feed.items.first.dc.format, "format"); expect(feed.items.first.dc.identifier, "identifier"); diff --git a/test/xml/RSS-DC.xml b/test/xml/RSS-DC.xml index 2e156e2..4233fb4 100644 --- a/test/xml/RSS-DC.xml +++ b/test/xml/RSS-DC.xml @@ -25,8 +25,8 @@ publisher contributor 2000-01-01T12:00+00:00 - 2000-01-01T12:00+00:00 - 2000-01-01T12:00+00:00 + 2000-01-01T13:00+00:00 + 2000-01-01T14:00+00:00 type format identifier From 15b58f5a2e0083520568b049af00604459b10089 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 01:47:59 +0700 Subject: [PATCH 08/22] upgrade xml package --- lib/domain/atom_feed.dart | 2 +- lib/domain/rss_feed.dart | 2 +- pubspec.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 1631013..59a607a 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -40,7 +40,7 @@ class AtomFeed { }); factory AtomFeed.parse(String xmlString) { - var document = parse(xmlString); + var document = XmlDocument.parse(xmlString); XmlElement feedElement; try { feedElement = document.findElements("feed").first; diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index f8ada6e..880f8e3 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -59,7 +59,7 @@ class RssFeed { }); factory RssFeed.parse(String xmlString) { - var document = parse(xmlString); + var document = XmlDocument.parse(xmlString); XmlElement channelElement; try { channelElement = document.findAllElements("channel").first; diff --git a/pubspec.yaml b/pubspec.yaml index 85aa596..81640c4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ homepage: https://github.com/witochandra/webfeed environment: sdk: ">=2.0.0 <3.0.0" dependencies: - xml: "^3.0.0" + xml: "^4.3.0" intl: "^0.16.0" dev_dependencies: test: ^1.3.0 From 2a6f0fb450044774ad326e375022791438f63ad8 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 01:55:13 +0700 Subject: [PATCH 09/22] enhance example --- example/main.dart | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/example/main.dart b/example/main.dart index 81a0888..a722833 100644 --- a/example/main.dart +++ b/example/main.dart @@ -1,24 +1,19 @@ import 'package:http/http.dart' as http; import 'package:webfeed/webfeed.dart'; -void main() { - var client = new http.Client(); +void main() async { + var client = http.Client(); // RSS feed - client.get("https://developer.apple.com/news/releases/rss/releases.rss").then((response) { - return response.body; - }).then((bodyString) { - var channel = new RssFeed.parse(bodyString); - print(channel); - return channel; - }); + var response = await client + .get("https://developer.apple.com/news/releases/rss/releases.rss"); + var channel = RssFeed.parse(response.body); + print(channel); // Atom feed - client.get("https://www.theverge.com/rss/index.xml").then((response) { - return response.body; - }).then((bodyString) { - var feed = new AtomFeed.parse(bodyString); - print(feed); - return feed; - }); + response = await client.get("https://www.theverge.com/rss/index.xml"); + var feed = AtomFeed.parse(response.body); + print(feed); + + client.close(); } From 3ed3f94d6001ede7bfd2009dbf5bb2c4ddcdf2d8 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 01:57:40 +0700 Subject: [PATCH 10/22] fix lint warning --- README.md | 4 +-- analysis_options.yaml | 4 +-- lib/domain/atom_feed.dart | 2 +- lib/domain/atom_generator.dart | 2 +- lib/domain/media/category.dart | 2 +- lib/domain/media/community.dart | 8 +++--- lib/domain/media/content.dart | 2 +- lib/domain/media/copyright.dart | 2 +- lib/domain/media/credit.dart | 2 +- lib/domain/media/description.dart | 2 +- lib/domain/media/embed.dart | 4 +-- lib/domain/media/group.dart | 10 +++---- lib/domain/media/hash.dart | 2 +- lib/domain/media/license.dart | 2 +- lib/domain/media/media.dart | 44 +++++++++++++++---------------- lib/domain/media/param.dart | 2 +- lib/domain/media/peer_link.dart | 2 +- lib/domain/media/player.dart | 2 +- lib/domain/media/price.dart | 2 +- lib/domain/media/rating.dart | 2 +- lib/domain/media/restriction.dart | 2 +- lib/domain/media/rights.dart | 2 +- lib/domain/media/scene.dart | 2 +- lib/domain/media/star_rating.dart | 2 +- lib/domain/media/statistics.dart | 2 +- lib/domain/media/status.dart | 2 +- lib/domain/media/tags.dart | 2 +- lib/domain/media/text.dart | 2 +- lib/domain/media/thumbnail.dart | 2 +- lib/domain/media/title.dart | 2 +- lib/domain/rss_content.dart | 2 +- test/atom_test.dart | 12 ++++----- test/rss_test.dart | 12 ++++----- 33 files changed, 73 insertions(+), 75 deletions(-) diff --git a/README.md b/README.md index 0e83d16..715442d 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ import 'package:webfeed/webfeed.dart'; To parse string into `RssFeed` object use: ``` -var rssFeed = new RssFeed.parse(xmlString); // for parsing RSS feed -var atomFeed = new AtomFeed.parse(xmlString); // for parsing Atom feed +var rssFeed = RssFeed.parse(xmlString); // for parsing RSS feed +var atomFeed = AtomFeed.parse(xmlString); // for parsing Atom feed ``` ### Preview diff --git a/analysis_options.yaml b/analysis_options.yaml index 0323d68..2c9d809 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -1,7 +1,4 @@ analyzer: - language: - enablePreviewDart2: true - strong-mode: true errors: unused_import: error unused_local_variable: error @@ -35,3 +32,4 @@ linter: - prefer_typing_uninitialized_variables - slash_for_doc_comments - type_init_formals + - unnecessary_new diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 59a607a..06d1b2c 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -45,7 +45,7 @@ class AtomFeed { try { feedElement = document.findElements("feed").first; } on StateError { - throw new ArgumentError("feed not found"); + throw ArgumentError("feed not found"); } return AtomFeed( diff --git a/lib/domain/atom_generator.dart b/lib/domain/atom_generator.dart index 7fd8579..14eb70d 100644 --- a/lib/domain/atom_generator.dart +++ b/lib/domain/atom_generator.dart @@ -14,6 +14,6 @@ class AtomGenerator { var uri = element.getAttribute("uri"); var version = element.getAttribute("version"); var value = element.text; - return new AtomGenerator(uri, version, value); + return AtomGenerator(uri, version, value); } } diff --git a/lib/domain/media/category.dart b/lib/domain/media/category.dart index 4796cd7..9029738 100644 --- a/lib/domain/media/category.dart +++ b/lib/domain/media/category.dart @@ -15,7 +15,7 @@ class Category { if (element == null) { return null; } - return new Category( + return Category( scheme: element.getAttribute("scheme"), label: element.getAttribute("label"), value: element.text, diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index 8be70b9..6f1c685 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -19,14 +19,14 @@ class Community { if (element == null) { return null; } - return new Community( - starRating: new StarRating.parse( + return Community( + starRating: StarRating.parse( findElementOrNull(element, "media:starRating"), ), - statistics: new Statistics.parse( + statistics: Statistics.parse( findElementOrNull(element, "media:statistics"), ), - tags: new Tags.parse( + tags: Tags.parse( findElementOrNull(element, "media:tags"), ), ); diff --git a/lib/domain/media/content.dart b/lib/domain/media/content.dart index 3a4ebaa..e580e5f 100644 --- a/lib/domain/media/content.dart +++ b/lib/domain/media/content.dart @@ -34,7 +34,7 @@ class Content { }); factory Content.parse(XmlElement element) { - return new Content( + return Content( url: element.getAttribute("url"), type: element.getAttribute("type"), fileSize: int.tryParse(element.getAttribute("fileSize") ?? "0"), diff --git a/lib/domain/media/copyright.dart b/lib/domain/media/copyright.dart index 1cad059..f4b5b8b 100644 --- a/lib/domain/media/copyright.dart +++ b/lib/domain/media/copyright.dart @@ -13,7 +13,7 @@ class Copyright { if (element == null) { return null; } - return new Copyright( + return Copyright( url: element.getAttribute("url"), value: element.text, ); diff --git a/lib/domain/media/credit.dart b/lib/domain/media/credit.dart index 70a5e50..212dac1 100644 --- a/lib/domain/media/credit.dart +++ b/lib/domain/media/credit.dart @@ -12,7 +12,7 @@ class Credit { }); factory Credit.parse(XmlElement element) { - return new Credit( + return Credit( role: element.getAttribute("role"), scheme: element.getAttribute("scheme"), value: element.text, diff --git a/lib/domain/media/description.dart b/lib/domain/media/description.dart index ba6f0e0..17bb1cb 100644 --- a/lib/domain/media/description.dart +++ b/lib/domain/media/description.dart @@ -13,7 +13,7 @@ class Description { if (element == null) { return null; } - return new Description( + return Description( type: element.getAttribute("type"), value: element.text, ); diff --git a/lib/domain/media/embed.dart b/lib/domain/media/embed.dart index 1cca476..6fc84ea 100644 --- a/lib/domain/media/embed.dart +++ b/lib/domain/media/embed.dart @@ -18,12 +18,12 @@ class Embed { if (element == null) { return null; } - return new Embed( + 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 new Param.parse(e); + return Param.parse(e); }).toList(), ); } diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 39e4153..2be5efd 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -22,17 +22,17 @@ class Group { if (element == null) { return null; } - return new Group( + return Group( contents: element.findElements("media:content").map((e) { - return new Content.parse(e); + return Content.parse(e); }).toList(), credits: element.findElements("media:credit").map((e) { - return new Credit.parse(e); + return Credit.parse(e); }).toList(), - category: new Category.parse( + category: Category.parse( findElementOrNull(element, "media:category"), ), - rating: new Rating.parse( + rating: Rating.parse( findElementOrNull(element, "media:rating"), ), ); diff --git a/lib/domain/media/hash.dart b/lib/domain/media/hash.dart index 72ce859..01ad1c3 100644 --- a/lib/domain/media/hash.dart +++ b/lib/domain/media/hash.dart @@ -13,7 +13,7 @@ class Hash { if (element == null) { return null; } - return new Hash( + return Hash( algo: element.getAttribute("algo"), value: element.text, ); diff --git a/lib/domain/media/license.dart b/lib/domain/media/license.dart index c52a8c6..75db98e 100644 --- a/lib/domain/media/license.dart +++ b/lib/domain/media/license.dart @@ -15,7 +15,7 @@ class License { if (element == null) { return null; } - return new License( + return License( type: element.getAttribute("type"), href: element.getAttribute("href"), value: element.text, diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index 39915b3..fc37773 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -78,48 +78,48 @@ class Media { }); factory Media.parse(XmlElement element) { - return new Media( - group: new Group.parse( + return Media( + group: Group.parse( findElementOrNull(element, "media:group"), ), contents: element.findElements("media:content").map((e) { - return new Content.parse(e); + return Content.parse(e); }).toList(), credits: element.findElements("media:credit").map((e) { - return new Credit.parse(e); + return Credit.parse(e); }).toList(), - category: new Category.parse( + category: Category.parse( findElementOrNull(element, "media:category"), ), - rating: new Rating.parse( + rating: Rating.parse( findElementOrNull(element, "media:rating"), ), - title: new Title.parse( + title: Title.parse( findElementOrNull(element, "media:title"), ), - description: new Description.parse( + description: Description.parse( findElementOrNull(element, "media:description"), ), keywords: findElementOrNull(element, "media:keywords")?.text, thumbnails: element.findElements("media:thumbnail").map((e) { - return new Thumbnail.parse(e); + return Thumbnail.parse(e); }).toList(), - hash: new Hash.parse( + hash: Hash.parse( findElementOrNull(element, "media:hash"), ), - player: new Player.parse( + player: Player.parse( findElementOrNull(element, "media:player"), ), - copyright: new Copyright.parse( + copyright: Copyright.parse( findElementOrNull(element, "media:copyright"), ), - text: new Text.parse( + text: Text.parse( findElementOrNull(element, "media:text"), ), - restriction: new Restriction.parse( + restriction: Restriction.parse( findElementOrNull(element, "media:restriction"), ), - community: new Community.parse( + community: Community.parse( findElementOrNull(element, "media:community"), ), comments: findElementOrNull(element, "media:comments") @@ -128,7 +128,7 @@ class Media { return e.text; })?.toList() ?? [], - embed: new Embed.parse( + embed: Embed.parse( findElementOrNull(element, "media:embed"), ), responses: findElementOrNull(element, "media:responses") @@ -143,25 +143,25 @@ class Media { return e.text; })?.toList() ?? [], - status: new Status.parse( + status: Status.parse( findElementOrNull(element, "media:status"), ), prices: element.findElements("media:price").map((e) { - return new Price.parse(e); + return Price.parse(e); }).toList(), - license: new License.parse( + license: License.parse( findElementOrNull(element, "media:license"), ), - peerLink: new PeerLink.parse( + peerLink: PeerLink.parse( findElementOrNull(element, "media:peerLink"), ), - rights: new Rights.parse( + rights: Rights.parse( findElementOrNull(element, "media:rights"), ), scenes: findElementOrNull(element, "media:scenes") ?.findElements("media:scene") ?.map((e) { - return new Scene.parse(e); + return Scene.parse(e); })?.toList() ?? [], ); diff --git a/lib/domain/media/param.dart b/lib/domain/media/param.dart index 175e6b8..f6299c8 100644 --- a/lib/domain/media/param.dart +++ b/lib/domain/media/param.dart @@ -13,7 +13,7 @@ class Param { if (element == null) { return null; } - return new Param( + return Param( name: element.getAttribute("name"), value: element.text, ); diff --git a/lib/domain/media/peer_link.dart b/lib/domain/media/peer_link.dart index 6c51a17..dd06d90 100644 --- a/lib/domain/media/peer_link.dart +++ b/lib/domain/media/peer_link.dart @@ -15,7 +15,7 @@ class PeerLink { if (element == null) { return null; } - return new PeerLink( + return PeerLink( type: element.getAttribute("type"), href: element.getAttribute("href"), value: element.text, diff --git a/lib/domain/media/player.dart b/lib/domain/media/player.dart index 23d5e7a..14b2a54 100644 --- a/lib/domain/media/player.dart +++ b/lib/domain/media/player.dart @@ -17,7 +17,7 @@ class Player { if (element == null) { return null; } - return new Player( + return Player( url: element.getAttribute("url"), width: int.tryParse(element.getAttribute("width") ?? "0"), height: int.tryParse(element.getAttribute("height") ?? "0"), diff --git a/lib/domain/media/price.dart b/lib/domain/media/price.dart index 6da075b..6b930ce 100644 --- a/lib/domain/media/price.dart +++ b/lib/domain/media/price.dart @@ -14,7 +14,7 @@ class Price { }); factory Price.parse(XmlElement element) { - return new Price( + return Price( price: double.tryParse(element.getAttribute("price") ?? "0"), type: element.getAttribute("type"), info: element.getAttribute("info"), diff --git a/lib/domain/media/rating.dart b/lib/domain/media/rating.dart index 77c2b12..5a53f88 100644 --- a/lib/domain/media/rating.dart +++ b/lib/domain/media/rating.dart @@ -13,7 +13,7 @@ class Rating { if (element == null) { return null; } - return new Rating( + return Rating( scheme: element.getAttribute("scheme"), value: element.text, ); diff --git a/lib/domain/media/restriction.dart b/lib/domain/media/restriction.dart index 4aa56bd..59a5339 100644 --- a/lib/domain/media/restriction.dart +++ b/lib/domain/media/restriction.dart @@ -15,7 +15,7 @@ class Restriction { if (element == null) { return null; } - return new Restriction( + return Restriction( relationship: element.getAttribute("relationship"), type: element.getAttribute("type"), value: element.text, diff --git a/lib/domain/media/rights.dart b/lib/domain/media/rights.dart index eb00d4d..38feed3 100644 --- a/lib/domain/media/rights.dart +++ b/lib/domain/media/rights.dart @@ -11,7 +11,7 @@ class Rights { if (element == null) { return null; } - return new Rights( + return Rights( status: element.getAttribute("status"), ); } diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index f032e1c..1336dc9 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -18,7 +18,7 @@ class Scene { if (element == null) { return null; } - return new Scene( + return Scene( title: findElementOrNull(element, "sceneTitle")?.text, description: findElementOrNull(element, "sceneDescription")?.text, startTime: findElementOrNull(element, "sceneStartTime")?.text, diff --git a/lib/domain/media/star_rating.dart b/lib/domain/media/star_rating.dart index ae4c400..9fc456b 100644 --- a/lib/domain/media/star_rating.dart +++ b/lib/domain/media/star_rating.dart @@ -14,7 +14,7 @@ class StarRating { }); factory StarRating.parse(XmlElement element) { - return new StarRating( + return StarRating( average: double.tryParse(element.getAttribute("average") ?? "0"), count: int.tryParse(element.getAttribute("count") ?? "0"), min: int.tryParse(element.getAttribute("min") ?? "0"), diff --git a/lib/domain/media/statistics.dart b/lib/domain/media/statistics.dart index d93461f..d30b025 100644 --- a/lib/domain/media/statistics.dart +++ b/lib/domain/media/statistics.dart @@ -10,7 +10,7 @@ class Statistics { }); factory Statistics.parse(XmlElement element) { - return new Statistics( + return Statistics( views: int.tryParse(element.getAttribute("views") ?? "0"), favorites: int.tryParse(element.getAttribute("favorites") ?? "0"), ); diff --git a/lib/domain/media/status.dart b/lib/domain/media/status.dart index 3071a09..17200ac 100644 --- a/lib/domain/media/status.dart +++ b/lib/domain/media/status.dart @@ -13,7 +13,7 @@ class Status { if (element == null) { return null; } - return new Status( + return Status( state: element.getAttribute("state"), reason: element.getAttribute("reason"), ); diff --git a/lib/domain/media/tags.dart b/lib/domain/media/tags.dart index c7001a7..3617a0a 100644 --- a/lib/domain/media/tags.dart +++ b/lib/domain/media/tags.dart @@ -13,7 +13,7 @@ class Tags { if (element == null) { return null; } - return new Tags( + 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 1ff886b..702e934 100644 --- a/lib/domain/media/text.dart +++ b/lib/domain/media/text.dart @@ -19,7 +19,7 @@ class Text { if (element == null) { return null; } - return new Text( + return Text( type: element.getAttribute("type"), lang: element.getAttribute("lang"), start: element.getAttribute("start"), diff --git a/lib/domain/media/thumbnail.dart b/lib/domain/media/thumbnail.dart index 8adce3b..0c3f31c 100644 --- a/lib/domain/media/thumbnail.dart +++ b/lib/domain/media/thumbnail.dart @@ -14,7 +14,7 @@ class Thumbnail { }); factory Thumbnail.parse(XmlElement element) { - return new Thumbnail( + return Thumbnail( url: element.getAttribute("url"), width: element.getAttribute("width"), height: element.getAttribute("height"), diff --git a/lib/domain/media/title.dart b/lib/domain/media/title.dart index 8c875a6..49482d6 100644 --- a/lib/domain/media/title.dart +++ b/lib/domain/media/title.dart @@ -13,7 +13,7 @@ class Title { if (element == null) { return null; } - return new Title( + return Title( type: element.getAttribute("type"), value: element.text, ); diff --git a/lib/domain/rss_content.dart b/lib/domain/rss_content.dart index ded57bc..5dacce1 100644 --- a/lib/domain/rss_content.dart +++ b/lib/domain/rss_content.dart @@ -1,6 +1,6 @@ import 'package:xml/xml.dart'; -final _imagesRegExp = new RegExp( +final _imagesRegExp = RegExp( "]+)(?:'|\")", multiLine: true, caseSensitive: false, diff --git a/test/atom_test.dart b/test/atom_test.dart index 70b6b0f..f3b9c12 100644 --- a/test/atom_test.dart +++ b/test/atom_test.dart @@ -6,18 +6,18 @@ import 'package:webfeed/webfeed.dart'; void main() { test("parse Invalid.xml", () { - var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); + var xmlString = File("test/xml/Invalid.xml").readAsStringSync(); try { - new AtomFeed.parse(xmlString); + AtomFeed.parse(xmlString); fail("Should throw Argument Error"); } on ArgumentError {} }); test("parse Atom.xml", () { - var xmlString = new File("test/xml/Atom.xml").readAsStringSync(); + var xmlString = File("test/xml/Atom.xml").readAsStringSync(); - var feed = new AtomFeed.parse(xmlString); + var feed = AtomFeed.parse(xmlString); expect(feed.id, "foo-bar-id"); expect(feed.title, "Foo bar news"); @@ -89,9 +89,9 @@ void main() { expect(item.rights, "This is rights 1"); }); test("parse Atom-Media.xml", () { - var xmlString = new File("test/xml/Atom-Media.xml").readAsStringSync(); + var xmlString = File("test/xml/Atom-Media.xml").readAsStringSync(); - var feed = new AtomFeed.parse(xmlString); + var feed = AtomFeed.parse(xmlString); expect(feed.id, "foo-bar-id"); expect(feed.title, "Foo bar news"); expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); diff --git a/test/rss_test.dart b/test/rss_test.dart index b97559e..16fc91e 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -8,17 +8,17 @@ import 'package:webfeed/webfeed.dart'; void main() { test("parse Invalid.xml", () { - var xmlString = new File("test/xml/Invalid.xml").readAsStringSync(); + var xmlString = File("test/xml/Invalid.xml").readAsStringSync(); try { - new RssFeed.parse(xmlString); + RssFeed.parse(xmlString); fail("Should throw Argument Error"); } on ArgumentError {} }); test("parse RSS.xml", () { - var xmlString = new File("test/xml/RSS.xml").readAsStringSync(); + var xmlString = File("test/xml/RSS.xml").readAsStringSync(); - var feed = new RssFeed.parse(xmlString); + var feed = RssFeed.parse(xmlString); expect(feed.title, "News - Foo bar News"); expect(feed.description, @@ -90,9 +90,9 @@ void main() { feed.items.first.content.images.first, "https://test.com/image_link"); }); test("parse RSS-Media.xml", () { - var xmlString = new File("test/xml/RSS-Media.xml").readAsStringSync(); + var xmlString = File("test/xml/RSS-Media.xml").readAsStringSync(); - var feed = new RssFeed.parse(xmlString); + var feed = RssFeed.parse(xmlString); expect(feed.title, "Song Site"); expect( feed.description, "Media RSS example with new fields added in v1.5.0"); From 96d7964227749c75a6cfec1a0268c76638215326 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 02:16:50 +0700 Subject: [PATCH 11/22] apply prefer_single_quotes rule --- analysis_options.yaml | 1 + example/main.dart | 4 +- lib/domain/atom_category.dart | 6 +- lib/domain/atom_feed.dart | 30 +-- lib/domain/atom_generator.dart | 4 +- lib/domain/atom_item.dart | 24 +- lib/domain/atom_link.dart | 14 +- lib/domain/atom_person.dart | 6 +- lib/domain/atom_source.dart | 6 +- lib/domain/dublin_core/dublin_core.dart | 34 +-- lib/domain/media/category.dart | 4 +- lib/domain/media/community.dart | 6 +- lib/domain/media/content.dart | 28 +- lib/domain/media/copyright.dart | 2 +- lib/domain/media/credit.dart | 4 +- lib/domain/media/description.dart | 2 +- lib/domain/media/embed.dart | 8 +- lib/domain/media/group.dart | 8 +- lib/domain/media/hash.dart | 2 +- lib/domain/media/license.dart | 4 +- lib/domain/media/media.dart | 58 ++--- lib/domain/media/param.dart | 2 +- lib/domain/media/peer_link.dart | 4 +- lib/domain/media/player.dart | 6 +- lib/domain/media/price.dart | 8 +- lib/domain/media/rating.dart | 2 +- lib/domain/media/restriction.dart | 4 +- lib/domain/media/rights.dart | 2 +- lib/domain/media/scene.dart | 8 +- lib/domain/media/star_rating.dart | 8 +- lib/domain/media/statistics.dart | 4 +- lib/domain/media/status.dart | 4 +- lib/domain/media/tags.dart | 2 +- lib/domain/media/text.dart | 8 +- lib/domain/media/thumbnail.dart | 8 +- lib/domain/media/title.dart | 2 +- lib/domain/rss_category.dart | 2 +- lib/domain/rss_cloud.dart | 10 +- lib/domain/rss_enclosure.dart | 6 +- lib/domain/rss_feed.dart | 48 ++-- lib/domain/rss_image.dart | 6 +- lib/domain/rss_item.dart | 22 +- lib/domain/rss_item_itunes.dart | 28 +- lib/domain/rss_itunes.dart | 28 +- lib/domain/rss_itunes_category.dart | 9 +- lib/domain/rss_itunes_episode_type.dart | 8 +- lib/domain/rss_itunes_image.dart | 2 +- lib/domain/rss_itunes_owner.dart | 4 +- lib/domain/rss_itunes_type.dart | 6 +- lib/domain/rss_source.dart | 2 +- lib/util/xml.dart | 3 +- test/atom_test.dart | 230 ++++++++--------- test/rss_test.dart | 330 ++++++++++++------------ 53 files changed, 536 insertions(+), 535 deletions(-) diff --git a/analysis_options.yaml b/analysis_options.yaml index 2c9d809..d74c8fe 100644 --- a/analysis_options.yaml +++ b/analysis_options.yaml @@ -33,3 +33,4 @@ linter: - slash_for_doc_comments - type_init_formals - unnecessary_new + - prefer_single_quotes diff --git a/example/main.dart b/example/main.dart index a722833..7a4500c 100644 --- a/example/main.dart +++ b/example/main.dart @@ -6,12 +6,12 @@ void main() async { // RSS feed var response = await client - .get("https://developer.apple.com/news/releases/rss/releases.rss"); + .get('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('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 22c6a97..acd5b58 100644 --- a/lib/domain/atom_category.dart +++ b/lib/domain/atom_category.dart @@ -8,9 +8,9 @@ class AtomCategory { AtomCategory(this.term, this.scheme, this.label); factory AtomCategory.parse(XmlElement element) { - var term = element.getAttribute("term"); - var scheme = element.getAttribute("scheme"); - var label = element.getAttribute("label"); + var term = element.getAttribute('term'); + var scheme = element.getAttribute('scheme'); + var label = element.getAttribute('label'); return AtomCategory(term, scheme, label); } } diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 06d1b2c..8a4f75e 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -43,36 +43,36 @@ class AtomFeed { var document = XmlDocument.parse(xmlString); XmlElement feedElement; try { - feedElement = document.findElements("feed").first; + feedElement = document.findElements('feed').first; } on StateError { - throw ArgumentError("feed not found"); + throw ArgumentError('feed not found'); } return AtomFeed( - id: findElementOrNull(feedElement, "id")?.text, - title: findElementOrNull(feedElement, "title")?.text, - updated: parseDateTime(findElementOrNull(feedElement, "updated")?.text), - items: feedElement.findElements("entry").map((element) { + id: findElementOrNull(feedElement, 'id')?.text, + title: findElementOrNull(feedElement, 'title')?.text, + updated: parseDateTime(findElementOrNull(feedElement, 'updated')?.text), + items: feedElement.findElements('entry').map((element) { return AtomItem.parse(element); }).toList(), - links: feedElement.findElements("link").map((element) { + links: feedElement.findElements('link').map((element) { return AtomLink.parse(element); }).toList(), - authors: feedElement.findElements("author").map((element) { + authors: feedElement.findElements('author').map((element) { return AtomPerson.parse(element); }).toList(), - contributors: feedElement.findElements("contributor").map((element) { + contributors: feedElement.findElements('contributor').map((element) { return AtomPerson.parse(element); }).toList(), - categories: feedElement.findElements("category").map((element) { + categories: feedElement.findElements('category').map((element) { return AtomCategory.parse(element); }).toList(), generator: - AtomGenerator.parse(findElementOrNull(feedElement, "generator")), - icon: findElementOrNull(feedElement, "icon")?.text, - logo: findElementOrNull(feedElement, "logo")?.text, - rights: findElementOrNull(feedElement, "rights")?.text, - subtitle: findElementOrNull(feedElement, "subtitle")?.text, + AtomGenerator.parse(findElementOrNull(feedElement, 'generator')), + icon: findElementOrNull(feedElement, 'icon')?.text, + logo: findElementOrNull(feedElement, 'logo')?.text, + rights: findElementOrNull(feedElement, 'rights')?.text, + subtitle: findElementOrNull(feedElement, 'subtitle')?.text, ); } } diff --git a/lib/domain/atom_generator.dart b/lib/domain/atom_generator.dart index 14eb70d..b3a0b5f 100644 --- a/lib/domain/atom_generator.dart +++ b/lib/domain/atom_generator.dart @@ -11,8 +11,8 @@ class AtomGenerator { if (element == null) { return null; } - var uri = element.getAttribute("uri"); - var version = element.getAttribute("version"); + var uri = element.getAttribute('uri'); + var version = element.getAttribute('version'); var value = element.text; return AtomGenerator(uri, version, value); } diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index f04181f..2b93ccc 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -41,26 +41,26 @@ class AtomItem { factory AtomItem.parse(XmlElement element) { return AtomItem( - id: findElementOrNull(element, "id")?.text, - title: findElementOrNull(element, "title")?.text, - updated: parseDateTime(findElementOrNull(element, "updated")?.text), - authors: element.findElements("author").map((element) { + id: findElementOrNull(element, 'id')?.text, + title: findElementOrNull(element, 'title')?.text, + updated: parseDateTime(findElementOrNull(element, 'updated')?.text), + authors: element.findElements('author').map((element) { return AtomPerson.parse(element); }).toList(), - links: element.findElements("link").map((element) { + links: element.findElements('link').map((element) { return AtomLink.parse(element); }).toList(), - categories: element.findElements("category").map((element) { + categories: element.findElements('category').map((element) { return AtomCategory.parse(element); }).toList(), - contributors: element.findElements("contributor").map((element) { + contributors: element.findElements('contributor').map((element) { return AtomPerson.parse(element); }).toList(), - source: AtomSource.parse(findElementOrNull(element, "source")), - published: findElementOrNull(element, "published")?.text, - content: findElementOrNull(element, "content")?.text, - summary: findElementOrNull(element, "summary")?.text, - rights: findElementOrNull(element, "rights")?.text, + source: AtomSource.parse(findElementOrNull(element, 'source')), + published: findElementOrNull(element, 'published')?.text, + content: findElementOrNull(element, 'content')?.text, + summary: findElementOrNull(element, 'summary')?.text, + rights: findElementOrNull(element, 'rights')?.text, media: Media.parse(element), ); } diff --git a/lib/domain/atom_link.dart b/lib/domain/atom_link.dart index 3b570f2..9b68ac2 100644 --- a/lib/domain/atom_link.dart +++ b/lib/domain/atom_link.dart @@ -18,14 +18,14 @@ class AtomLink { ); factory AtomLink.parse(XmlElement element) { - var href = element.getAttribute("href"); - var rel = element.getAttribute("rel"); - var type = element.getAttribute("type"); - var title = element.getAttribute("title"); - var hreflang = element.getAttribute("hreflang"); + var href = element.getAttribute('href'); + var rel = element.getAttribute('rel'); + var type = element.getAttribute('type'); + var title = element.getAttribute('title'); + var hreflang = element.getAttribute('hreflang'); var length = 0; - if (element.getAttribute("length") != null) { - length = int.parse(element.getAttribute("length")); + if (element.getAttribute('length') != null) { + length = int.parse(element.getAttribute('length')); } return AtomLink(href, rel, type, hreflang, title, length); } diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart index c68fe45..1d84e6c 100644 --- a/lib/domain/atom_person.dart +++ b/lib/domain/atom_person.dart @@ -9,9 +9,9 @@ class AtomPerson { AtomPerson(this.name, this.uri, this.email); factory AtomPerson.parse(XmlElement element) { - var name = findElementOrNull(element, "name")?.text; - var uri = findElementOrNull(element, "uri")?.text; - var email = findElementOrNull(element, "email")?.text; + var name = findElementOrNull(element, 'name')?.text; + var uri = findElementOrNull(element, 'uri')?.text; + var email = findElementOrNull(element, 'email')?.text; return AtomPerson(name, uri, email); } } diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart index d632d5a..9f1b34b 100644 --- a/lib/domain/atom_source.dart +++ b/lib/domain/atom_source.dart @@ -12,9 +12,9 @@ class AtomSource { if (element == null) { return null; } - var id = findElementOrNull(element, "id")?.text; - var title = findElementOrNull(element, "title")?.text; - var updated = findElementOrNull(element, "updated")?.text; + var id = findElementOrNull(element, 'id')?.text; + var title = findElementOrNull(element, 'title')?.text; + var updated = findElementOrNull(element, 'updated')?.text; return AtomSource(id, title, updated); } diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index 53a496c..b36c004 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -46,23 +46,23 @@ class DublinCore { return null; } return DublinCore( - title: findElementOrNull(element, "dc:title")?.text, - description: findElementOrNull(element, "dc:description")?.text, - creator: findElementOrNull(element, "dc:creator")?.text, - subject: findElementOrNull(element, "dc:subject")?.text, - publisher: findElementOrNull(element, "dc:publisher")?.text, - contributor: findElementOrNull(element, "dc:contributor")?.text, - date: parseDateTime(findElementOrNull(element, "dc:date")?.text), - created: parseDateTime(findElementOrNull(element, "dc:created")?.text), - modified: parseDateTime(findElementOrNull(element, "dc:modified")?.text), - type: findElementOrNull(element, "dc:type")?.text, - format: findElementOrNull(element, "dc:format")?.text, - identifier: findElementOrNull(element, "dc:identifier")?.text, - source: findElementOrNull(element, "dc:source")?.text, - language: findElementOrNull(element, "dc:language")?.text, - relation: findElementOrNull(element, "dc:relation")?.text, - coverage: findElementOrNull(element, "dc:coverage")?.text, - rights: findElementOrNull(element, "dc:rights")?.text, + title: findElementOrNull(element, 'dc:title')?.text, + description: findElementOrNull(element, 'dc:description')?.text, + creator: findElementOrNull(element, 'dc:creator')?.text, + subject: findElementOrNull(element, 'dc:subject')?.text, + publisher: findElementOrNull(element, 'dc:publisher')?.text, + contributor: findElementOrNull(element, 'dc:contributor')?.text, + date: parseDateTime(findElementOrNull(element, 'dc:date')?.text), + created: parseDateTime(findElementOrNull(element, 'dc:created')?.text), + modified: parseDateTime(findElementOrNull(element, 'dc:modified')?.text), + type: findElementOrNull(element, 'dc:type')?.text, + format: findElementOrNull(element, 'dc:format')?.text, + identifier: findElementOrNull(element, 'dc:identifier')?.text, + source: findElementOrNull(element, 'dc:source')?.text, + language: findElementOrNull(element, 'dc:language')?.text, + relation: findElementOrNull(element, 'dc:relation')?.text, + coverage: findElementOrNull(element, 'dc:coverage')?.text, + rights: findElementOrNull(element, 'dc:rights')?.text, ); } } diff --git a/lib/domain/media/category.dart b/lib/domain/media/category.dart index 9029738..967e0a2 100644 --- a/lib/domain/media/category.dart +++ b/lib/domain/media/category.dart @@ -16,8 +16,8 @@ class Category { return null; } return Category( - scheme: element.getAttribute("scheme"), - label: element.getAttribute("label"), + scheme: element.getAttribute('scheme'), + label: element.getAttribute('label'), value: element.text, ); } diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index 6f1c685..fcbbf8a 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -21,13 +21,13 @@ class Community { } return Community( starRating: StarRating.parse( - findElementOrNull(element, "media:starRating"), + findElementOrNull(element, 'media:starRating'), ), statistics: Statistics.parse( - findElementOrNull(element, "media:statistics"), + findElementOrNull(element, 'media:statistics'), ), tags: Tags.parse( - findElementOrNull(element, "media:tags"), + findElementOrNull(element, 'media:tags'), ), ); } diff --git a/lib/domain/media/content.dart b/lib/domain/media/content.dart index e580e5f..061119c 100644 --- a/lib/domain/media/content.dart +++ b/lib/domain/media/content.dart @@ -35,22 +35,22 @@ class Content { factory Content.parse(XmlElement element) { return Content( - url: element.getAttribute("url"), - type: element.getAttribute("type"), - fileSize: int.tryParse(element.getAttribute("fileSize") ?? "0"), - medium: element.getAttribute("medium"), - isDefault: element.getAttribute("isDefault") == "true", - expression: element.getAttribute("expression"), - bitrate: int.tryParse(element.getAttribute("bitrate") ?? "0"), - framerate: double.tryParse(element.getAttribute("framerate") ?? "0"), + url: element.getAttribute('url'), + type: element.getAttribute('type'), + fileSize: int.tryParse(element.getAttribute('fileSize') ?? '0'), + medium: element.getAttribute('medium'), + isDefault: element.getAttribute('isDefault') == 'true', + expression: element.getAttribute('expression'), + bitrate: int.tryParse(element.getAttribute('bitrate') ?? '0'), + framerate: double.tryParse(element.getAttribute('framerate') ?? '0'), samplingrate: double.tryParse( - element.getAttribute("samplingrate") ?? "0", + element.getAttribute('samplingrate') ?? '0', ), - channels: int.tryParse(element.getAttribute("channels") ?? "0"), - duration: int.tryParse(element.getAttribute("duration") ?? "0"), - height: int.tryParse(element.getAttribute("height") ?? "0"), - width: int.tryParse(element.getAttribute("width") ?? "0"), - lang: element.getAttribute("lang"), + channels: int.tryParse(element.getAttribute('channels') ?? '0'), + duration: int.tryParse(element.getAttribute('duration') ?? '0'), + height: int.tryParse(element.getAttribute('height') ?? '0'), + width: int.tryParse(element.getAttribute('width') ?? '0'), + lang: element.getAttribute('lang'), ); } } diff --git a/lib/domain/media/copyright.dart b/lib/domain/media/copyright.dart index f4b5b8b..e40c4c7 100644 --- a/lib/domain/media/copyright.dart +++ b/lib/domain/media/copyright.dart @@ -14,7 +14,7 @@ class Copyright { return null; } return Copyright( - url: element.getAttribute("url"), + url: element.getAttribute('url'), value: element.text, ); } diff --git a/lib/domain/media/credit.dart b/lib/domain/media/credit.dart index 212dac1..3f0838b 100644 --- a/lib/domain/media/credit.dart +++ b/lib/domain/media/credit.dart @@ -13,8 +13,8 @@ class Credit { factory Credit.parse(XmlElement element) { return Credit( - role: element.getAttribute("role"), - scheme: element.getAttribute("scheme"), + role: element.getAttribute('role'), + scheme: element.getAttribute('scheme'), value: element.text, ); } diff --git a/lib/domain/media/description.dart b/lib/domain/media/description.dart index 17bb1cb..29866d0 100644 --- a/lib/domain/media/description.dart +++ b/lib/domain/media/description.dart @@ -14,7 +14,7 @@ class Description { return null; } return Description( - type: element.getAttribute("type"), + type: element.getAttribute('type'), value: element.text, ); } diff --git a/lib/domain/media/embed.dart b/lib/domain/media/embed.dart index 6fc84ea..81555be 100644 --- a/lib/domain/media/embed.dart +++ b/lib/domain/media/embed.dart @@ -19,10 +19,10 @@ class Embed { 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) { + url: element.getAttribute('url'), + width: int.tryParse(element.getAttribute('width') ?? '0'), + height: int.tryParse(element.getAttribute('height') ?? '0'), + params: element.findElements('media:param').map((e) { return Param.parse(e); }).toList(), ); diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 2be5efd..7f656a9 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -23,17 +23,17 @@ class Group { return null; } return Group( - contents: element.findElements("media:content").map((e) { + contents: element.findElements('media:content').map((e) { return Content.parse(e); }).toList(), - credits: element.findElements("media:credit").map((e) { + credits: element.findElements('media:credit').map((e) { return Credit.parse(e); }).toList(), category: Category.parse( - findElementOrNull(element, "media:category"), + findElementOrNull(element, 'media:category'), ), rating: Rating.parse( - findElementOrNull(element, "media:rating"), + findElementOrNull(element, 'media:rating'), ), ); } diff --git a/lib/domain/media/hash.dart b/lib/domain/media/hash.dart index 01ad1c3..bfcbd72 100644 --- a/lib/domain/media/hash.dart +++ b/lib/domain/media/hash.dart @@ -14,7 +14,7 @@ class Hash { return null; } return Hash( - algo: element.getAttribute("algo"), + algo: element.getAttribute('algo'), value: element.text, ); } diff --git a/lib/domain/media/license.dart b/lib/domain/media/license.dart index 75db98e..e3990db 100644 --- a/lib/domain/media/license.dart +++ b/lib/domain/media/license.dart @@ -16,8 +16,8 @@ class License { return null; } return License( - type: element.getAttribute("type"), - href: element.getAttribute("href"), + type: element.getAttribute('type'), + href: element.getAttribute('href'), value: element.text, ); } diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index fc37773..c5655a2 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -80,86 +80,86 @@ class Media { factory Media.parse(XmlElement element) { return Media( group: Group.parse( - findElementOrNull(element, "media:group"), + findElementOrNull(element, 'media:group'), ), - contents: element.findElements("media:content").map((e) { + contents: element.findElements('media:content').map((e) { return Content.parse(e); }).toList(), - credits: element.findElements("media:credit").map((e) { + credits: element.findElements('media:credit').map((e) { return Credit.parse(e); }).toList(), category: Category.parse( - findElementOrNull(element, "media:category"), + findElementOrNull(element, 'media:category'), ), rating: Rating.parse( - findElementOrNull(element, "media:rating"), + findElementOrNull(element, 'media:rating'), ), title: Title.parse( - findElementOrNull(element, "media:title"), + findElementOrNull(element, 'media:title'), ), description: Description.parse( - findElementOrNull(element, "media:description"), + findElementOrNull(element, 'media:description'), ), - keywords: findElementOrNull(element, "media:keywords")?.text, - thumbnails: element.findElements("media:thumbnail").map((e) { + keywords: findElementOrNull(element, 'media:keywords')?.text, + thumbnails: element.findElements('media:thumbnail').map((e) { return Thumbnail.parse(e); }).toList(), hash: Hash.parse( - findElementOrNull(element, "media:hash"), + findElementOrNull(element, 'media:hash'), ), player: Player.parse( - findElementOrNull(element, "media:player"), + findElementOrNull(element, 'media:player'), ), copyright: Copyright.parse( - findElementOrNull(element, "media:copyright"), + findElementOrNull(element, 'media:copyright'), ), text: Text.parse( - findElementOrNull(element, "media:text"), + findElementOrNull(element, 'media:text'), ), restriction: Restriction.parse( - findElementOrNull(element, "media:restriction"), + findElementOrNull(element, 'media:restriction'), ), community: Community.parse( - findElementOrNull(element, "media:community"), + findElementOrNull(element, 'media:community'), ), - comments: findElementOrNull(element, "media:comments") - ?.findElements("media:comment") + comments: findElementOrNull(element, 'media:comments') + ?.findElements('media:comment') ?.map((e) { return e.text; })?.toList() ?? [], embed: Embed.parse( - findElementOrNull(element, "media:embed"), + findElementOrNull(element, 'media:embed'), ), - responses: findElementOrNull(element, "media:responses") - ?.findElements("media:response") + responses: findElementOrNull(element, 'media:responses') + ?.findElements('media:response') ?.map((e) { return e.text; })?.toList() ?? [], - backLinks: findElementOrNull(element, "media:backLinks") - ?.findElements("media:backLink") + backLinks: findElementOrNull(element, 'media:backLinks') + ?.findElements('media:backLink') ?.map((e) { return e.text; })?.toList() ?? [], status: Status.parse( - findElementOrNull(element, "media:status"), + findElementOrNull(element, 'media:status'), ), - prices: element.findElements("media:price").map((e) { + prices: element.findElements('media:price').map((e) { return Price.parse(e); }).toList(), license: License.parse( - findElementOrNull(element, "media:license"), + findElementOrNull(element, 'media:license'), ), peerLink: PeerLink.parse( - findElementOrNull(element, "media:peerLink"), + findElementOrNull(element, 'media:peerLink'), ), rights: Rights.parse( - findElementOrNull(element, "media:rights"), + findElementOrNull(element, 'media:rights'), ), - scenes: findElementOrNull(element, "media:scenes") - ?.findElements("media:scene") + scenes: findElementOrNull(element, 'media:scenes') + ?.findElements('media:scene') ?.map((e) { return Scene.parse(e); })?.toList() ?? diff --git a/lib/domain/media/param.dart b/lib/domain/media/param.dart index f6299c8..ac42675 100644 --- a/lib/domain/media/param.dart +++ b/lib/domain/media/param.dart @@ -14,7 +14,7 @@ class Param { return null; } return Param( - name: element.getAttribute("name"), + name: element.getAttribute('name'), value: element.text, ); } diff --git a/lib/domain/media/peer_link.dart b/lib/domain/media/peer_link.dart index dd06d90..08a5524 100644 --- a/lib/domain/media/peer_link.dart +++ b/lib/domain/media/peer_link.dart @@ -16,8 +16,8 @@ class PeerLink { return null; } return PeerLink( - type: element.getAttribute("type"), - href: element.getAttribute("href"), + type: element.getAttribute('type'), + href: element.getAttribute('href'), value: element.text, ); } diff --git a/lib/domain/media/player.dart b/lib/domain/media/player.dart index 14b2a54..2036445 100644 --- a/lib/domain/media/player.dart +++ b/lib/domain/media/player.dart @@ -18,9 +18,9 @@ class Player { return null; } return Player( - url: element.getAttribute("url"), - width: int.tryParse(element.getAttribute("width") ?? "0"), - height: int.tryParse(element.getAttribute("height") ?? "0"), + url: element.getAttribute('url'), + width: int.tryParse(element.getAttribute('width') ?? '0'), + height: int.tryParse(element.getAttribute('height') ?? '0'), value: element.text, ); } diff --git a/lib/domain/media/price.dart b/lib/domain/media/price.dart index 6b930ce..4ac9059 100644 --- a/lib/domain/media/price.dart +++ b/lib/domain/media/price.dart @@ -15,10 +15,10 @@ class Price { factory Price.parse(XmlElement element) { return Price( - price: double.tryParse(element.getAttribute("price") ?? "0"), - type: element.getAttribute("type"), - info: element.getAttribute("info"), - currency: element.getAttribute("currency"), + price: double.tryParse(element.getAttribute('price') ?? '0'), + type: element.getAttribute('type'), + info: element.getAttribute('info'), + currency: element.getAttribute('currency'), ); } } diff --git a/lib/domain/media/rating.dart b/lib/domain/media/rating.dart index 5a53f88..7924cdd 100644 --- a/lib/domain/media/rating.dart +++ b/lib/domain/media/rating.dart @@ -14,7 +14,7 @@ class Rating { return null; } return Rating( - scheme: element.getAttribute("scheme"), + scheme: element.getAttribute('scheme'), value: element.text, ); } diff --git a/lib/domain/media/restriction.dart b/lib/domain/media/restriction.dart index 59a5339..cc896e9 100644 --- a/lib/domain/media/restriction.dart +++ b/lib/domain/media/restriction.dart @@ -16,8 +16,8 @@ class Restriction { return null; } return Restriction( - relationship: element.getAttribute("relationship"), - type: element.getAttribute("type"), + relationship: element.getAttribute('relationship'), + type: element.getAttribute('type'), value: element.text, ); } diff --git a/lib/domain/media/rights.dart b/lib/domain/media/rights.dart index 38feed3..2dfd20b 100644 --- a/lib/domain/media/rights.dart +++ b/lib/domain/media/rights.dart @@ -12,7 +12,7 @@ class Rights { return null; } return Rights( - status: element.getAttribute("status"), + status: element.getAttribute('status'), ); } } diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index 1336dc9..19e730e 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -19,10 +19,10 @@ class Scene { return null; } return Scene( - title: findElementOrNull(element, "sceneTitle")?.text, - description: findElementOrNull(element, "sceneDescription")?.text, - startTime: findElementOrNull(element, "sceneStartTime")?.text, - endTime: findElementOrNull(element, "sceneEndTime")?.text, + title: findElementOrNull(element, 'sceneTitle')?.text, + description: findElementOrNull(element, 'sceneDescription')?.text, + startTime: findElementOrNull(element, 'sceneStartTime')?.text, + endTime: findElementOrNull(element, 'sceneEndTime')?.text, ); } } diff --git a/lib/domain/media/star_rating.dart b/lib/domain/media/star_rating.dart index 9fc456b..9348a5a 100644 --- a/lib/domain/media/star_rating.dart +++ b/lib/domain/media/star_rating.dart @@ -15,10 +15,10 @@ class StarRating { 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 d30b025..01ade1e 100644 --- a/lib/domain/media/statistics.dart +++ b/lib/domain/media/statistics.dart @@ -11,8 +11,8 @@ class Statistics { 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 17200ac..a5f0b15 100644 --- a/lib/domain/media/status.dart +++ b/lib/domain/media/status.dart @@ -14,8 +14,8 @@ class Status { return null; } return Status( - state: element.getAttribute("state"), - reason: element.getAttribute("reason"), + state: element.getAttribute('state'), + reason: element.getAttribute('reason'), ); } } diff --git a/lib/domain/media/tags.dart b/lib/domain/media/tags.dart index 3617a0a..b3f747d 100644 --- a/lib/domain/media/tags.dart +++ b/lib/domain/media/tags.dart @@ -15,7 +15,7 @@ class Tags { } return Tags( tags: element.text, - weight: int.tryParse(element.getAttribute("weight") ?? "1"), + weight: int.tryParse(element.getAttribute('weight') ?? '1'), ); } } diff --git a/lib/domain/media/text.dart b/lib/domain/media/text.dart index 702e934..58e8d21 100644 --- a/lib/domain/media/text.dart +++ b/lib/domain/media/text.dart @@ -20,10 +20,10 @@ class Text { return null; } return Text( - type: element.getAttribute("type"), - lang: element.getAttribute("lang"), - start: element.getAttribute("start"), - end: element.getAttribute("end"), + type: element.getAttribute('type'), + lang: element.getAttribute('lang'), + start: element.getAttribute('start'), + end: element.getAttribute('end'), value: element.text, ); } diff --git a/lib/domain/media/thumbnail.dart b/lib/domain/media/thumbnail.dart index 0c3f31c..85d81e7 100644 --- a/lib/domain/media/thumbnail.dart +++ b/lib/domain/media/thumbnail.dart @@ -15,10 +15,10 @@ class Thumbnail { factory Thumbnail.parse(XmlElement element) { return Thumbnail( - url: element.getAttribute("url"), - width: element.getAttribute("width"), - height: element.getAttribute("height"), - time: element.getAttribute("time"), + url: element.getAttribute('url'), + width: element.getAttribute('width'), + height: element.getAttribute('height'), + time: element.getAttribute('time'), ); } } diff --git a/lib/domain/media/title.dart b/lib/domain/media/title.dart index 49482d6..9968bce 100644 --- a/lib/domain/media/title.dart +++ b/lib/domain/media/title.dart @@ -14,7 +14,7 @@ class Title { return null; } return Title( - type: element.getAttribute("type"), + type: element.getAttribute('type'), value: element.text, ); } diff --git a/lib/domain/rss_category.dart b/lib/domain/rss_category.dart index 845a837..a3ca7d7 100644 --- a/lib/domain/rss_category.dart +++ b/lib/domain/rss_category.dart @@ -10,7 +10,7 @@ class RssCategory { if (element == null) { return null; } - var domain = element.getAttribute("domain"); + var domain = element.getAttribute('domain'); var value = element.text; return RssCategory(domain, value); diff --git a/lib/domain/rss_cloud.dart b/lib/domain/rss_cloud.dart index 74d8b6a..73f3c32 100644 --- a/lib/domain/rss_cloud.dart +++ b/lib/domain/rss_cloud.dart @@ -19,11 +19,11 @@ class RssCloud { if (node == null) { return null; } - var domain = node.getAttribute("domain"); - var port = node.getAttribute("port"); - var path = node.getAttribute("path"); - var registerProcedure = node.getAttribute("registerProcedure"); - var protocol = node.getAttribute("protocol"); + var domain = node.getAttribute('domain'); + var port = node.getAttribute('port'); + var path = node.getAttribute('path'); + var registerProcedure = node.getAttribute('registerProcedure'); + var protocol = node.getAttribute('protocol'); return RssCloud(domain, port, path, registerProcedure, protocol); } } diff --git a/lib/domain/rss_enclosure.dart b/lib/domain/rss_enclosure.dart index 4b125e2..dd303c7 100644 --- a/lib/domain/rss_enclosure.dart +++ b/lib/domain/rss_enclosure.dart @@ -11,9 +11,9 @@ class RssEnclosure { if (element == null) { return null; } - var url = element.getAttribute("url"); - var type = element.getAttribute("type"); - var length = int.tryParse(element.getAttribute("length") ?? "0"); + var url = element.getAttribute('url'); + var type = element.getAttribute('type'); + var length = int.tryParse(element.getAttribute('length') ?? '0'); return RssEnclosure(url, type, length); } } diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 880f8e3..2235fe4 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -62,45 +62,45 @@ class RssFeed { var document = XmlDocument.parse(xmlString); XmlElement channelElement; try { - channelElement = document.findAllElements("channel").first; + channelElement = document.findAllElements('channel').first; } on StateError { - throw ArgumentError("channel not found"); + throw ArgumentError('channel not found'); } return RssFeed( - title: findElementOrNull(channelElement, "title")?.text, - author: findElementOrNull(channelElement, "author")?.text, - description: findElementOrNull(channelElement, "description")?.text, - link: findElementOrNull(channelElement, "link")?.text, - items: channelElement.findElements("item").map((element) { + title: findElementOrNull(channelElement, 'title')?.text, + author: findElementOrNull(channelElement, 'author')?.text, + description: findElementOrNull(channelElement, 'description')?.text, + link: findElementOrNull(channelElement, 'link')?.text, + items: channelElement.findElements('item').map((element) { return RssItem.parse(element); }).toList(), - image: RssImage.parse(findElementOrNull(channelElement, "image")), - cloud: RssCloud.parse(findElementOrNull(channelElement, "cloud")), - categories: channelElement.findElements("category").map((element) { + image: RssImage.parse(findElementOrNull(channelElement, 'image')), + cloud: RssCloud.parse(findElementOrNull(channelElement, 'cloud')), + categories: channelElement.findElements('category').map((element) { return RssCategory.parse(element); }).toList(), - skipDays: findElementOrNull(channelElement, "skipDays") - ?.findAllElements("day") + skipDays: findElementOrNull(channelElement, 'skipDays') + ?.findAllElements('day') ?.map((element) { return element.text; })?.toList() ?? [], - skipHours: findElementOrNull(channelElement, "skipHours") - ?.findAllElements("hour") + skipHours: findElementOrNull(channelElement, 'skipHours') + ?.findAllElements('hour') ?.map((element) { - return int.tryParse(element.text ?? "0"); + return int.tryParse(element.text ?? '0'); })?.toList() ?? [], - lastBuildDate: findElementOrNull(channelElement, "lastBuildDate")?.text, - language: findElementOrNull(channelElement, "language")?.text, - generator: findElementOrNull(channelElement, "generator")?.text, - copyright: findElementOrNull(channelElement, "copyright")?.text, - docs: findElementOrNull(channelElement, "docs")?.text, - managingEditor: findElementOrNull(channelElement, "managingEditor")?.text, - rating: findElementOrNull(channelElement, "rating")?.text, - webMaster: findElementOrNull(channelElement, "webMaster")?.text, - ttl: int.tryParse(findElementOrNull(channelElement, "ttl")?.text ?? "0"), + lastBuildDate: findElementOrNull(channelElement, 'lastBuildDate')?.text, + language: findElementOrNull(channelElement, 'language')?.text, + generator: findElementOrNull(channelElement, 'generator')?.text, + copyright: findElementOrNull(channelElement, 'copyright')?.text, + docs: findElementOrNull(channelElement, 'docs')?.text, + managingEditor: findElementOrNull(channelElement, 'managingEditor')?.text, + rating: findElementOrNull(channelElement, 'rating')?.text, + webMaster: findElementOrNull(channelElement, 'webMaster')?.text, + ttl: int.tryParse(findElementOrNull(channelElement, 'ttl')?.text ?? '0'), dc: DublinCore.parse(channelElement), itunes: RssItunes.parse(channelElement), ); diff --git a/lib/domain/rss_image.dart b/lib/domain/rss_image.dart index 447b628..9ed4e33 100644 --- a/lib/domain/rss_image.dart +++ b/lib/domain/rss_image.dart @@ -12,9 +12,9 @@ class RssImage { if (element == null) { return null; } - var title = findElementOrNull(element, "title")?.text; - var url = findElementOrNull(element, "url")?.text; - var link = findElementOrNull(element, "link")?.text; + var title = findElementOrNull(element, 'title')?.text; + var url = findElementOrNull(element, 'url')?.text; + var link = findElementOrNull(element, 'link')?.text; return RssImage(title, url, link); } diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index edecd9b..534399e 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -45,20 +45,20 @@ class RssItem { factory RssItem.parse(XmlElement element) { return RssItem( - title: findElementOrNull(element, "title")?.text, - description: findElementOrNull(element, "description")?.text, - link: findElementOrNull(element, "link")?.text, - categories: element.findElements("category").map((element) { + title: findElementOrNull(element, 'title')?.text, + description: findElementOrNull(element, 'description')?.text, + link: findElementOrNull(element, 'link')?.text, + categories: element.findElements('category').map((element) { return RssCategory.parse(element); }).toList(), - guid: findElementOrNull(element, "guid")?.text, - pubDate: parseDateTime(findElementOrNull(element, "pubDate")?.text), - author: findElementOrNull(element, "author")?.text, - comments: findElementOrNull(element, "comments")?.text, - source: RssSource.parse(findElementOrNull(element, "source")), - content: RssContent.parse(findElementOrNull(element, "content:encoded")), + guid: findElementOrNull(element, 'guid')?.text, + pubDate: parseDateTime(findElementOrNull(element, 'pubDate')?.text), + author: findElementOrNull(element, 'author')?.text, + comments: findElementOrNull(element, 'comments')?.text, + source: RssSource.parse(findElementOrNull(element, 'source')), + content: RssContent.parse(findElementOrNull(element, 'content:encoded')), media: Media.parse(element), - enclosure: RssEnclosure.parse(findElementOrNull(element, "enclosure")), + enclosure: RssEnclosure.parse(findElementOrNull(element, 'enclosure')), dc: DublinCore.parse(element), itunes: RssItemItunes.parse(element), ); diff --git a/lib/domain/rss_item_itunes.dart b/lib/domain/rss_item_itunes.dart index 19f1c12..0c94044 100644 --- a/lib/domain/rss_item_itunes.dart +++ b/lib/domain/rss_item_itunes.dart @@ -40,31 +40,31 @@ class RssItemItunes { if (element == null) { return null; } - var episodeStr = findElementOrNull(element, "itunes:episode")?.text?.trim(); - var seasonStr = findElementOrNull(element, "itunes:season")?.text?.trim(); + var episodeStr = findElementOrNull(element, 'itunes:episode')?.text?.trim(); + var seasonStr = findElementOrNull(element, 'itunes:season')?.text?.trim(); var durationStr = - findElementOrNull(element, "itunes:duration")?.text?.trim(); + findElementOrNull(element, 'itunes:duration')?.text?.trim(); return RssItemItunes( - title: findElementOrNull(element, "itunes:title")?.text?.trim(), + title: findElementOrNull(element, 'itunes:title')?.text?.trim(), episode: episodeStr == null ? null : int.parse(episodeStr), season: seasonStr == null ? null : int.parse(seasonStr), duration: durationStr == null ? null : parseDuration(durationStr), episodeType: newRssItunesEpisodeType( - findElementOrNull(element, "itunes:episodeType")), - author: findElementOrNull(element, "itunes:author")?.text?.trim(), - summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), - explicit: parseBoolLiteral(element, "itunes:explicit"), - subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), - keywords: findElementOrNull(element, "itunes:keywords") + findElementOrNull(element, 'itunes:episodeType')), + author: findElementOrNull(element, 'itunes:author')?.text?.trim(), + summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), + explicit: parseBoolLiteral(element, 'itunes:explicit'), + subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), + keywords: findElementOrNull(element, 'itunes:keywords') ?.text - ?.split(",") + ?.split(',') ?.map((keyword) => keyword.trim()) ?.toList(), - image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), + image: RssItunesImage.parse(findElementOrNull(element, 'itunes:image')), category: RssItunesCategory.parse( - findElementOrNull(element, "itunes:category")), - block: parseBoolLiteral(element, "itunes:block"), + findElementOrNull(element, 'itunes:category')), + block: parseBoolLiteral(element, 'itunes:block'), ); } } diff --git a/lib/domain/rss_itunes.dart b/lib/domain/rss_itunes.dart index e4e7685..af0b9e9 100644 --- a/lib/domain/rss_itunes.dart +++ b/lib/domain/rss_itunes.dart @@ -42,26 +42,26 @@ class RssItunes { return null; } return RssItunes( - author: findElementOrNull(element, "itunes:author")?.text?.trim(), - summary: findElementOrNull(element, "itunes:summary")?.text?.trim(), - explicit: parseBoolLiteral(element, "itunes:explicit"), - title: findElementOrNull(element, "itunes:title")?.text?.trim(), - subtitle: findElementOrNull(element, "itunes:subtitle")?.text?.trim(), - owner: RssItunesOwner.parse(findElementOrNull(element, "itunes:owner")), - keywords: findElementOrNull(element, "itunes:keywords") + author: findElementOrNull(element, 'itunes:author')?.text?.trim(), + summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), + explicit: parseBoolLiteral(element, 'itunes:explicit'), + title: findElementOrNull(element, 'itunes:title')?.text?.trim(), + subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), + owner: RssItunesOwner.parse(findElementOrNull(element, 'itunes:owner')), + keywords: findElementOrNull(element, 'itunes:keywords') ?.text - ?.split(",") + ?.split(',') ?.map((keyword) => keyword.trim()) ?.toList(), - image: RssItunesImage.parse(findElementOrNull(element, "itunes:image")), - categories: findAllDirectElementsOrNull(element, "itunes:category") + image: RssItunesImage.parse(findElementOrNull(element, 'itunes:image')), + categories: findAllDirectElementsOrNull(element, 'itunes:category') .map((ele) => RssItunesCategory.parse(ele)) .toList(), - type: newRssItunesType(findElementOrNull(element, "itunes:type")), + type: newRssItunesType(findElementOrNull(element, 'itunes:type')), newFeedUrl: - findElementOrNull(element, "itunes:new-feed-url")?.text?.trim(), - block: parseBoolLiteral(element, "itunes:block"), - complete: parseBoolLiteral(element, "itunes:complete"), + findElementOrNull(element, 'itunes:new-feed-url')?.text?.trim(), + block: parseBoolLiteral(element, 'itunes:block'), + complete: parseBoolLiteral(element, 'itunes:complete'), ); } } diff --git a/lib/domain/rss_itunes_category.dart b/lib/domain/rss_itunes_category.dart index b79f339..f6b7334 100644 --- a/lib/domain/rss_itunes_category.dart +++ b/lib/domain/rss_itunes_category.dart @@ -11,14 +11,15 @@ class RssItunesCategory { Iterable subCategories; try { - subCategories = element.findElements("itunes:category"); + subCategories = element.findElements('itunes:category'); } on StateError { subCategories = null; } return RssItunesCategory( - category: element.getAttribute("text")?.trim(), - subCategories: - subCategories?.map((ele) => ele.getAttribute("text")?.trim())?.toList(), + category: element.getAttribute('text')?.trim(), + subCategories: subCategories + ?.map((ele) => ele.getAttribute('text')?.trim()) + ?.toList(), ); } } diff --git a/lib/domain/rss_itunes_episode_type.dart b/lib/domain/rss_itunes_episode_type.dart index 30e639d..ffbf960 100644 --- a/lib/domain/rss_itunes_episode_type.dart +++ b/lib/domain/rss_itunes_episode_type.dart @@ -1,17 +1,17 @@ import 'package:xml/xml.dart'; -enum RssItunesEpisodeType {full, trailer, bonus} +enum RssItunesEpisodeType { full, trailer, bonus } RssItunesEpisodeType newRssItunesEpisodeType(XmlElement element) { // "full" is default type if (element == null) return RssItunesEpisodeType.full; switch (element.text) { - case "full": + case 'full': return RssItunesEpisodeType.full; - case "trailer": + case 'trailer': return RssItunesEpisodeType.trailer; - case "bonus": + case 'bonus': return RssItunesEpisodeType.bonus; default: return null; diff --git a/lib/domain/rss_itunes_image.dart b/lib/domain/rss_itunes_image.dart index 7b2ef2f..8328979 100644 --- a/lib/domain/rss_itunes_image.dart +++ b/lib/domain/rss_itunes_image.dart @@ -8,7 +8,7 @@ class RssItunesImage { factory RssItunesImage.parse(XmlElement element) { if (element == null) return null; return RssItunesImage( - href: element.getAttribute("href")?.trim(), + href: element.getAttribute('href')?.trim(), ); } } diff --git a/lib/domain/rss_itunes_owner.dart b/lib/domain/rss_itunes_owner.dart index 2d72294..e0bc605 100644 --- a/lib/domain/rss_itunes_owner.dart +++ b/lib/domain/rss_itunes_owner.dart @@ -11,8 +11,8 @@ class RssItunesOwner { factory RssItunesOwner.parse(XmlElement element) { if (element == null) return null; return RssItunesOwner( - name: findElementOrNull(element, "itunes:name")?.text?.trim(), - email: findElementOrNull(element, "itunes:email")?.text?.trim(), + name: findElementOrNull(element, 'itunes:name')?.text?.trim(), + email: findElementOrNull(element, 'itunes:email')?.text?.trim(), ); } } diff --git a/lib/domain/rss_itunes_type.dart b/lib/domain/rss_itunes_type.dart index b2cb031..b5c846f 100644 --- a/lib/domain/rss_itunes_type.dart +++ b/lib/domain/rss_itunes_type.dart @@ -3,13 +3,13 @@ import 'package:xml/xml.dart'; enum RssItunesType { episodic, serial } RssItunesType newRssItunesType(XmlElement element) { - // "episodic" is default type + // 'episodic' is default type if (element == null) return RssItunesType.episodic; switch (element.text) { - case "episodic": + case 'episodic': return RssItunesType.episodic; - case "serial": + case 'serial': return RssItunesType.serial; default: return null; diff --git a/lib/domain/rss_source.dart b/lib/domain/rss_source.dart index 6d82be8..056fe7b 100644 --- a/lib/domain/rss_source.dart +++ b/lib/domain/rss_source.dart @@ -10,7 +10,7 @@ class RssSource { if (element == null) { return null; } - var url = element.getAttribute("url"); + var url = element.getAttribute('url'); var value = element.text; return RssSource(url, value); diff --git a/lib/util/xml.dart b/lib/util/xml.dart index 179926c..113a8c1 100644 --- a/lib/util/xml.dart +++ b/lib/util/xml.dart @@ -23,6 +23,5 @@ List findAllDirectElementsOrNull(XmlElement element, String name, bool parseBoolLiteral(XmlElement element, String tagName) { var v = findElementOrNull(element, tagName)?.text?.toLowerCase()?.trim(); if (v == null) return null; - return ["yes", "true"].contains(v); + return ['yes', 'true'].contains(v); } - diff --git a/test/atom_test.dart b/test/atom_test.dart index f3b9c12..1cd24fc 100644 --- a/test/atom_test.dart +++ b/test/atom_test.dart @@ -5,95 +5,95 @@ import 'package:test/test.dart'; import 'package:webfeed/webfeed.dart'; void main() { - test("parse Invalid.xml", () { - var xmlString = File("test/xml/Invalid.xml").readAsStringSync(); + test('parse Invalid.xml', () { + var xmlString = File('test/xml/Invalid.xml').readAsStringSync(); try { AtomFeed.parse(xmlString); - fail("Should throw Argument Error"); + fail('Should throw Argument Error'); } on ArgumentError {} }); - test("parse Atom.xml", () { - var xmlString = File("test/xml/Atom.xml").readAsStringSync(); + test('parse Atom.xml', () { + var xmlString = File('test/xml/Atom.xml').readAsStringSync(); var feed = AtomFeed.parse(xmlString); - expect(feed.id, "foo-bar-id"); - expect(feed.title, "Foo bar news"); + expect(feed.id, 'foo-bar-id'); + expect(feed.title, 'Foo bar news'); expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); expect(feed.links.length, 2); - expect(feed.links.first.rel, "foo"); - expect(feed.links.first.type, "text/html"); - expect(feed.links.first.hreflang, "en"); - expect(feed.links.first.href, "http://foo.bar.news/"); - expect(feed.links.first.title, "Foo bar news html"); + expect(feed.links.first.rel, 'foo'); + expect(feed.links.first.type, 'text/html'); + expect(feed.links.first.hreflang, 'en'); + expect(feed.links.first.href, 'http://foo.bar.news/'); + expect(feed.links.first.title, 'Foo bar news html'); expect(feed.links.first.length, 1000); expect(feed.authors.length, 2); - expect(feed.authors.first.name, "Alice"); - expect(feed.authors.first.uri, "http://foo.bar.news/people/alice"); - expect(feed.authors.first.email, "alice@foo.bar.news"); + expect(feed.authors.first.name, 'Alice'); + expect(feed.authors.first.uri, 'http://foo.bar.news/people/alice'); + expect(feed.authors.first.email, 'alice@foo.bar.news'); expect(feed.contributors.length, 2); - expect(feed.contributors.first.name, "Charlie"); - expect(feed.contributors.first.uri, "http://foo.bar.news/people/charlie"); - expect(feed.contributors.first.email, "charlie@foo.bar.news"); + expect(feed.contributors.first.name, 'Charlie'); + expect(feed.contributors.first.uri, 'http://foo.bar.news/people/charlie'); + expect(feed.contributors.first.email, 'charlie@foo.bar.news'); expect(feed.categories.length, 2); - expect(feed.categories.first.term, "foo category"); - expect(feed.categories.first.scheme, "this-is-foo-scheme"); - expect(feed.categories.first.label, "this is foo label"); + expect(feed.categories.first.term, 'foo category'); + expect(feed.categories.first.scheme, 'this-is-foo-scheme'); + expect(feed.categories.first.label, 'this is foo label'); - expect(feed.generator.uri, "http://foo.bar.news/generator"); - expect(feed.generator.version, "1.0"); - expect(feed.generator.value, "Foo bar generator"); + expect(feed.generator.uri, 'http://foo.bar.news/generator'); + expect(feed.generator.version, '1.0'); + expect(feed.generator.value, 'Foo bar generator'); - expect(feed.icon, "http://foo.bar.news/icon.png"); - expect(feed.logo, "http://foo.bar.news/logo.png"); - expect(feed.subtitle, "This is subtitle"); + expect(feed.icon, 'http://foo.bar.news/icon.png'); + expect(feed.logo, 'http://foo.bar.news/logo.png'); + expect(feed.subtitle, 'This is subtitle'); expect(feed.items.length, 2); var item = feed.items.first; - expect(item.id, "foo-bar-entry-id-1"); - expect(item.title, "Foo bar item 1"); + expect(item.id, 'foo-bar-entry-id-1'); + expect(item.title, 'Foo bar item 1'); expect(item.updated, DateTime.utc(2018, 4, 6, 13, 2, 40)); expect(item.authors.length, 2); - expect(item.authors.first.name, "Ellie"); - expect(item.authors.first.uri, "http://foo.bar.news/people/ellie"); - expect(item.authors.first.email, "ellie@foo.bar.news"); + expect(item.authors.first.name, 'Ellie'); + expect(item.authors.first.uri, 'http://foo.bar.news/people/ellie'); + expect(item.authors.first.email, 'ellie@foo.bar.news'); expect(item.links.length, 2); - expect(item.links.first.rel, "foo entry"); - expect(item.links.first.type, "text/html"); - expect(item.links.first.hreflang, "en"); - expect(item.links.first.href, "http://foo.bar.news/entry"); - expect(item.links.first.title, "Foo bar news html"); + expect(item.links.first.rel, 'foo entry'); + expect(item.links.first.type, 'text/html'); + expect(item.links.first.hreflang, 'en'); + expect(item.links.first.href, 'http://foo.bar.news/entry'); + expect(item.links.first.title, 'Foo bar news html'); expect(item.links.first.length, 1000); expect(item.categories.length, 2); - expect(item.categories.first.term, "foo entry category"); - expect(item.categories.first.scheme, "this-is-foo-entry-scheme"); - expect(item.categories.first.label, "this is foo entry label"); + expect(item.categories.first.term, 'foo entry category'); + expect(item.categories.first.scheme, 'this-is-foo-entry-scheme'); + expect(item.categories.first.label, 'this is foo entry label'); expect(item.contributors.length, 2); - expect(item.contributors.first.name, "Gin"); - expect(item.contributors.first.uri, "http://foo.bar.news/people/gin"); - expect(item.contributors.first.email, "gin@foo.bar.news"); - - expect(item.published, "2018-04-06T13:02:49Z"); - expect(item.summary, "This is summary 1"); - expect(item.content, "This is content 1"); - expect(item.rights, "This is rights 1"); + expect(item.contributors.first.name, 'Gin'); + expect(item.contributors.first.uri, 'http://foo.bar.news/people/gin'); + expect(item.contributors.first.email, 'gin@foo.bar.news'); + + expect(item.published, '2018-04-06T13:02:49Z'); + expect(item.summary, 'This is summary 1'); + expect(item.content, 'This is content 1'); + expect(item.rights, 'This is rights 1'); }); - test("parse Atom-Media.xml", () { - var xmlString = File("test/xml/Atom-Media.xml").readAsStringSync(); + test('parse Atom-Media.xml', () { + var xmlString = File('test/xml/Atom-Media.xml').readAsStringSync(); var feed = AtomFeed.parse(xmlString); - expect(feed.id, "foo-bar-id"); - expect(feed.title, "Foo bar news"); + expect(feed.id, 'foo-bar-id'); + expect(feed.title, 'Foo bar news'); expect(feed.updated, DateTime.utc(2018, 4, 6, 13, 2, 46)); expect(feed.items.length, 1); @@ -101,17 +101,17 @@ void main() { var item = feed.items.first; expect(item.media.group.contents.length, 5); expect(item.media.group.credits.length, 2); - expect(item.media.group.category.value, "music/artist name/album/song"); - expect(item.media.group.rating.value, "nonadult"); + expect(item.media.group.category.value, 'music/artist name/album/song'); + expect(item.media.group.rating.value, 'nonadult'); expect(item.media.contents.length, 2); var mediaContent = item.media.contents.first; - expect(mediaContent.url, "http://www.foo.com/video.mov"); - expect(mediaContent.type, "video/quicktime"); + expect(mediaContent.url, 'http://www.foo.com/video.mov'); + expect(mediaContent.type, 'video/quicktime'); expect(mediaContent.fileSize, 2000); - expect(mediaContent.medium, "video"); + expect(mediaContent.medium, 'video'); expect(mediaContent.isDefault, true); - expect(mediaContent.expression, "full"); + expect(mediaContent.expression, 'full'); expect(mediaContent.bitrate, 128); expect(mediaContent.framerate, 25); expect(mediaContent.samplingrate, 44.1); @@ -119,54 +119,54 @@ void main() { expect(item.media.credits.length, 2); var mediaCredit = item.media.credits.first; - expect(mediaCredit.role, "owner1"); - expect(mediaCredit.scheme, "urn:yvs"); - expect(mediaCredit.value, "copyright holder of the entity"); + expect(mediaCredit.role, 'owner1'); + expect(mediaCredit.scheme, 'urn:yvs'); + expect(mediaCredit.value, 'copyright holder of the entity'); expect(item.media.category.scheme, - "http://search.yahoo.com/mrss/category_ schema"); - expect(item.media.category.label, "Music"); - expect(item.media.category.value, "music/artist/album/song"); + 'http://search.yahoo.com/mrss/category_ schema'); + expect(item.media.category.label, 'Music'); + expect(item.media.category.value, 'music/artist/album/song'); - expect(item.media.rating.scheme, "urn:simple"); - expect(item.media.rating.value, "adult"); + expect(item.media.rating.scheme, 'urn:simple'); + expect(item.media.rating.value, 'adult'); - expect(item.media.title.type, "plain"); + expect(item.media.title.type, 'plain'); expect(item.media.title.value, "The Judy's -- The Moo Song"); - expect(item.media.description.type, "plain"); + expect(item.media.description.type, 'plain'); expect(item.media.description.value, - "This was some really bizarre band I listened to as a young lad."); + 'This was some really bizarre band I listened to as a young lad.'); - expect(item.media.keywords, "kitty, cat, big dog, yarn, fluffy"); + expect(item.media.keywords, 'kitty, cat, big dog, yarn, fluffy'); expect(item.media.thumbnails.length, 2); var mediaThumbnail = item.media.thumbnails.first; - expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); - expect(mediaThumbnail.width, "75"); - expect(mediaThumbnail.height, "50"); - expect(mediaThumbnail.time, "12:05:01.123"); + expect(mediaThumbnail.url, 'http://www.foo.com/keyframe1.jpg'); + expect(mediaThumbnail.width, '75'); + expect(mediaThumbnail.height, '50'); + expect(mediaThumbnail.time, '12:05:01.123'); - expect(item.media.hash.algo, "md5"); - expect(item.media.hash.value, "dfdec888b72151965a34b4b59031290a"); + expect(item.media.hash.algo, 'md5'); + expect(item.media.hash.value, 'dfdec888b72151965a34b4b59031290a'); - expect(item.media.player.url, "http://www.foo.com/player?id=1111"); + expect(item.media.player.url, 'http://www.foo.com/player?id=1111'); expect(item.media.player.width, 400); expect(item.media.player.height, 200); - expect(item.media.player.value, ""); + expect(item.media.player.value, ''); - expect(item.media.copyright.url, "http://blah.com/additional-info.html"); - expect(item.media.copyright.value, "2005 FooBar Media"); + expect(item.media.copyright.url, 'http://blah.com/additional-info.html'); + expect(item.media.copyright.value, '2005 FooBar Media'); - expect(item.media.text.type, "plain"); - expect(item.media.text.lang, "en"); - expect(item.media.text.start, "00:00:03.000"); - expect(item.media.text.end, "00:00:10.000"); - expect(item.media.text.value, " Oh, say, can you see"); + expect(item.media.text.type, 'plain'); + expect(item.media.text.lang, 'en'); + expect(item.media.text.start, '00:00:03.000'); + expect(item.media.text.end, '00:00:10.000'); + expect(item.media.text.value, ' Oh, say, can you see'); - expect(item.media.restriction.relationship, "allow"); - expect(item.media.restriction.type, "country"); - expect(item.media.restriction.value, "au us"); + expect(item.media.restriction.relationship, 'allow'); + expect(item.media.restriction.type, 'country'); + expect(item.media.restriction.value, 'au us'); expect(item.media.community.starRating.average, 3.5); expect(item.media.community.starRating.count, 20); @@ -174,58 +174,58 @@ void main() { expect(item.media.community.starRating.max, 10); expect(item.media.community.statistics.views, 5); expect(item.media.community.statistics.favorites, 4); - expect(item.media.community.tags.tags, "news: 5, abc:3"); + expect(item.media.community.tags.tags, 'news: 5, abc:3'); expect(item.media.community.tags.weight, 1); expect(item.media.comments.length, 2); - expect(item.media.comments.first, "comment1"); - expect(item.media.comments.last, "comment2"); + expect(item.media.comments.first, 'comment1'); + expect(item.media.comments.last, 'comment2'); - expect(item.media.embed.url, "http://www.foo.com/player.swf"); + expect(item.media.embed.url, 'http://www.foo.com/player.swf'); expect(item.media.embed.width, 512); expect(item.media.embed.height, 323); expect(item.media.embed.params.length, 5); - expect(item.media.embed.params.first.name, "type"); + expect(item.media.embed.params.first.name, 'type'); expect( - item.media.embed.params.first.value, "application/x-shockwave-flash"); + item.media.embed.params.first.value, 'application/x-shockwave-flash'); expect(item.media.responses.length, 2); - expect(item.media.responses.first, "http://www.response1.com"); - expect(item.media.responses.last, "http://www.response2.com"); + expect(item.media.responses.first, 'http://www.response1.com'); + expect(item.media.responses.last, 'http://www.response2.com'); expect(item.media.backLinks.length, 2); - expect(item.media.backLinks.first, "http://www.backlink1.com"); - expect(item.media.backLinks.last, "http://www.backlink2.com"); + expect(item.media.backLinks.first, 'http://www.backlink1.com'); + expect(item.media.backLinks.last, 'http://www.backlink2.com'); - expect(item.media.status.state, "active"); + expect(item.media.status.state, 'active'); expect(item.media.status.reason, null); expect(item.media.prices.length, 2); expect(item.media.prices.first.price, 19.99); - expect(item.media.prices.first.type, "rent"); + expect(item.media.prices.first.type, 'rent'); expect( - item.media.prices.first.info, "http://www.dummy.jp/package_info.html"); - expect(item.media.prices.first.currency, "EUR"); + item.media.prices.first.info, 'http://www.dummy.jp/package_info.html'); + expect(item.media.prices.first.currency, 'EUR'); - expect(item.media.license.type, "text/html"); - expect(item.media.license.href, "http://www.licensehost.com/license"); - expect(item.media.license.value, " Sample license for a video"); + expect(item.media.license.type, 'text/html'); + expect(item.media.license.href, 'http://www.licensehost.com/license'); + expect(item.media.license.value, ' Sample license for a video'); - expect(item.media.peerLink.type, "application/x-bittorrent"); - expect(item.media.peerLink.href, "http://www.foo.org/sampleFile.torrent"); - expect(item.media.peerLink.value, ""); + expect(item.media.peerLink.type, 'application/x-bittorrent'); + expect(item.media.peerLink.href, 'http://www.foo.org/sampleFile.torrent'); + expect(item.media.peerLink.value, ''); - expect(item.media.rights.status, "official"); + expect(item.media.rights.status, 'official'); expect(item.media.scenes.length, 2); - expect(item.media.scenes.first.title, "sceneTitle1"); - expect(item.media.scenes.first.description, "sceneDesc1"); - expect(item.media.scenes.first.startTime, "00:15"); - expect(item.media.scenes.first.endTime, "00:45"); + expect(item.media.scenes.first.title, 'sceneTitle1'); + expect(item.media.scenes.first.description, 'sceneDesc1'); + expect(item.media.scenes.first.startTime, '00:15'); + expect(item.media.scenes.first.endTime, '00:45'); }); - test("parse Atom-Empty.xml", () { - var xmlString = File("test/xml/Atom-Empty.xml").readAsStringSync(); + test('parse Atom-Empty.xml', () { + var xmlString = File('test/xml/Atom-Empty.xml').readAsStringSync(); var feed = AtomFeed.parse(xmlString); diff --git a/test/rss_test.dart b/test/rss_test.dart index 16fc91e..8fa729f 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -7,54 +7,54 @@ import 'package:webfeed/domain/rss_itunes_type.dart'; import 'package:webfeed/webfeed.dart'; void main() { - test("parse Invalid.xml", () { - var xmlString = File("test/xml/Invalid.xml").readAsStringSync(); + test('parse Invalid.xml', () { + var xmlString = File('test/xml/Invalid.xml').readAsStringSync(); try { RssFeed.parse(xmlString); - fail("Should throw Argument Error"); + fail('Should throw Argument Error'); } on ArgumentError {} }); - test("parse RSS.xml", () { - var xmlString = File("test/xml/RSS.xml").readAsStringSync(); + test('parse RSS.xml', () { + var xmlString = File('test/xml/RSS.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.title, "News - Foo bar News"); + expect(feed.title, 'News - Foo bar News'); expect(feed.description, - "Foo bar News and Updates feed provided by Foo bar, Inc."); - expect(feed.link, "https://foo.bar.news/"); - expect(feed.author, "hello@world.net"); - expect(feed.language, "en-US"); - expect(feed.lastBuildDate, "Mon, 26 Mar 2018 14:00:00 PDT"); - expect(feed.generator, "Custom"); - expect(feed.copyright, "Copyright 2018, Foo bar Inc."); - expect(feed.docs, "https://foo.bar.news/docs"); - expect(feed.managingEditor, "alice@foo.bar.news"); - expect(feed.rating, "The PICS rating of the feed"); - expect(feed.webMaster, "webmaster@foo.bar.news"); + 'Foo bar News and Updates feed provided by Foo bar, Inc.'); + expect(feed.link, 'https://foo.bar.news/'); + expect(feed.author, 'hello@world.net'); + expect(feed.language, 'en-US'); + expect(feed.lastBuildDate, 'Mon, 26 Mar 2018 14:00:00 PDT'); + expect(feed.generator, 'Custom'); + expect(feed.copyright, 'Copyright 2018, Foo bar Inc.'); + expect(feed.docs, 'https://foo.bar.news/docs'); + expect(feed.managingEditor, 'alice@foo.bar.news'); + expect(feed.rating, 'The PICS rating of the feed'); + expect(feed.webMaster, 'webmaster@foo.bar.news'); expect(feed.ttl, 60); - expect(feed.image.title, "Foo bar News"); - expect(feed.image.url, "https://foo.bar.news/logo.gif"); - expect(feed.image.link, "https://foo.bar.news/"); + expect(feed.image.title, 'Foo bar News'); + expect(feed.image.url, 'https://foo.bar.news/logo.gif'); + expect(feed.image.link, 'https://foo.bar.news/'); - expect(feed.cloud.domain, "radio.foo.bar.news"); - expect(feed.cloud.port, "80"); - expect(feed.cloud.path, "/RPC2"); - expect(feed.cloud.registerProcedure, "foo.bar.rssPleaseNotify"); - expect(feed.cloud.protocol, "xml-rpc"); + expect(feed.cloud.domain, 'radio.foo.bar.news'); + expect(feed.cloud.port, '80'); + expect(feed.cloud.path, '/RPC2'); + expect(feed.cloud.registerProcedure, 'foo.bar.rssPleaseNotify'); + expect(feed.cloud.protocol, 'xml-rpc'); expect(feed.categories.length, 2); expect(feed.categories[0].domain, null); - expect(feed.categories[0].value, "Ipsum"); - expect(feed.categories[1].domain, "news"); - expect(feed.categories[1].value, "Lorem Ipsum"); + expect(feed.categories[0].value, 'Ipsum'); + expect(feed.categories[1].domain, 'news'); + expect(feed.categories[1].value, 'Lorem Ipsum'); expect(feed.skipDays.length, 3); - expect(feed.skipDays.contains("Monday"), true); - expect(feed.skipDays.contains("Tuesday"), true); - expect(feed.skipDays.contains("Sunday"), true); + expect(feed.skipDays.contains('Monday'), true); + expect(feed.skipDays.contains('Tuesday'), true); + expect(feed.skipDays.contains('Sunday'), true); expect(feed.skipHours.length, 5); expect(feed.skipHours.contains(0), true); @@ -66,58 +66,58 @@ void main() { expect(feed.items.length, 2); expect(feed.items.first.title, - "The standard Lorem Ipsum passage, used since the 1500s"); + 'The standard Lorem Ipsum passage, used since the 1500s'); expect(feed.items.first.description, - "Lorem ipsum dolor sit amet, consectetur adipiscing elit"); - expect(feed.items.first.link, "https://foo.bar.news/1"); - expect(feed.items.first.guid, "https://foo.bar.news/1?guid"); + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit'); + expect(feed.items.first.link, 'https://foo.bar.news/1'); + expect(feed.items.first.guid, 'https://foo.bar.news/1?guid'); expect(feed.items.first.pubDate, DateTime(2018, 03, 26, 14)); //Mon, 26 Mar 2018 14:00:00 PDT - expect(feed.items.first.categories.first.domain, "news"); - expect(feed.items.first.categories.first.value, "Lorem"); - expect(feed.items.first.author, "alice@foo.bar.news"); - expect(feed.items.first.source.url, "https://foo.bar.news/1?source"); - expect(feed.items.first.source.value, "Foo Bar"); - expect(feed.items.first.comments, "https://foo.bar.news/1/comments"); + expect(feed.items.first.categories.first.domain, 'news'); + expect(feed.items.first.categories.first.value, 'Lorem'); + expect(feed.items.first.author, 'alice@foo.bar.news'); + expect(feed.items.first.source.url, 'https://foo.bar.news/1?source'); + expect(feed.items.first.source.value, 'Foo Bar'); + expect(feed.items.first.comments, 'https://foo.bar.news/1/comments'); expect(feed.items.first.enclosure.url, - "http://www.scripting.com/mp3s/weatherReportSuite.mp3"); + 'http://www.scripting.com/mp3s/weatherReportSuite.mp3'); expect(feed.items.first.enclosure.length, 12216320); - expect(feed.items.first.enclosure.type, "audio/mpeg"); + expect(feed.items.first.enclosure.type, 'audio/mpeg'); expect(feed.items.first.content.value, - " Test content
"); + ' Test content
'); expect( - feed.items.first.content.images.first, "https://test.com/image_link"); + feed.items.first.content.images.first, 'https://test.com/image_link'); }); - test("parse RSS-Media.xml", () { - var xmlString = File("test/xml/RSS-Media.xml").readAsStringSync(); + test('parse RSS-Media.xml', () { + var xmlString = File('test/xml/RSS-Media.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.title, "Song Site"); + expect(feed.title, 'Song Site'); expect( - feed.description, "Media RSS example with new fields added in v1.5.0"); + feed.description, 'Media RSS example with new fields added in v1.5.0'); expect(feed.items.length, 1); var item = feed.items.first; expect(item.title, null); - expect(item.link, "http://www.foo.com"); + expect(item.link, 'http://www.foo.com'); expect(item.pubDate, DateTime(2001, 08, 27, 16, 08, 56)); //Mon, 27 Aug 2001 16:08:56 PST expect(item.media.group.contents.length, 5); expect(item.media.group.credits.length, 2); - expect(item.media.group.category.value, "music/artist name/album/song"); - expect(item.media.group.rating.value, "nonadult"); + expect(item.media.group.category.value, 'music/artist name/album/song'); + expect(item.media.group.rating.value, 'nonadult'); expect(item.media.contents.length, 2); var mediaContent = item.media.contents.first; - expect(mediaContent.url, "http://www.foo.com/video.mov"); - expect(mediaContent.type, "video/quicktime"); + expect(mediaContent.url, 'http://www.foo.com/video.mov'); + expect(mediaContent.type, 'video/quicktime'); expect(mediaContent.fileSize, 2000); - expect(mediaContent.medium, "video"); + expect(mediaContent.medium, 'video'); expect(mediaContent.isDefault, true); - expect(mediaContent.expression, "full"); + expect(mediaContent.expression, 'full'); expect(mediaContent.bitrate, 128); expect(mediaContent.framerate, 25); expect(mediaContent.samplingrate, 44.1); @@ -125,54 +125,54 @@ void main() { expect(item.media.credits.length, 2); var mediaCredit = item.media.credits.first; - expect(mediaCredit.role, "owner1"); - expect(mediaCredit.scheme, "urn:yvs"); - expect(mediaCredit.value, "copyright holder of the entity"); + expect(mediaCredit.role, 'owner1'); + expect(mediaCredit.scheme, 'urn:yvs'); + expect(mediaCredit.value, 'copyright holder of the entity'); expect(item.media.category.scheme, - "http://search.yahoo.com/mrss/category_ schema"); - expect(item.media.category.label, "Music"); - expect(item.media.category.value, "music/artist/album/song"); + 'http://search.yahoo.com/mrss/category_ schema'); + expect(item.media.category.label, 'Music'); + expect(item.media.category.value, 'music/artist/album/song'); - expect(item.media.rating.scheme, "urn:simple"); - expect(item.media.rating.value, "adult"); + expect(item.media.rating.scheme, 'urn:simple'); + expect(item.media.rating.value, 'adult'); - expect(item.media.title.type, "plain"); + expect(item.media.title.type, 'plain'); expect(item.media.title.value, "The Judy's -- The Moo Song"); - expect(item.media.description.type, "plain"); + expect(item.media.description.type, 'plain'); expect(item.media.description.value, - "This was some really bizarre band I listened to as a young lad."); + 'This was some really bizarre band I listened to as a young lad.'); - expect(item.media.keywords, "kitty, cat, big dog, yarn, fluffy"); + expect(item.media.keywords, 'kitty, cat, big dog, yarn, fluffy'); expect(item.media.thumbnails.length, 2); var mediaThumbnail = item.media.thumbnails.first; - expect(mediaThumbnail.url, "http://www.foo.com/keyframe1.jpg"); - expect(mediaThumbnail.width, "75"); - expect(mediaThumbnail.height, "50"); - expect(mediaThumbnail.time, "12:05:01.123"); + expect(mediaThumbnail.url, 'http://www.foo.com/keyframe1.jpg'); + expect(mediaThumbnail.width, '75'); + expect(mediaThumbnail.height, '50'); + expect(mediaThumbnail.time, '12:05:01.123'); - expect(item.media.hash.algo, "md5"); - expect(item.media.hash.value, "dfdec888b72151965a34b4b59031290a"); + expect(item.media.hash.algo, 'md5'); + expect(item.media.hash.value, 'dfdec888b72151965a34b4b59031290a'); - expect(item.media.player.url, "http://www.foo.com/player?id=1111"); + expect(item.media.player.url, 'http://www.foo.com/player?id=1111'); expect(item.media.player.width, 400); expect(item.media.player.height, 200); - expect(item.media.player.value, ""); + expect(item.media.player.value, ''); - expect(item.media.copyright.url, "http://blah.com/additional-info.html"); - expect(item.media.copyright.value, "2005 FooBar Media"); + expect(item.media.copyright.url, 'http://blah.com/additional-info.html'); + expect(item.media.copyright.value, '2005 FooBar Media'); - expect(item.media.text.type, "plain"); - expect(item.media.text.lang, "en"); - expect(item.media.text.start, "00:00:03.000"); - expect(item.media.text.end, "00:00:10.000"); - expect(item.media.text.value, " Oh, say, can you see"); + expect(item.media.text.type, 'plain'); + expect(item.media.text.lang, 'en'); + expect(item.media.text.start, '00:00:03.000'); + expect(item.media.text.end, '00:00:10.000'); + expect(item.media.text.value, ' Oh, say, can you see'); - expect(item.media.restriction.relationship, "allow"); - expect(item.media.restriction.type, "country"); - expect(item.media.restriction.value, "au us"); + expect(item.media.restriction.relationship, 'allow'); + expect(item.media.restriction.type, 'country'); + expect(item.media.restriction.value, 'au us'); expect(item.media.community.starRating.average, 3.5); expect(item.media.community.starRating.count, 20); @@ -180,97 +180,97 @@ void main() { expect(item.media.community.starRating.max, 10); expect(item.media.community.statistics.views, 5); expect(item.media.community.statistics.favorites, 4); - expect(item.media.community.tags.tags, "news: 5, abc:3"); + expect(item.media.community.tags.tags, 'news: 5, abc:3'); expect(item.media.community.tags.weight, 1); expect(item.media.comments.length, 2); - expect(item.media.comments.first, "comment1"); - expect(item.media.comments.last, "comment2"); + expect(item.media.comments.first, 'comment1'); + expect(item.media.comments.last, 'comment2'); - expect(item.media.embed.url, "http://www.foo.com/player.swf"); + expect(item.media.embed.url, 'http://www.foo.com/player.swf'); expect(item.media.embed.width, 512); expect(item.media.embed.height, 323); expect(item.media.embed.params.length, 5); - expect(item.media.embed.params.first.name, "type"); + expect(item.media.embed.params.first.name, 'type'); expect( - item.media.embed.params.first.value, "application/x-shockwave-flash"); + item.media.embed.params.first.value, 'application/x-shockwave-flash'); expect(item.media.responses.length, 2); - expect(item.media.responses.first, "http://www.response1.com"); - expect(item.media.responses.last, "http://www.response2.com"); + expect(item.media.responses.first, 'http://www.response1.com'); + expect(item.media.responses.last, 'http://www.response2.com'); expect(item.media.backLinks.length, 2); - expect(item.media.backLinks.first, "http://www.backlink1.com"); - expect(item.media.backLinks.last, "http://www.backlink2.com"); + expect(item.media.backLinks.first, 'http://www.backlink1.com'); + expect(item.media.backLinks.last, 'http://www.backlink2.com'); - expect(item.media.status.state, "active"); + expect(item.media.status.state, 'active'); expect(item.media.status.reason, null); expect(item.media.prices.length, 2); expect(item.media.prices.first.price, 19.99); - expect(item.media.prices.first.type, "rent"); + expect(item.media.prices.first.type, 'rent'); expect( - item.media.prices.first.info, "http://www.dummy.jp/package_info.html"); - expect(item.media.prices.first.currency, "EUR"); + item.media.prices.first.info, 'http://www.dummy.jp/package_info.html'); + expect(item.media.prices.first.currency, 'EUR'); - expect(item.media.license.type, "text/html"); - expect(item.media.license.href, "http://www.licensehost.com/license"); - expect(item.media.license.value, " Sample license for a video"); + expect(item.media.license.type, 'text/html'); + expect(item.media.license.href, 'http://www.licensehost.com/license'); + expect(item.media.license.value, ' Sample license for a video'); - expect(item.media.peerLink.type, "application/x-bittorrent"); - expect(item.media.peerLink.href, "http://www.foo.org/sampleFile.torrent"); - expect(item.media.peerLink.value, ""); + expect(item.media.peerLink.type, 'application/x-bittorrent'); + expect(item.media.peerLink.href, 'http://www.foo.org/sampleFile.torrent'); + expect(item.media.peerLink.value, ''); - expect(item.media.rights.status, "official"); + expect(item.media.rights.status, 'official'); expect(item.media.scenes.length, 2); - expect(item.media.scenes.first.title, "sceneTitle1"); - expect(item.media.scenes.first.description, "sceneDesc1"); - expect(item.media.scenes.first.startTime, "00:15"); - expect(item.media.scenes.first.endTime, "00:45"); + expect(item.media.scenes.first.title, 'sceneTitle1'); + expect(item.media.scenes.first.description, 'sceneDesc1'); + expect(item.media.scenes.first.startTime, '00:15'); + expect(item.media.scenes.first.endTime, '00:45'); }); - test("parse RSS-DC.xml", () { - var xmlString = File("test/xml/RSS-DC.xml").readAsStringSync(); + test('parse RSS-DC.xml', () { + var xmlString = File('test/xml/RSS-DC.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.dc.title, "title"); - expect(feed.dc.creator, "creator"); - expect(feed.dc.subject, "subject"); - expect(feed.dc.description, "description"); - expect(feed.dc.publisher, "publisher"); - expect(feed.dc.contributor, "contributor"); + expect(feed.dc.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.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, 1, 12)); - 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.items.first.dc.type, 'type'); + expect(feed.items.first.dc.format, 'format'); + expect(feed.items.first.dc.identifier, 'identifier'); + expect(feed.items.first.dc.source, 'source'); + expect(feed.items.first.dc.language, 'language'); + expect(feed.items.first.dc.relation, 'relation'); + expect(feed.items.first.dc.coverage, 'coverage'); + expect(feed.items.first.dc.rights, 'rights'); }); - test("parse RSS-Empty.xml", () { - var xmlString = File("test/xml/RSS-Empty.xml").readAsStringSync(); + test('parse RSS-Empty.xml', () { + var xmlString = File('test/xml/RSS-Empty.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); @@ -313,39 +313,39 @@ void main() { expect(feed.items.first.content, null); }); - test("parse RSS-Itunes.xml", () { - var xmlString = File("test/xml/RSS-Itunes.xml").readAsStringSync(); + test('parse RSS-Itunes.xml', () { + var xmlString = File('test/xml/RSS-Itunes.xml').readAsStringSync(); var feed = RssFeed.parse(xmlString); - expect(feed.itunes.author, "Changelog Media"); - expect(feed.itunes.summary, "Foo"); + expect(feed.itunes.author, 'Changelog Media'); + expect(feed.itunes.summary, 'Foo'); expect(feed.itunes.explicit, false); expect(feed.itunes.image.href, - "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); + 'https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357'); expect(feed.itunes.keywords, - "go,golang,open source,software,development".split(",")); - expect(feed.itunes.owner.name, "Changelog Media"); - expect(feed.itunes.owner.email, "editors@changelog.com"); + 'go,golang,open source,software,development'.split(',')); + expect(feed.itunes.owner.name, 'Changelog Media'); + expect(feed.itunes.owner.email, 'editors@changelog.com'); expect( Set.from([ feed.itunes.categories[0].category, feed.itunes.categories[1].category ]), - ["Technology", "Foo"]); + ['Technology', 'Foo']); for (var category in feed.itunes.categories) { switch (category.category) { - case "Foo": - expect(category.subCategories, ["Bar", "Baz"]); + case 'Foo': + expect(category.subCategories, ['Bar', 'Baz']); break; - case "Technology": - expect(category.subCategories, ["Software How-To", "Tech News"]); + case 'Technology': + expect(category.subCategories, ['Software How-To', 'Tech News']); break; } } - expect(feed.itunes.title, "Go Time"); + expect(feed.itunes.title, 'Go Time'); expect(feed.itunes.type, RssItunesType.serial); - expect(feed.itunes.newFeedUrl, "wubawuba"); + expect(feed.itunes.newFeedUrl, 'wubawuba'); expect(feed.itunes.block, true); expect(feed.itunes.complete, true); @@ -354,17 +354,17 @@ void main() { expect(item.itunes.episode, 1); expect(item.itunes.season, 1); expect(item.itunes.image.href, - "https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357"); + 'https://cdn.changelog.com/uploads/covers/go-time-original.png?v=63725770357'); expect(item.itunes.duration, Duration(minutes: 32, seconds: 30)); expect(item.itunes.explicit, false); expect(item.itunes.keywords, - "go,golang,open source,software,development".split(",")); - expect(item.itunes.subtitle, "with Erik, Carlisia, and Brian"); - expect(item.itunes.summary, "Foo"); + 'go,golang,open source,software,development'.split(',')); + expect(item.itunes.subtitle, 'with Erik, Carlisia, and Brian'); + expect(item.itunes.summary, 'Foo'); expect(item.itunes.author, - "Erik St. Martin, Carlisia Pinto, and Brian Ketelsen"); + 'Erik St. Martin, Carlisia Pinto, and Brian Ketelsen'); expect(item.itunes.explicit, false); - expect(item.itunes.title, "awesome title"); + expect(item.itunes.title, 'awesome title'); expect(item.itunes.block, false); }); } From 9a843763fe7df79ecda0d1383f454616893d1e3d Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 02:55:54 +0700 Subject: [PATCH 12/22] refactor itunes --- lib/domain/itunes/itunes.dart | 103 ++++++++++++++++++ .../itunes_category.dart} | 8 +- lib/domain/itunes/itunes_episode_type.dart | 16 +++ .../itunes_image.dart} | 8 +- .../itunes_owner.dart} | 11 +- lib/domain/itunes/itunes_type.dart | 14 +++ lib/domain/rss_feed.dart | 7 +- lib/domain/rss_item.dart | 6 +- lib/domain/rss_item_itunes.dart | 89 --------------- lib/domain/rss_itunes.dart | 67 ------------ lib/domain/rss_itunes_episode_type.dart | 19 ---- lib/domain/rss_itunes_type.dart | 17 --- lib/util/xml.dart | 2 +- test/rss_test.dart | 8 +- 14 files changed, 157 insertions(+), 218 deletions(-) create mode 100644 lib/domain/itunes/itunes.dart rename lib/domain/{rss_itunes_category.dart => itunes/itunes_category.dart} (74%) create mode 100644 lib/domain/itunes/itunes_episode_type.dart rename lib/domain/{rss_itunes_image.dart => itunes/itunes_image.dart} (53%) rename lib/domain/{rss_itunes_owner.dart => itunes/itunes_owner.dart} (60%) create mode 100644 lib/domain/itunes/itunes_type.dart delete mode 100644 lib/domain/rss_item_itunes.dart delete mode 100644 lib/domain/rss_itunes.dart delete mode 100644 lib/domain/rss_itunes_episode_type.dart delete mode 100644 lib/domain/rss_itunes_type.dart diff --git a/lib/domain/itunes/itunes.dart b/lib/domain/itunes/itunes.dart new file mode 100644 index 0000000..de2481b --- /dev/null +++ b/lib/domain/itunes/itunes.dart @@ -0,0 +1,103 @@ +import 'package:webfeed/domain/itunes/itunes_category.dart'; +import 'package:webfeed/domain/itunes/itunes_episode_type.dart'; +import 'package:webfeed/domain/itunes/itunes_image.dart'; +import 'package:webfeed/domain/itunes/itunes_owner.dart'; +import 'package:webfeed/domain/itunes/itunes_type.dart'; +import 'package:webfeed/util/xml.dart'; +import 'package:xml/xml.dart'; + +class Itunes { + final String author; + final String summary; + final bool explicit; + final String title; + final String subtitle; + final ItunesOwner owner; + final List keywords; + final ItunesImage image; + final List categories; + final ItunesType type; + final String newFeedUrl; + final bool block; + final bool complete; + final int episode; + final int season; + final Duration duration; + final ItunesEpisodeType episodeType; + + Itunes({ + this.author, + this.summary, + this.explicit, + this.title, + this.subtitle, + this.owner, + this.keywords, + this.image, + this.categories, + this.type, + this.newFeedUrl, + this.block, + this.complete, + this.episode, + this.season, + this.duration, + this.episodeType, + }); + + factory Itunes.parse(XmlElement element) { + if (element == null) { + return null; + } + var episodeStr = findElementOrNull(element, 'itunes:episode')?.text?.trim(); + var seasonStr = findElementOrNull(element, 'itunes:season')?.text?.trim(); + var durationStr = + findElementOrNull(element, 'itunes:duration')?.text?.trim(); + return Itunes( + author: findElementOrNull(element, 'itunes:author')?.text?.trim(), + summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), + explicit: parseBoolLiteral(element, 'itunes:explicit'), + title: findElementOrNull(element, 'itunes:title')?.text?.trim(), + subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), + owner: ItunesOwner.parse(findElementOrNull(element, 'itunes:owner')), + keywords: findElementOrNull(element, 'itunes:keywords') + ?.text + ?.split(',') + ?.map((keyword) => keyword.trim()) + ?.toList(), + image: ItunesImage.parse(findElementOrNull(element, 'itunes:image')), + categories: findAllDirectElementsOrNull(element, 'itunes:category') + .map((ele) => ItunesCategory.parse(ele)) + .toList(), + type: newItunesType(findElementOrNull(element, 'itunes:type')), + newFeedUrl: + findElementOrNull(element, 'itunes:new-feed-url')?.text?.trim(), + block: parseBoolLiteral(element, 'itunes:block'), + complete: parseBoolLiteral(element, 'itunes:complete'), + episode: episodeStr == null ? null : int.parse(episodeStr), + season: seasonStr == null ? null : int.parse(seasonStr), + duration: durationStr == null ? null : _parseDuration(durationStr), + episodeType: newItunesEpisodeType( + findElementOrNull(element, 'itunes:episodeType')), + ); + } + + static Duration _parseDuration(String s) { + var hours = 0; + var minutes = 0; + var seconds = 0; + var parts = s.split(':'); + if (parts.length > 2) { + hours = int.parse(parts[parts.length - 3]); + } + if (parts.length > 1) { + minutes = int.parse(parts[parts.length - 2]); + } + seconds = int.parse(parts[parts.length - 1]); + return Duration( + hours: hours, + minutes: minutes, + seconds: seconds, + ); + } +} diff --git a/lib/domain/rss_itunes_category.dart b/lib/domain/itunes/itunes_category.dart similarity index 74% rename from lib/domain/rss_itunes_category.dart rename to lib/domain/itunes/itunes_category.dart index f6b7334..ad61ca9 100644 --- a/lib/domain/rss_itunes_category.dart +++ b/lib/domain/itunes/itunes_category.dart @@ -1,12 +1,12 @@ import 'package:xml/xml.dart'; -class RssItunesCategory { +class ItunesCategory { final String category; final List subCategories; - RssItunesCategory({this.category, this.subCategories}); + ItunesCategory({this.category, this.subCategories}); - factory RssItunesCategory.parse(XmlElement element) { + factory ItunesCategory.parse(XmlElement element) { if (element == null) return null; Iterable subCategories; @@ -15,7 +15,7 @@ class RssItunesCategory { } on StateError { subCategories = null; } - return RssItunesCategory( + return ItunesCategory( category: element.getAttribute('text')?.trim(), subCategories: subCategories ?.map((ele) => ele.getAttribute('text')?.trim()) diff --git a/lib/domain/itunes/itunes_episode_type.dart b/lib/domain/itunes/itunes_episode_type.dart new file mode 100644 index 0000000..fc84b39 --- /dev/null +++ b/lib/domain/itunes/itunes_episode_type.dart @@ -0,0 +1,16 @@ +import 'package:xml/xml.dart'; + +enum ItunesEpisodeType { full, trailer, bonus, unknown } + +ItunesEpisodeType newItunesEpisodeType(XmlElement element) { + switch (element?.text) { + case 'full': + return ItunesEpisodeType.full; + case 'trailer': + return ItunesEpisodeType.trailer; + case 'bonus': + return ItunesEpisodeType.bonus; + default: + return ItunesEpisodeType.unknown; + } +} diff --git a/lib/domain/rss_itunes_image.dart b/lib/domain/itunes/itunes_image.dart similarity index 53% rename from lib/domain/rss_itunes_image.dart rename to lib/domain/itunes/itunes_image.dart index 8328979..4ae61ca 100644 --- a/lib/domain/rss_itunes_image.dart +++ b/lib/domain/itunes/itunes_image.dart @@ -1,13 +1,13 @@ import 'package:xml/xml.dart'; -class RssItunesImage { +class ItunesImage { final String href; - RssItunesImage({this.href}); + ItunesImage({this.href}); - factory RssItunesImage.parse(XmlElement element) { + factory ItunesImage.parse(XmlElement element) { if (element == null) return null; - return RssItunesImage( + return ItunesImage( href: element.getAttribute('href')?.trim(), ); } diff --git a/lib/domain/rss_itunes_owner.dart b/lib/domain/itunes/itunes_owner.dart similarity index 60% rename from lib/domain/rss_itunes_owner.dart rename to lib/domain/itunes/itunes_owner.dart index e0bc605..1b8c717 100644 --- a/lib/domain/rss_itunes_owner.dart +++ b/lib/domain/itunes/itunes_owner.dart @@ -1,16 +1,15 @@ +import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; -import '../util/xml.dart'; - -class RssItunesOwner { +class ItunesOwner { final String name; final String email; - RssItunesOwner({this.name, this.email}); + ItunesOwner({this.name, this.email}); - factory RssItunesOwner.parse(XmlElement element) { + factory ItunesOwner.parse(XmlElement element) { if (element == null) return null; - return RssItunesOwner( + return ItunesOwner( name: findElementOrNull(element, 'itunes:name')?.text?.trim(), email: findElementOrNull(element, 'itunes:email')?.text?.trim(), ); diff --git a/lib/domain/itunes/itunes_type.dart b/lib/domain/itunes/itunes_type.dart new file mode 100644 index 0000000..b32f6bd --- /dev/null +++ b/lib/domain/itunes/itunes_type.dart @@ -0,0 +1,14 @@ +import 'package:xml/xml.dart'; + +enum ItunesType { episodic, serial, unknown } + +ItunesType newItunesType(XmlElement element) { + switch (element?.text) { + case 'episodic': + return ItunesType.episodic; + case 'serial': + return ItunesType.serial; + default: + return ItunesType.unknown; + } +} diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 2235fe4..2033830 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -1,6 +1,7 @@ import 'dart:core'; import 'package:webfeed/domain/dublin_core/dublin_core.dart'; +import 'package:webfeed/domain/itunes/itunes.dart'; import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_cloud.dart'; import 'package:webfeed/domain/rss_image.dart'; @@ -8,8 +9,6 @@ import 'package:webfeed/domain/rss_item.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; -import 'rss_itunes.dart'; - class RssFeed { final String title; final String author; @@ -32,7 +31,7 @@ class RssFeed { final String webMaster; final int ttl; final DublinCore dc; - final RssItunes itunes; + final Itunes itunes; RssFeed({ this.title, @@ -102,7 +101,7 @@ class RssFeed { webMaster: findElementOrNull(channelElement, 'webMaster')?.text, ttl: int.tryParse(findElementOrNull(channelElement, 'ttl')?.text ?? '0'), dc: DublinCore.parse(channelElement), - itunes: RssItunes.parse(channelElement), + itunes: Itunes.parse(channelElement), ); } } diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 534399e..245e772 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -1,9 +1,9 @@ import 'package:webfeed/domain/dublin_core/dublin_core.dart'; +import 'package:webfeed/domain/itunes/itunes.dart'; import 'package:webfeed/domain/media/media.dart'; import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_content.dart'; import 'package:webfeed/domain/rss_enclosure.dart'; -import 'package:webfeed/domain/rss_item_itunes.dart'; import 'package:webfeed/domain/rss_source.dart'; import 'package:webfeed/util/datetime.dart'; import 'package:webfeed/util/xml.dart'; @@ -24,7 +24,7 @@ class RssItem { final Media media; final RssEnclosure enclosure; final DublinCore dc; - final RssItemItunes itunes; + final Itunes itunes; RssItem({ this.title, @@ -60,7 +60,7 @@ class RssItem { media: Media.parse(element), enclosure: RssEnclosure.parse(findElementOrNull(element, 'enclosure')), dc: DublinCore.parse(element), - itunes: RssItemItunes.parse(element), + itunes: Itunes.parse(element), ); } } diff --git a/lib/domain/rss_item_itunes.dart b/lib/domain/rss_item_itunes.dart deleted file mode 100644 index 0c94044..0000000 --- a/lib/domain/rss_item_itunes.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'package:webfeed/util/xml.dart'; -import 'package:xml/xml.dart'; - -import 'rss_itunes_category.dart'; -import 'rss_itunes_episode_type.dart'; -import 'rss_itunes_image.dart'; - -class RssItemItunes { - final String title; - final int episode; - final int season; - final Duration duration; - final RssItunesEpisodeType episodeType; - final String author; - final String summary; - final bool explicit; - final String subtitle; - final List keywords; - final RssItunesImage image; - final RssItunesCategory category; - final bool block; - - RssItemItunes({ - this.title, - this.episode, - this.season, - this.duration, - this.episodeType, - this.author, - this.summary, - this.explicit, - this.subtitle, - this.keywords, - this.image, - this.category, - this.block, - }); - - factory RssItemItunes.parse(XmlElement element) { - if (element == null) { - return null; - } - var episodeStr = findElementOrNull(element, 'itunes:episode')?.text?.trim(); - var seasonStr = findElementOrNull(element, 'itunes:season')?.text?.trim(); - var durationStr = - findElementOrNull(element, 'itunes:duration')?.text?.trim(); - - return RssItemItunes( - title: findElementOrNull(element, 'itunes:title')?.text?.trim(), - episode: episodeStr == null ? null : int.parse(episodeStr), - season: seasonStr == null ? null : int.parse(seasonStr), - duration: durationStr == null ? null : parseDuration(durationStr), - episodeType: newRssItunesEpisodeType( - findElementOrNull(element, 'itunes:episodeType')), - author: findElementOrNull(element, 'itunes:author')?.text?.trim(), - summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), - explicit: parseBoolLiteral(element, 'itunes:explicit'), - subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), - keywords: findElementOrNull(element, 'itunes:keywords') - ?.text - ?.split(',') - ?.map((keyword) => keyword.trim()) - ?.toList(), - image: RssItunesImage.parse(findElementOrNull(element, 'itunes:image')), - category: RssItunesCategory.parse( - findElementOrNull(element, 'itunes:category')), - block: parseBoolLiteral(element, 'itunes:block'), - ); - } -} - -Duration parseDuration(String s) { - var hours = 0; - var minutes = 0; - var seconds = 0; - var parts = s.split(':'); - if (parts.length > 2) { - hours = int.parse(parts[parts.length - 3]); - } - if (parts.length > 1) { - minutes = int.parse(parts[parts.length - 2]); - } - seconds = int.parse(parts[parts.length - 1]); - return Duration( - hours: hours, - minutes: minutes, - seconds: seconds, - ); -} diff --git a/lib/domain/rss_itunes.dart b/lib/domain/rss_itunes.dart deleted file mode 100644 index af0b9e9..0000000 --- a/lib/domain/rss_itunes.dart +++ /dev/null @@ -1,67 +0,0 @@ -import 'package:webfeed/util/xml.dart'; -import 'package:xml/xml.dart'; - -import 'rss_itunes_category.dart'; -import 'rss_itunes_image.dart'; -import 'rss_itunes_owner.dart'; -import 'rss_itunes_type.dart'; - -class RssItunes { - final String author; - final String summary; - final bool explicit; - final String title; - final String subtitle; - final RssItunesOwner owner; - final List keywords; - final RssItunesImage image; - final List categories; - final RssItunesType type; - final String newFeedUrl; - final bool block; - final bool complete; - - RssItunes({ - this.author, - this.summary, - this.explicit, - this.title, - this.subtitle, - this.owner, - this.keywords, - this.image, - this.categories, - this.type, - this.newFeedUrl, - this.block, - this.complete, - }); - - factory RssItunes.parse(XmlElement element) { - if (element == null) { - return null; - } - return RssItunes( - author: findElementOrNull(element, 'itunes:author')?.text?.trim(), - summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), - explicit: parseBoolLiteral(element, 'itunes:explicit'), - title: findElementOrNull(element, 'itunes:title')?.text?.trim(), - subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), - owner: RssItunesOwner.parse(findElementOrNull(element, 'itunes:owner')), - keywords: findElementOrNull(element, 'itunes:keywords') - ?.text - ?.split(',') - ?.map((keyword) => keyword.trim()) - ?.toList(), - image: RssItunesImage.parse(findElementOrNull(element, 'itunes:image')), - categories: findAllDirectElementsOrNull(element, 'itunes:category') - .map((ele) => RssItunesCategory.parse(ele)) - .toList(), - type: newRssItunesType(findElementOrNull(element, 'itunes:type')), - newFeedUrl: - findElementOrNull(element, 'itunes:new-feed-url')?.text?.trim(), - block: parseBoolLiteral(element, 'itunes:block'), - complete: parseBoolLiteral(element, 'itunes:complete'), - ); - } -} diff --git a/lib/domain/rss_itunes_episode_type.dart b/lib/domain/rss_itunes_episode_type.dart deleted file mode 100644 index ffbf960..0000000 --- a/lib/domain/rss_itunes_episode_type.dart +++ /dev/null @@ -1,19 +0,0 @@ -import 'package:xml/xml.dart'; - -enum RssItunesEpisodeType { full, trailer, bonus } - -RssItunesEpisodeType newRssItunesEpisodeType(XmlElement element) { - // "full" is default type - if (element == null) return RssItunesEpisodeType.full; - - switch (element.text) { - case 'full': - return RssItunesEpisodeType.full; - case 'trailer': - return RssItunesEpisodeType.trailer; - case 'bonus': - return RssItunesEpisodeType.bonus; - default: - return null; - } -} diff --git a/lib/domain/rss_itunes_type.dart b/lib/domain/rss_itunes_type.dart deleted file mode 100644 index b5c846f..0000000 --- a/lib/domain/rss_itunes_type.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:xml/xml.dart'; - -enum RssItunesType { episodic, serial } - -RssItunesType newRssItunesType(XmlElement element) { - // 'episodic' is default type - if (element == null) return RssItunesType.episodic; - - switch (element.text) { - case 'episodic': - return RssItunesType.episodic; - case 'serial': - return RssItunesType.serial; - default: - return null; - } -} diff --git a/lib/util/xml.dart b/lib/util/xml.dart index 113a8c1..a847311 100644 --- a/lib/util/xml.dart +++ b/lib/util/xml.dart @@ -22,6 +22,6 @@ List findAllDirectElementsOrNull(XmlElement element, String name, bool parseBoolLiteral(XmlElement element, String tagName) { var v = findElementOrNull(element, tagName)?.text?.toLowerCase()?.trim(); - if (v == null) return null; + if (v == null) return false; return ['yes', 'true'].contains(v); } diff --git a/test/rss_test.dart b/test/rss_test.dart index 8fa729f..e20014d 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -2,8 +2,8 @@ import 'dart:core'; import 'dart:io'; import 'package:test/test.dart'; -import 'package:webfeed/domain/rss_itunes_episode_type.dart'; -import 'package:webfeed/domain/rss_itunes_type.dart'; +import 'package:webfeed/domain/itunes/itunes_episode_type.dart'; +import 'package:webfeed/domain/itunes/itunes_type.dart'; import 'package:webfeed/webfeed.dart'; void main() { @@ -344,13 +344,13 @@ void main() { } } expect(feed.itunes.title, 'Go Time'); - expect(feed.itunes.type, RssItunesType.serial); + expect(feed.itunes.type, ItunesType.serial); expect(feed.itunes.newFeedUrl, 'wubawuba'); expect(feed.itunes.block, true); expect(feed.itunes.complete, true); var item = feed.items[0]; - expect(item.itunes.episodeType, RssItunesEpisodeType.full); + expect(item.itunes.episodeType, ItunesEpisodeType.full); expect(item.itunes.episode, 1); expect(item.itunes.season, 1); expect(item.itunes.image.href, From ffb7b1428efa776b1171493c942f1c8265f9562d Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 03:01:51 +0700 Subject: [PATCH 13/22] bump version --- CHANGELOG.md | 9 +++++++++ pubspec.yaml | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 901904c..e1bf0f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,10 +1,19 @@ # Changelog +## [0.5.0](https://pub.dartlang.org/packages/webfeed/versions/0.5.0) +- Support iTunes namespace [#19](https://github.com/witochandra/webfeed/pull/19) +- Parse date strings into DateTime [#22](https://github.com/witochandra/webfeed/pull/22) +- Add created & modified into dublin core namespace [#27](https://github.com/witochandra/webfeed/pull/27) +- Upgrade xml package [#28](https://github.com/witochandra/webfeed/issues/28) +- Fix linting warnings + ## [0.4.2](https://pub.dartlang.org/packages/webfeed/versions/0.4.2) ### Fixed - Bad import in `rss_content.dart` & `rss_source.dart` + ## [0.4.1](https://pub.dartlang.org/packages/webfeed/versions/0.4.1) ### Added - Support `author` in RssFeed + ## [0.4.0](https://pub.dartlang.org/packages/webfeed/versions/0.4.0) ### Added - Support for dublin core namespace diff --git a/pubspec.yaml b/pubspec.yaml index 81640c4..337dc53 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: webfeed -version: 0.4.2 +version: 0.5.0 description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. author: Wito Chandra homepage: https://github.com/witochandra/webfeed From 5d180cc1f573b6a3e0e4d8b7084998c652f5aac4 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 03:05:17 +0700 Subject: [PATCH 14/22] publish --- CHANGELOG.md | 2 +- README.md | 2 +- pubspec.yaml | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1bf0f5..7eb4287 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ # Changelog -## [0.5.0](https://pub.dartlang.org/packages/webfeed/versions/0.5.0) +## [0.5.1](https://pub.dartlang.org/packages/webfeed/versions/0.5.1) - Support iTunes namespace [#19](https://github.com/witochandra/webfeed/pull/19) - Parse date strings into DateTime [#22](https://github.com/witochandra/webfeed/pull/22) - Add created & modified into dublin core namespace [#27](https://github.com/witochandra/webfeed/pull/27) diff --git a/README.md b/README.md index 715442d..d24918b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A dart package for parsing RSS and Atom feed. Add this line into your `pubspec.yaml` ``` -webfeed: ^0.4.2 +webfeed: ^0.5.1 ``` Import the package into your dart code using: diff --git a/pubspec.yaml b/pubspec.yaml index 337dc53..58df0a3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,6 @@ name: webfeed -version: 0.5.0 +version: 0.5.1 description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. -author: Wito Chandra homepage: https://github.com/witochandra/webfeed environment: sdk: ">=2.0.0 <3.0.0" From 4e9b7c8939922ce3018dfcee5c31606a20a476ca Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 11:07:05 +0700 Subject: [PATCH 15/22] lower the xml version contraints --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 58df0a3..7041aed 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -5,7 +5,7 @@ homepage: https://github.com/witochandra/webfeed environment: sdk: ">=2.0.0 <3.0.0" dependencies: - xml: "^4.3.0" + xml: "^4.2.0" intl: "^0.16.0" dev_dependencies: test: ^1.3.0 From 400b6922afb86ead0c684ccf85a6fc78437e64f1 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 11:09:19 +0700 Subject: [PATCH 16/22] bump version --- CHANGELOG.md | 3 +++ README.md | 2 +- pubspec.yaml | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7eb4287..5e470a4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,7 @@ # Changelog +## [0.5.2](https://pub.dartlang.org/packages/webfeed/versions/0.5.2) +- Lower the xml package version constraints + ## [0.5.1](https://pub.dartlang.org/packages/webfeed/versions/0.5.1) - Support iTunes namespace [#19](https://github.com/witochandra/webfeed/pull/19) - Parse date strings into DateTime [#22](https://github.com/witochandra/webfeed/pull/22) diff --git a/README.md b/README.md index d24918b..384830a 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ A dart package for parsing RSS and Atom feed. Add this line into your `pubspec.yaml` ``` -webfeed: ^0.5.1 +webfeed: ^0.5.2 ``` Import the package into your dart code using: diff --git a/pubspec.yaml b/pubspec.yaml index 7041aed..8ec43b5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: webfeed -version: 0.5.1 +version: 0.5.2 description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. homepage: https://github.com/witochandra/webfeed environment: From 35e841ecc55678ca34b9dde063957b98f61dd49f Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 04:45:52 +0700 Subject: [PATCH 17/22] refactor util/xml.dart --- lib/domain/atom_feed.dart | 16 +++--- lib/domain/atom_item.dart | 42 ++++++++-------- lib/domain/atom_person.dart | 11 +++-- lib/domain/atom_source.dart | 16 +++--- lib/domain/dublin_core/dublin_core.dart | 34 ++++++------- lib/domain/itunes/itunes.dart | 43 ++++++++-------- lib/domain/itunes/itunes_category.dart | 15 ++---- lib/domain/itunes/itunes_owner.dart | 4 +- lib/domain/media/community.dart | 6 +-- lib/domain/media/group.dart | 4 +- lib/domain/media/media.dart | 42 ++++++++-------- lib/domain/media/scene.dart | 8 +-- lib/domain/rss_feed.dart | 65 ++++++++++++------------- lib/domain/rss_image.dart | 12 ++--- lib/domain/rss_item.dart | 27 +++++----- lib/util/xml.dart | 27 +++++++--- test/rss_test.dart | 4 +- test/xml/RSS-DC.xml | 8 +-- test/xml/RSS-Itunes.xml | 7 +-- 19 files changed, 202 insertions(+), 189 deletions(-) diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 8a4f75e..2844212 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -49,9 +49,9 @@ class AtomFeed { } return AtomFeed( - id: findElementOrNull(feedElement, 'id')?.text, - title: findElementOrNull(feedElement, 'title')?.text, - updated: parseDateTime(findElementOrNull(feedElement, 'updated')?.text), + id: findFirstElement(feedElement, 'id')?.text, + title: findFirstElement(feedElement, 'title')?.text, + updated: parseDateTime(findFirstElement(feedElement, 'updated')?.text), items: feedElement.findElements('entry').map((element) { return AtomItem.parse(element); }).toList(), @@ -68,11 +68,11 @@ class AtomFeed { return AtomCategory.parse(element); }).toList(), generator: - AtomGenerator.parse(findElementOrNull(feedElement, 'generator')), - icon: findElementOrNull(feedElement, 'icon')?.text, - logo: findElementOrNull(feedElement, 'logo')?.text, - rights: findElementOrNull(feedElement, 'rights')?.text, - subtitle: findElementOrNull(feedElement, 'subtitle')?.text, + AtomGenerator.parse(findFirstElement(feedElement, 'generator')), + icon: findFirstElement(feedElement, 'icon')?.text, + logo: findFirstElement(feedElement, 'logo')?.text, + rights: findFirstElement(feedElement, 'rights')?.text, + subtitle: findFirstElement(feedElement, 'subtitle')?.text, ); } } diff --git a/lib/domain/atom_item.dart b/lib/domain/atom_item.dart index 2b93ccc..a5efa08 100644 --- a/lib/domain/atom_item.dart +++ b/lib/domain/atom_item.dart @@ -41,26 +41,28 @@ class AtomItem { factory AtomItem.parse(XmlElement element) { return AtomItem( - id: findElementOrNull(element, 'id')?.text, - title: findElementOrNull(element, 'title')?.text, - updated: parseDateTime(findElementOrNull(element, 'updated')?.text), - authors: element.findElements('author').map((element) { - return AtomPerson.parse(element); - }).toList(), - links: element.findElements('link').map((element) { - return AtomLink.parse(element); - }).toList(), - categories: element.findElements('category').map((element) { - return AtomCategory.parse(element); - }).toList(), - contributors: element.findElements('contributor').map((element) { - return AtomPerson.parse(element); - }).toList(), - source: AtomSource.parse(findElementOrNull(element, 'source')), - published: findElementOrNull(element, 'published')?.text, - content: findElementOrNull(element, 'content')?.text, - summary: findElementOrNull(element, 'summary')?.text, - rights: findElementOrNull(element, 'rights')?.text, + id: findFirstElement(element, 'id')?.text, + title: findFirstElement(element, 'title')?.text, + updated: parseDateTime(findFirstElement(element, 'updated')?.text), + authors: element + .findElements('author') + .map((e) => AtomPerson.parse(e)) + .toList(), + links: + element.findElements('link').map((e) => AtomLink.parse(e)).toList(), + categories: element + .findElements('category') + .map((e) => AtomCategory.parse(e)) + .toList(), + contributors: element + .findElements('contributor') + .map((e) => AtomPerson.parse(e)) + .toList(), + source: AtomSource.parse(findFirstElement(element, 'source')), + published: findFirstElement(element, 'published')?.text, + content: findFirstElement(element, 'content')?.text, + summary: findFirstElement(element, 'summary')?.text, + rights: findFirstElement(element, 'rights')?.text, media: Media.parse(element), ); } diff --git a/lib/domain/atom_person.dart b/lib/domain/atom_person.dart index 1d84e6c..749e7e0 100644 --- a/lib/domain/atom_person.dart +++ b/lib/domain/atom_person.dart @@ -6,12 +6,13 @@ class AtomPerson { final String uri; final String email; - AtomPerson(this.name, this.uri, this.email); + AtomPerson({this.name, this.uri, this.email}); factory AtomPerson.parse(XmlElement element) { - var name = findElementOrNull(element, 'name')?.text; - var uri = findElementOrNull(element, 'uri')?.text; - var email = findElementOrNull(element, 'email')?.text; - return AtomPerson(name, uri, email); + return AtomPerson( + name: findFirstElement(element, 'name')?.text, + uri: findFirstElement(element, 'uri')?.text, + email: findFirstElement(element, 'email')?.text, + ); } } diff --git a/lib/domain/atom_source.dart b/lib/domain/atom_source.dart index 9f1b34b..b917f14 100644 --- a/lib/domain/atom_source.dart +++ b/lib/domain/atom_source.dart @@ -6,16 +6,20 @@ class AtomSource { final String title; final String updated; - AtomSource(this.id, this.title, this.updated); + AtomSource({ + this.id, + this.title, + this.updated, + }); factory AtomSource.parse(XmlElement element) { if (element == null) { return null; } - var id = findElementOrNull(element, 'id')?.text; - var title = findElementOrNull(element, 'title')?.text; - var updated = findElementOrNull(element, 'updated')?.text; - - return AtomSource(id, title, updated); + return AtomSource( + id: findFirstElement(element, 'id')?.text, + title: findFirstElement(element, 'title')?.text, + updated: findFirstElement(element, 'updated')?.text, + ); } } diff --git a/lib/domain/dublin_core/dublin_core.dart b/lib/domain/dublin_core/dublin_core.dart index b36c004..d297df5 100644 --- a/lib/domain/dublin_core/dublin_core.dart +++ b/lib/domain/dublin_core/dublin_core.dart @@ -46,23 +46,23 @@ class DublinCore { return null; } return DublinCore( - title: findElementOrNull(element, 'dc:title')?.text, - description: findElementOrNull(element, 'dc:description')?.text, - creator: findElementOrNull(element, 'dc:creator')?.text, - subject: findElementOrNull(element, 'dc:subject')?.text, - publisher: findElementOrNull(element, 'dc:publisher')?.text, - contributor: findElementOrNull(element, 'dc:contributor')?.text, - date: parseDateTime(findElementOrNull(element, 'dc:date')?.text), - created: parseDateTime(findElementOrNull(element, 'dc:created')?.text), - modified: parseDateTime(findElementOrNull(element, 'dc:modified')?.text), - type: findElementOrNull(element, 'dc:type')?.text, - format: findElementOrNull(element, 'dc:format')?.text, - identifier: findElementOrNull(element, 'dc:identifier')?.text, - source: findElementOrNull(element, 'dc:source')?.text, - language: findElementOrNull(element, 'dc:language')?.text, - relation: findElementOrNull(element, 'dc:relation')?.text, - coverage: findElementOrNull(element, 'dc:coverage')?.text, - rights: findElementOrNull(element, 'dc:rights')?.text, + title: findFirstElement(element, 'dc:title')?.text, + description: findFirstElement(element, 'dc:description')?.text, + creator: findFirstElement(element, 'dc:creator')?.text, + subject: findFirstElement(element, 'dc:subject')?.text, + publisher: findFirstElement(element, 'dc:publisher')?.text, + contributor: findFirstElement(element, 'dc:contributor')?.text, + date: parseDateTime(findFirstElement(element, 'dc:date')?.text), + created: parseDateTime(findFirstElement(element, 'dc:created')?.text), + modified: parseDateTime(findFirstElement(element, 'dc:modified')?.text), + type: findFirstElement(element, 'dc:type')?.text, + format: findFirstElement(element, 'dc:format')?.text, + identifier: findFirstElement(element, 'dc:identifier')?.text, + source: findFirstElement(element, 'dc:source')?.text, + language: findFirstElement(element, 'dc:language')?.text, + relation: findFirstElement(element, 'dc:relation')?.text, + coverage: findFirstElement(element, 'dc:coverage')?.text, + rights: findFirstElement(element, 'dc:rights')?.text, ); } } diff --git a/lib/domain/itunes/itunes.dart b/lib/domain/itunes/itunes.dart index de2481b..a6cc682 100644 --- a/lib/domain/itunes/itunes.dart +++ b/lib/domain/itunes/itunes.dart @@ -49,36 +49,35 @@ class Itunes { if (element == null) { return null; } - var episodeStr = findElementOrNull(element, 'itunes:episode')?.text?.trim(); - var seasonStr = findElementOrNull(element, 'itunes:season')?.text?.trim(); - var durationStr = - findElementOrNull(element, 'itunes:duration')?.text?.trim(); + var episodeStr = findFirstElement(element, 'itunes:episode')?.text; + var seasonStr = findFirstElement(element, 'itunes:season')?.text; + var durationStr = findFirstElement(element, 'itunes:duration')?.text; return Itunes( - author: findElementOrNull(element, 'itunes:author')?.text?.trim(), - summary: findElementOrNull(element, 'itunes:summary')?.text?.trim(), + author: findFirstElement(element, 'itunes:author')?.text, + summary: findFirstElement(element, 'itunes:summary')?.text, explicit: parseBoolLiteral(element, 'itunes:explicit'), - title: findElementOrNull(element, 'itunes:title')?.text?.trim(), - subtitle: findElementOrNull(element, 'itunes:subtitle')?.text?.trim(), - owner: ItunesOwner.parse(findElementOrNull(element, 'itunes:owner')), - keywords: findElementOrNull(element, 'itunes:keywords') - ?.text - ?.split(',') - ?.map((keyword) => keyword.trim()) - ?.toList(), - image: ItunesImage.parse(findElementOrNull(element, 'itunes:image')), - categories: findAllDirectElementsOrNull(element, 'itunes:category') - .map((ele) => ItunesCategory.parse(ele)) + title: findFirstElement(element, 'itunes:title')?.text, + subtitle: findFirstElement(element, 'itunes:subtitle')?.text, + owner: ItunesOwner.parse(findFirstElement(element, 'itunes:owner')), + keywords: findFirstElement(element, 'itunes:keywords') + ?.text + ?.split(',') + ?.map((keyword) => keyword.trim()) + ?.toList() ?? + [], + image: ItunesImage.parse(findFirstElement(element, 'itunes:image')), + categories: findElements(element, 'itunes:category') + .map((e) => ItunesCategory.parse(e)) .toList(), - type: newItunesType(findElementOrNull(element, 'itunes:type')), - newFeedUrl: - findElementOrNull(element, 'itunes:new-feed-url')?.text?.trim(), + type: newItunesType(findFirstElement(element, 'itunes:type')), + newFeedUrl: findFirstElement(element, 'itunes:new-feed-url')?.text, block: parseBoolLiteral(element, 'itunes:block'), complete: parseBoolLiteral(element, 'itunes:complete'), episode: episodeStr == null ? null : int.parse(episodeStr), season: seasonStr == null ? null : int.parse(seasonStr), duration: durationStr == null ? null : _parseDuration(durationStr), - episodeType: newItunesEpisodeType( - findElementOrNull(element, 'itunes:episodeType')), + episodeType: + newItunesEpisodeType(findFirstElement(element, 'itunes:episodeType')), ); } diff --git a/lib/domain/itunes/itunes_category.dart b/lib/domain/itunes/itunes_category.dart index ad61ca9..2bfc792 100644 --- a/lib/domain/itunes/itunes_category.dart +++ b/lib/domain/itunes/itunes_category.dart @@ -8,18 +8,13 @@ class ItunesCategory { factory ItunesCategory.parse(XmlElement element) { if (element == null) return null; - - Iterable subCategories; - try { - subCategories = element.findElements('itunes:category'); - } on StateError { - subCategories = null; - } return ItunesCategory( category: element.getAttribute('text')?.trim(), - subCategories: subCategories - ?.map((ele) => ele.getAttribute('text')?.trim()) - ?.toList(), + subCategories: element + .findElements('itunes:category') + ?.map((e) => e.getAttribute('text')?.trim()) + ?.toList() ?? + [], ); } } diff --git a/lib/domain/itunes/itunes_owner.dart b/lib/domain/itunes/itunes_owner.dart index 1b8c717..2aa3f3a 100644 --- a/lib/domain/itunes/itunes_owner.dart +++ b/lib/domain/itunes/itunes_owner.dart @@ -10,8 +10,8 @@ class ItunesOwner { factory ItunesOwner.parse(XmlElement element) { if (element == null) return null; return ItunesOwner( - name: findElementOrNull(element, 'itunes:name')?.text?.trim(), - email: findElementOrNull(element, 'itunes:email')?.text?.trim(), + name: findFirstElement(element, 'itunes:name')?.text?.trim(), + email: findFirstElement(element, 'itunes:email')?.text?.trim(), ); } } diff --git a/lib/domain/media/community.dart b/lib/domain/media/community.dart index fcbbf8a..a29ed1e 100644 --- a/lib/domain/media/community.dart +++ b/lib/domain/media/community.dart @@ -21,13 +21,13 @@ class Community { } return Community( starRating: StarRating.parse( - findElementOrNull(element, 'media:starRating'), + findFirstElement(element, 'media:starRating'), ), statistics: Statistics.parse( - findElementOrNull(element, 'media:statistics'), + findFirstElement(element, 'media:statistics'), ), tags: Tags.parse( - findElementOrNull(element, 'media:tags'), + findFirstElement(element, 'media:tags'), ), ); } diff --git a/lib/domain/media/group.dart b/lib/domain/media/group.dart index 7f656a9..8f82f7b 100644 --- a/lib/domain/media/group.dart +++ b/lib/domain/media/group.dart @@ -30,10 +30,10 @@ class Group { return Credit.parse(e); }).toList(), category: Category.parse( - findElementOrNull(element, 'media:category'), + findFirstElement(element, 'media:category'), ), rating: Rating.parse( - findElementOrNull(element, 'media:rating'), + findFirstElement(element, 'media:rating'), ), ); } diff --git a/lib/domain/media/media.dart b/lib/domain/media/media.dart index c5655a2..2ee0cba 100644 --- a/lib/domain/media/media.dart +++ b/lib/domain/media/media.dart @@ -80,7 +80,7 @@ class Media { factory Media.parse(XmlElement element) { return Media( group: Group.parse( - findElementOrNull(element, 'media:group'), + findFirstElement(element, 'media:group'), ), contents: element.findElements('media:content').map((e) { return Content.parse(e); @@ -89,76 +89,76 @@ class Media { return Credit.parse(e); }).toList(), category: Category.parse( - findElementOrNull(element, 'media:category'), + findFirstElement(element, 'media:category'), ), rating: Rating.parse( - findElementOrNull(element, 'media:rating'), + findFirstElement(element, 'media:rating'), ), title: Title.parse( - findElementOrNull(element, 'media:title'), + findFirstElement(element, 'media:title'), ), description: Description.parse( - findElementOrNull(element, 'media:description'), + findFirstElement(element, 'media:description'), ), - keywords: findElementOrNull(element, 'media:keywords')?.text, + keywords: findFirstElement(element, 'media:keywords')?.text, thumbnails: element.findElements('media:thumbnail').map((e) { return Thumbnail.parse(e); }).toList(), hash: Hash.parse( - findElementOrNull(element, 'media:hash'), + findFirstElement(element, 'media:hash'), ), player: Player.parse( - findElementOrNull(element, 'media:player'), + findFirstElement(element, 'media:player'), ), copyright: Copyright.parse( - findElementOrNull(element, 'media:copyright'), + findFirstElement(element, 'media:copyright'), ), text: Text.parse( - findElementOrNull(element, 'media:text'), + findFirstElement(element, 'media:text'), ), restriction: Restriction.parse( - findElementOrNull(element, 'media:restriction'), + findFirstElement(element, 'media:restriction'), ), community: Community.parse( - findElementOrNull(element, 'media:community'), + findFirstElement(element, 'media:community'), ), - comments: findElementOrNull(element, 'media:comments') + comments: findFirstElement(element, 'media:comments') ?.findElements('media:comment') ?.map((e) { return e.text; })?.toList() ?? [], embed: Embed.parse( - findElementOrNull(element, 'media:embed'), + findFirstElement(element, 'media:embed'), ), - responses: findElementOrNull(element, 'media:responses') + responses: findFirstElement(element, 'media:responses') ?.findElements('media:response') ?.map((e) { return e.text; })?.toList() ?? [], - backLinks: findElementOrNull(element, 'media:backLinks') + backLinks: findFirstElement(element, 'media:backLinks') ?.findElements('media:backLink') ?.map((e) { return e.text; })?.toList() ?? [], status: Status.parse( - findElementOrNull(element, 'media:status'), + findFirstElement(element, 'media:status'), ), prices: element.findElements('media:price').map((e) { return Price.parse(e); }).toList(), license: License.parse( - findElementOrNull(element, 'media:license'), + findFirstElement(element, 'media:license'), ), peerLink: PeerLink.parse( - findElementOrNull(element, 'media:peerLink'), + findFirstElement(element, 'media:peerLink'), ), rights: Rights.parse( - findElementOrNull(element, 'media:rights'), + findFirstElement(element, 'media:rights'), ), - scenes: findElementOrNull(element, 'media:scenes') + scenes: findFirstElement(element, 'media:scenes') ?.findElements('media:scene') ?.map((e) { return Scene.parse(e); diff --git a/lib/domain/media/scene.dart b/lib/domain/media/scene.dart index 19e730e..f327a87 100644 --- a/lib/domain/media/scene.dart +++ b/lib/domain/media/scene.dart @@ -19,10 +19,10 @@ class Scene { return null; } return Scene( - title: findElementOrNull(element, 'sceneTitle')?.text, - description: findElementOrNull(element, 'sceneDescription')?.text, - startTime: findElementOrNull(element, 'sceneStartTime')?.text, - endTime: findElementOrNull(element, 'sceneEndTime')?.text, + title: findFirstElement(element, 'sceneTitle')?.text, + description: findFirstElement(element, 'sceneDescription')?.text, + startTime: findFirstElement(element, 'sceneStartTime')?.text, + endTime: findFirstElement(element, 'sceneEndTime')?.text, ); } } diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 2033830..7d84d00 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -59,47 +59,44 @@ class RssFeed { factory RssFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - XmlElement channelElement; - try { - channelElement = document.findAllElements('channel').first; - } on StateError { + var channelElement = findFirstElement(document, 'channel', recursive: true); + if (channelElement == null) { throw ArgumentError('channel not found'); } - return RssFeed( - title: findElementOrNull(channelElement, 'title')?.text, - author: findElementOrNull(channelElement, 'author')?.text, - description: findElementOrNull(channelElement, 'description')?.text, - link: findElementOrNull(channelElement, 'link')?.text, - items: channelElement.findElements('item').map((element) { - return RssItem.parse(element); - }).toList(), - image: RssImage.parse(findElementOrNull(channelElement, 'image')), - cloud: RssCloud.parse(findElementOrNull(channelElement, 'cloud')), - categories: channelElement.findElements('category').map((element) { - return RssCategory.parse(element); - }).toList(), - skipDays: findElementOrNull(channelElement, 'skipDays') + title: findFirstElement(channelElement, 'title')?.text, + author: findFirstElement(channelElement, 'author')?.text, + description: findFirstElement(channelElement, 'description')?.text, + link: findFirstElement(channelElement, 'link')?.text, + items: channelElement + .findElements('item') + .map((e) => RssItem.parse(e)) + .toList(), + image: RssImage.parse(findFirstElement(channelElement, 'image')), + cloud: RssCloud.parse(findFirstElement(channelElement, 'cloud')), + categories: channelElement + .findElements('category') + .map((e) => RssCategory.parse(e)) + .toList(), + skipDays: findFirstElement(channelElement, 'skipDays') ?.findAllElements('day') - ?.map((element) { - return element.text; - })?.toList() ?? + ?.map((e) => e.text) + ?.toList() ?? [], - skipHours: findElementOrNull(channelElement, 'skipHours') + skipHours: findFirstElement(channelElement, 'skipHours') ?.findAllElements('hour') - ?.map((element) { - return int.tryParse(element.text ?? '0'); - })?.toList() ?? + ?.map((e) => int.tryParse(e.text ?? '0')) + ?.toList() ?? [], - lastBuildDate: findElementOrNull(channelElement, 'lastBuildDate')?.text, - language: findElementOrNull(channelElement, 'language')?.text, - generator: findElementOrNull(channelElement, 'generator')?.text, - copyright: findElementOrNull(channelElement, 'copyright')?.text, - docs: findElementOrNull(channelElement, 'docs')?.text, - managingEditor: findElementOrNull(channelElement, 'managingEditor')?.text, - rating: findElementOrNull(channelElement, 'rating')?.text, - webMaster: findElementOrNull(channelElement, 'webMaster')?.text, - ttl: int.tryParse(findElementOrNull(channelElement, 'ttl')?.text ?? '0'), + lastBuildDate: findFirstElement(channelElement, 'lastBuildDate')?.text, + language: findFirstElement(channelElement, 'language')?.text, + generator: findFirstElement(channelElement, 'generator')?.text, + copyright: findFirstElement(channelElement, 'copyright')?.text, + docs: findFirstElement(channelElement, 'docs')?.text, + managingEditor: findFirstElement(channelElement, 'managingEditor')?.text, + rating: findFirstElement(channelElement, 'rating')?.text, + webMaster: findFirstElement(channelElement, 'webMaster')?.text, + ttl: int.tryParse(findFirstElement(channelElement, 'ttl')?.text ?? '0'), dc: DublinCore.parse(channelElement), itunes: Itunes.parse(channelElement), ); diff --git a/lib/domain/rss_image.dart b/lib/domain/rss_image.dart index 9ed4e33..35e39b3 100644 --- a/lib/domain/rss_image.dart +++ b/lib/domain/rss_image.dart @@ -6,16 +6,16 @@ class RssImage { final String url; final String link; - RssImage(this.title, this.url, this.link); + RssImage({this.title, this.url, this.link}); factory RssImage.parse(XmlElement element) { if (element == null) { return null; } - var title = findElementOrNull(element, 'title')?.text; - var url = findElementOrNull(element, 'url')?.text; - var link = findElementOrNull(element, 'link')?.text; - - return RssImage(title, url, link); + return RssImage( + title: findFirstElement(element, 'title')?.text, + url: findFirstElement(element, 'url')?.text, + link: findFirstElement(element, 'link')?.text, + ); } } diff --git a/lib/domain/rss_item.dart b/lib/domain/rss_item.dart index 245e772..15fa909 100644 --- a/lib/domain/rss_item.dart +++ b/lib/domain/rss_item.dart @@ -45,20 +45,21 @@ class RssItem { factory RssItem.parse(XmlElement element) { return RssItem( - title: findElementOrNull(element, 'title')?.text, - description: findElementOrNull(element, 'description')?.text, - link: findElementOrNull(element, 'link')?.text, - categories: element.findElements('category').map((element) { - return RssCategory.parse(element); - }).toList(), - guid: findElementOrNull(element, 'guid')?.text, - pubDate: parseDateTime(findElementOrNull(element, 'pubDate')?.text), - author: findElementOrNull(element, 'author')?.text, - comments: findElementOrNull(element, 'comments')?.text, - source: RssSource.parse(findElementOrNull(element, 'source')), - content: RssContent.parse(findElementOrNull(element, 'content:encoded')), + title: findFirstElement(element, 'title')?.text, + description: findFirstElement(element, 'description')?.text, + link: findFirstElement(element, 'link')?.text, + categories: element + .findElements('category') + .map((e) => RssCategory.parse(e)) + .toList(), + guid: findFirstElement(element, 'guid')?.text, + pubDate: parseDateTime(findFirstElement(element, 'pubDate')?.text), + author: findFirstElement(element, 'author')?.text, + comments: findFirstElement(element, 'comments')?.text, + source: RssSource.parse(findFirstElement(element, 'source')), + content: RssContent.parse(findFirstElement(element, 'content:encoded')), media: Media.parse(element), - enclosure: RssEnclosure.parse(findElementOrNull(element, 'enclosure')), + enclosure: RssEnclosure.parse(findFirstElement(element, 'enclosure')), dc: DublinCore.parse(element), itunes: Itunes.parse(element), ); diff --git a/lib/util/xml.dart b/lib/util/xml.dart index a847311..460ff93 100644 --- a/lib/util/xml.dart +++ b/lib/util/xml.dart @@ -2,26 +2,39 @@ import 'dart:core'; import 'package:xml/xml.dart'; -XmlElement findElementOrNull(XmlElement element, String name, - {String namespace}) { +XmlElement findFirstElement( + XmlNode node, + String name, { + bool recursive = false, + String namespace, +}) { try { - return element.findAllElements(name, namespace: namespace).first; + return findElements(node, name, recursive: recursive, namespace: namespace) + ?.first; } on StateError { return null; } } -List findAllDirectElementsOrNull(XmlElement element, String name, - {String namespace}) { +Iterable findElements( + XmlNode node, + String name, { + bool recursive = false, + String namespace, +}) { try { - return element.findElements(name, namespace: namespace).toList(); + if (recursive) { + return node.findAllElements(name, namespace: namespace); + } else { + return node.findElements(name, namespace: namespace); + } } on StateError { return null; } } bool parseBoolLiteral(XmlElement element, String tagName) { - var v = findElementOrNull(element, tagName)?.text?.toLowerCase()?.trim(); + var v = findFirstElement(element, tagName)?.text?.toLowerCase()?.trim(); if (v == null) return false; return ['yes', 'true'].contains(v); } diff --git a/test/rss_test.dart b/test/rss_test.dart index e20014d..36f8244 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -258,7 +258,9 @@ void main() { 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, 1, 12)); + 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'); diff --git a/test/xml/RSS-DC.xml b/test/xml/RSS-DC.xml index 4233fb4..8ffcd38 100644 --- a/test/xml/RSS-DC.xml +++ b/test/xml/RSS-DC.xml @@ -9,6 +9,8 @@ publisher contributor 2000-01-01T12:00+00:00 + 2000-01-01T13:00+00:00 + 2000-01-01T14:00+00:00 type format identifier @@ -24,9 +26,9 @@ description publisher contributor - 2000-01-01T12:00+00:00 - 2000-01-01T13:00+00:00 - 2000-01-01T14:00+00:00 + 2000-01-02T12:00+00:00 + 2000-01-02T13:00+00:00 + 2000-01-02T14:00+00:00 type format identifier diff --git a/test/xml/RSS-Itunes.xml b/test/xml/RSS-Itunes.xml index 237b564..bb2a6a3 100644 --- a/test/xml/RSS-Itunes.xml +++ b/test/xml/RSS-Itunes.xml @@ -45,12 +45,9 @@ go, golang, open source, software, development with Erik, Carlisia, and Brian Foo - - Erik St. Martin, Carlisia Pinto, and Brian Ketelsen + Erik St. Martin, Carlisia Pinto, and Brian Ketelsen - - Erik St. Martin, Carlisia Pinto, and Brian Ketelsen - + Erik St. Martin, Carlisia Pinto, and Brian Ketelsen \ No newline at end of file From 1b490d53f0ba36ab665ea4b350e7b12f5e1e5e5c Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 04:59:08 +0700 Subject: [PATCH 18/22] simplify AtomFeed.parse --- lib/domain/atom_feed.dart | 41 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 2844212..2e4e855 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -41,10 +41,8 @@ class AtomFeed { factory AtomFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - XmlElement feedElement; - try { - feedElement = document.findElements('feed').first; - } on StateError { + var feedElement = findFirstElement(document, 'feed', recursive: true); + if (feedElement == null) { throw ArgumentError('feed not found'); } @@ -52,21 +50,26 @@ class AtomFeed { id: findFirstElement(feedElement, 'id')?.text, title: findFirstElement(feedElement, 'title')?.text, updated: parseDateTime(findFirstElement(feedElement, 'updated')?.text), - items: feedElement.findElements('entry').map((element) { - return AtomItem.parse(element); - }).toList(), - links: feedElement.findElements('link').map((element) { - return AtomLink.parse(element); - }).toList(), - authors: feedElement.findElements('author').map((element) { - return AtomPerson.parse(element); - }).toList(), - contributors: feedElement.findElements('contributor').map((element) { - return AtomPerson.parse(element); - }).toList(), - categories: feedElement.findElements('category').map((element) { - return AtomCategory.parse(element); - }).toList(), + items: feedElement + .findElements('entry') + .map((e) => AtomItem.parse(e)) + .toList(), + links: feedElement + .findElements('link') + .map((e) => AtomLink.parse(e)) + .toList(), + authors: feedElement + .findElements('author') + .map((e) => AtomPerson.parse(e)) + .toList(), + contributors: feedElement + .findElements('contributor') + .map((e) => AtomPerson.parse(e)) + .toList(), + categories: feedElement + .findElements('category') + .map((e) => AtomCategory.parse(e)) + .toList(), generator: AtomGenerator.parse(findFirstElement(feedElement, 'generator')), icon: findFirstElement(feedElement, 'icon')?.text, From de0b4cd507b9abb1ecf10bf46f4e2f7505705074 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 05:27:19 +0700 Subject: [PATCH 19/22] support RDF --- lib/domain/atom_feed.dart | 2 +- lib/domain/rss_feed.dart | 12 +++++++++--- test/rss_test.dart | 16 ++++++++++++++++ test/xml/RSS-RDF.xml | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 4 deletions(-) create mode 100644 test/xml/RSS-RDF.xml diff --git a/lib/domain/atom_feed.dart b/lib/domain/atom_feed.dart index 2e4e855..128ed30 100644 --- a/lib/domain/atom_feed.dart +++ b/lib/domain/atom_feed.dart @@ -41,7 +41,7 @@ class AtomFeed { factory AtomFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - var feedElement = findFirstElement(document, 'feed', recursive: true); + var feedElement = findFirstElement(document, 'feed'); if (feedElement == null) { throw ArgumentError('feed not found'); } diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 7d84d00..4aced3e 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -59,7 +59,12 @@ class RssFeed { factory RssFeed.parse(String xmlString) { var document = XmlDocument.parse(xmlString); - var channelElement = findFirstElement(document, 'channel', recursive: true); + var rss = findFirstElement(document, 'rss'); + var rdf = findFirstElement(document, 'rdf:RDF'); + if (rss == null && rdf == null) { + throw ArgumentError('not a rss feed'); + } + var channelElement = findFirstElement(rss ?? rdf, 'channel'); if (channelElement == null) { throw ArgumentError('channel not found'); } @@ -68,11 +73,12 @@ class RssFeed { author: findFirstElement(channelElement, 'author')?.text, description: findFirstElement(channelElement, 'description')?.text, link: findFirstElement(channelElement, 'link')?.text, - items: channelElement + items: (rss != null ? channelElement : rdf) .findElements('item') .map((e) => RssItem.parse(e)) .toList(), - image: RssImage.parse(findFirstElement(channelElement, 'image')), + image: RssImage.parse( + findFirstElement(rss != null ? channelElement : rdf, 'image')), cloud: RssCloud.parse(findFirstElement(channelElement, 'cloud')), categories: channelElement .findElements('category') diff --git a/test/rss_test.dart b/test/rss_test.dart index 36f8244..9dc738d 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -369,4 +369,20 @@ void main() { expect(item.itunes.title, 'awesome title'); expect(item.itunes.block, false); }); + + test('parse RSS-RDF.xml', () { + var xmlString = File('test/xml/RSS-RDF.xml').readAsStringSync(); + + var feed = RssFeed.parse(xmlString); + + expect(feed.title, 'Mozilla Dot Org'); + expect(feed.link, 'http://www.mozilla.org'); + expect(feed.description, 'the Mozilla Organization web site'); + expect(feed.image.title, 'Mozilla'); + expect(feed.image.url, 'http://www.mozilla.org/images/moz.gif'); + expect(feed.image.link, 'http://www.mozilla.org'); + expect(feed.items.length, 5); + expect(feed.items.first.title, 'New Status Updates'); + expect(feed.items.first.link, 'http://www.mozilla.org/status/'); + }); } diff --git a/test/xml/RSS-RDF.xml b/test/xml/RSS-RDF.xml new file mode 100644 index 0000000..63a5d03 --- /dev/null +++ b/test/xml/RSS-RDF.xml @@ -0,0 +1,35 @@ + + + + Mozilla Dot Org + http://www.mozilla.org + the Mozilla Organization web site + + + Mozilla + http://www.mozilla.org/images/moz.gif + http://www.mozilla.org + + + New Status Updates + http://www.mozilla.org/status/ + + + Bugzilla Reorganized + http://www.mozilla.org/bugs/ + + + Mozilla Party, 2.0! + http://www.mozilla.org/party/1999/ + + + Unix Platform Parity + http://www.mozilla.org/build/unix.html + + + NPL 1.0M published + http://www.mozilla.org/NPL/NPL-1.0M.html + + \ No newline at end of file From 770895f21e1457ec3f6212bd00921faf201741b2 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 05:48:36 +0700 Subject: [PATCH 20/22] support syndication namespace --- lib/domain/rss_feed.dart | 4 ++ lib/domain/syndication/syndication.dart | 51 +++++++++++++++++++++++++ test/rss_test.dart | 23 +++++++++++ test/xml/RSS-Syndication.xml | 24 ++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 lib/domain/syndication/syndication.dart create mode 100644 test/xml/RSS-Syndication.xml diff --git a/lib/domain/rss_feed.dart b/lib/domain/rss_feed.dart index 4aced3e..a2e66c2 100644 --- a/lib/domain/rss_feed.dart +++ b/lib/domain/rss_feed.dart @@ -6,6 +6,7 @@ import 'package:webfeed/domain/rss_category.dart'; import 'package:webfeed/domain/rss_cloud.dart'; import 'package:webfeed/domain/rss_image.dart'; import 'package:webfeed/domain/rss_item.dart'; +import 'package:webfeed/domain/syndication/syndication.dart'; import 'package:webfeed/util/xml.dart'; import 'package:xml/xml.dart'; @@ -32,6 +33,7 @@ class RssFeed { final int ttl; final DublinCore dc; final Itunes itunes; + final Syndication syndication; RssFeed({ this.title, @@ -55,6 +57,7 @@ class RssFeed { this.ttl, this.dc, this.itunes, + this.syndication, }); factory RssFeed.parse(String xmlString) { @@ -105,6 +108,7 @@ class RssFeed { ttl: int.tryParse(findFirstElement(channelElement, 'ttl')?.text ?? '0'), dc: DublinCore.parse(channelElement), itunes: Itunes.parse(channelElement), + syndication: Syndication.parse(channelElement), ); } } diff --git a/lib/domain/syndication/syndication.dart b/lib/domain/syndication/syndication.dart new file mode 100644 index 0000000..4b05e12 --- /dev/null +++ b/lib/domain/syndication/syndication.dart @@ -0,0 +1,51 @@ +import 'package:webfeed/util/datetime.dart'; +import 'package:webfeed/util/xml.dart'; +import 'package:xml/xml.dart'; + +enum SyndicationUpdatePeriod { hourly, daily, weekly, monthly, yearly } + +class Syndication { + final SyndicationUpdatePeriod updatePeriod; + final int updateFrequency; + final DateTime updateBase; + + Syndication({ + this.updatePeriod, + this.updateFrequency, + this.updateBase, + }); + + factory Syndication.parse(XmlElement element) { + if (element == null) { + return null; + } + SyndicationUpdatePeriod updatePeriod; + switch (findFirstElement(element, 'sy:updatePeriod')?.text) { + case 'hourly': + updatePeriod = SyndicationUpdatePeriod.hourly; + break; + case 'daily': + updatePeriod = SyndicationUpdatePeriod.daily; + break; + case 'weekly': + updatePeriod = SyndicationUpdatePeriod.weekly; + break; + case 'monthly': + updatePeriod = SyndicationUpdatePeriod.monthly; + break; + case 'yearly': + updatePeriod = SyndicationUpdatePeriod.yearly; + break; + default: + updatePeriod = SyndicationUpdatePeriod.daily; + break; + } + return Syndication( + updatePeriod: updatePeriod, + updateFrequency: int.tryParse( + findFirstElement(element, 'sy:updateFrequency')?.text ?? '1'), + updateBase: + parseDateTime(findFirstElement(element, 'sy:updateBase')?.text), + ); + } +} diff --git a/test/rss_test.dart b/test/rss_test.dart index 9dc738d..44eb9b2 100644 --- a/test/rss_test.dart +++ b/test/rss_test.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:test/test.dart'; import 'package:webfeed/domain/itunes/itunes_episode_type.dart'; import 'package:webfeed/domain/itunes/itunes_type.dart'; +import 'package:webfeed/domain/syndication/syndication.dart'; import 'package:webfeed/webfeed.dart'; void main() { @@ -385,4 +386,26 @@ void main() { expect(feed.items.first.title, 'New Status Updates'); expect(feed.items.first.link, 'http://www.mozilla.org/status/'); }); + + test('parse RSS-Syndication.xml', () { + var xmlString = File('test/xml/RSS-Syndication.xml').readAsStringSync(); + + var feed = RssFeed.parse(xmlString); + + expect(feed.title, 'Meerkat'); + expect(feed.link, 'http://meerkat.oreillynet.com'); + expect(feed.description, 'Meerkat: An Open Wire Service'); + expect(feed.image.title, 'Meerkat Powered!'); + expect(feed.image.url, + 'http://meerkat.oreillynet.com/icons/meerkat-powered.jpg'); + expect(feed.image.link, 'http://meerkat.oreillynet.com'); + expect(feed.syndication.updatePeriod, SyndicationUpdatePeriod.hourly); + expect(feed.syndication.updateFrequency, 2); + expect(feed.syndication.updateBase, DateTime.utc(2001, 1, 1, 12, 1)); + expect(feed.items.length, 1); + expect(feed.items.first.title, 'XML: A Disruptive Technology'); + expect(feed.items.first.description, + 'XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet.'); + expect(feed.items.first.link, 'http://c.moreover.com/click/here.pl?r123'); + }); } diff --git a/test/xml/RSS-Syndication.xml b/test/xml/RSS-Syndication.xml new file mode 100644 index 0000000..2fcd356 --- /dev/null +++ b/test/xml/RSS-Syndication.xml @@ -0,0 +1,24 @@ + + + + Meerkat + http://meerkat.oreillynet.com + Meerkat: An Open Wire Service + hourly + 2 + 2001-01-01T12:01+00:00 + + + + Meerkat Powered! + http://meerkat.oreillynet.com/icons/meerkat-powered.jpg + http://meerkat.oreillynet.com + + + XML: A Disruptive Technology + http://c.moreover.com/click/here.pl?r123 + XML is placing increasingly heavy loads on the existing technical infrastructure of the Internet. + + From 3f2cd69eb53000d52318a8cf67ce0538ca891ac8 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 05:53:42 +0700 Subject: [PATCH 21/22] bump version --- README.md | 6 ++++-- pubspec.yaml | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 384830a..6e179d2 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,19 @@ A dart package for parsing RSS and Atom feed. ### Features -- [x] RSS +- [x] RSS (0.9, 1.0, & 2.0) - [x] Atom - [x] Namespaces - [x] Media RSS - [x] Dublin Core + - [x] iTunes + - [x] Syndication ### Installing Add this line into your `pubspec.yaml` ``` -webfeed: ^0.5.2 +webfeed: ^0.6.0 ``` Import the package into your dart code using: diff --git a/pubspec.yaml b/pubspec.yaml index 8ec43b5..78ec0ad 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: webfeed -version: 0.5.2 -description: webfeed is a dart package for parsing RSS and Atom feeds. Media & DublinCore namespaces are also supported. +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" From 09cbc7a3be61be4ac7675063b5754f8825ce4414 Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Sun, 16 Aug 2020 06:00:46 +0700 Subject: [PATCH 22/22] add changelog --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e470a4..3c8d64f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ # Changelog +## [0.6.0](https://pub.dartlang.org/packages/webfeed/versions/0.6.0) +- Refactor util/xml.dart +- Support RDF feed +- Support Syndication namespace + ## [0.5.2](https://pub.dartlang.org/packages/webfeed/versions/0.5.2) - Lower the xml package version constraints