From 9a843763fe7df79ecda0d1383f454616893d1e3d Mon Sep 17 00:00:00 2001 From: Wito Chandra Date: Wed, 12 Aug 2020 02:55:54 +0700 Subject: [PATCH] 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,