| @@ -0,0 +1,35 @@ | |||||
| import 'package:xml/xml/nodes/element.dart'; | |||||
| final _imagesRegExp = new RegExp( | |||||
| "<img\\s.*?src=(?:'|\")([^'\">]+)(?:'|\")", | |||||
| multiLine: true, | |||||
| caseSensitive: false, | |||||
| ); | |||||
| /// For RSS Content Module: | |||||
| /// | |||||
| /// - `xmlns:content="http://purl.org/rss/1.0/modules/content/"` | |||||
| /// | |||||
| class RssContent { | |||||
| String value; | |||||
| Iterable<String> images; | |||||
| RssContent(this.value, this.images); | |||||
| factory RssContent.parse(XmlElement node) { | |||||
| final content = node.text; | |||||
| final images = <String>[]; | |||||
| _imagesRegExp.allMatches(content).forEach((match) { | |||||
| images.add(match.group(1)); | |||||
| }); | |||||
| return new RssContent(content, images); | |||||
| } | |||||
| @override | |||||
| String toString() { | |||||
| return ''' | |||||
| content: $value | |||||
| images: $images | |||||
| '''; | |||||
| } | |||||
| } | |||||
| @@ -1,4 +1,5 @@ | |||||
| import 'package:webfeed/domain/rss_category.dart'; | import 'package:webfeed/domain/rss_category.dart'; | ||||
| import 'package:webfeed/domain/rss_content.dart'; | |||||
| import 'package:webfeed/domain/rss_source.dart'; | import 'package:webfeed/domain/rss_source.dart'; | ||||
| import 'package:webfeed/util/helpers.dart'; | import 'package:webfeed/util/helpers.dart'; | ||||
| import 'package:xml/xml.dart'; | import 'package:xml/xml.dart'; | ||||
| @@ -14,9 +15,20 @@ class RssItem { | |||||
| final String author; | final String author; | ||||
| final String comments; | final String comments; | ||||
| final RssSource source; | final RssSource source; | ||||
| final RssContent content; | |||||
| RssItem(this.title, this.description, this.link, | |||||
| {this.categories, this.guid, this.pubDate, this.author, this.comments, this.source}); | |||||
| RssItem( | |||||
| this.title, | |||||
| this.description, | |||||
| this.link, { | |||||
| this.categories, | |||||
| this.guid, | |||||
| this.pubDate, | |||||
| this.author, | |||||
| this.comments, | |||||
| this.source, | |||||
| this.content, | |||||
| }); | |||||
| factory RssItem.parse(XmlElement element) { | factory RssItem.parse(XmlElement element) { | ||||
| var title = xmlGetString(element, "title"); | var title = xmlGetString(element, "title"); | ||||
| @@ -37,8 +49,23 @@ class RssItem { | |||||
| source = new RssSource.parse(element.findElements("source").first); | source = new RssSource.parse(element.findElements("source").first); | ||||
| } on StateError {} | } on StateError {} | ||||
| return new RssItem(title, description, link, | |||||
| categories: categories, guid: guid, pubDate: pubDate, author: author, comments: comments, source: source); | |||||
| RssContent content; | |||||
| try { | |||||
| content = new RssContent.parse(element.findElements("content:encoded").first); | |||||
| } on StateError {} | |||||
| return new RssItem( | |||||
| title, | |||||
| description, | |||||
| link, | |||||
| categories: categories, | |||||
| guid: guid, | |||||
| pubDate: pubDate, | |||||
| author: author, | |||||
| comments: comments, | |||||
| source: source, | |||||
| content: content, | |||||
| ); | |||||
| } | } | ||||
| @override | @override | ||||
| @@ -52,6 +79,7 @@ class RssItem { | |||||
| author: $author | author: $author | ||||
| comments: $comments | comments: $comments | ||||
| source: $source | source: $source | ||||
| content: $content | |||||
| '''; | '''; | ||||
| } | } | ||||
| } | } | ||||
| @@ -72,5 +72,8 @@ void main() { | |||||
| expect(feed.items.first.source.url, "https://foo.bar.news/1?source"); | expect(feed.items.first.source.url, "https://foo.bar.news/1?source"); | ||||
| expect(feed.items.first.source.value, "Foo Bar"); | expect(feed.items.first.source.value, "Foo Bar"); | ||||
| expect(feed.items.first.comments, "https://foo.bar.news/1/comments"); | expect(feed.items.first.comments, "https://foo.bar.news/1/comments"); | ||||
| expect(feed.items.first.content.value, "<img width=\"1000\" height=\"690\" src=\"https://test.com/image_link\"/> Test content<br />"); | |||||
| expect(feed.items.first.content.images.first, "https://test.com/image_link"); | |||||
| }); | }); | ||||
| } | } | ||||
| @@ -1,5 +1,7 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
| <rss version="2.0"> | |||||
| <rss version="2.0" | |||||
| xmlns:content="http://purl.org/rss/1.0/modules/content/"> | |||||
| <channel> | <channel> | ||||
| <title>News - Foo bar News</title> | <title>News - Foo bar News</title> | ||||
| <link>https://foo.bar.news/</link> | <link>https://foo.bar.news/</link> | ||||
| @@ -44,6 +46,7 @@ | |||||
| <author>alice@foo.bar.news</author> | <author>alice@foo.bar.news</author> | ||||
| <source url="https://foo.bar.news/1?source">Foo Bar</source> | <source url="https://foo.bar.news/1?source">Foo Bar</source> | ||||
| <comments>https://foo.bar.news/1/comments</comments> | <comments>https://foo.bar.news/1/comments</comments> | ||||
| <content:encoded><![CDATA[<img width="1000" height="690" src="https://test.com/image_link"/> Test content<br />]]></content:encoded> | |||||
| </item> | </item> | ||||
| <item> | <item> | ||||
| <title>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</title> | <title>Section 1.10.32 of "de Finibus Bonorum et Malorum", written by Cicero in 45 BC</title> | ||||