diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_date.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_date.xml
new file mode 100644
index 00000000..b4aaab5c
--- /dev/null
+++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_date.xml
@@ -0,0 +1,43 @@
+
+
+ Google Expands its Flutter Development Kit To Windows Apps
+
+ https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed
+
+ Google has announced that Flutter, its open source UI development kit for
+ building cross-platform software from the same codebase, is finally available for
+ Windows apps in alpha. From a report:For the world's leading desktop operating system
+ with some 1 billion installations of Windows 10 alone, this has been a long time coming.
+ Flutter's alpha incarnation was initially launched at Google's I/O developer conference
+ back in 2017, before arriving in beta less than a year later. In its original guise,
+ Flutter was designed for Android and iOS app development, but it has since expanded to
+ cover the web, MacOS, and Linux, which are currently available in various alpha or beta
+ iterations. Developers have had to consider unique platform-specific factors when
+ designing for the desktop or mobile phones, such as different screen sizes and how
+ people interact with their devices. On smartphones, people typically use touch and
+ swipe-based gestures, while keyboards and mice are commonly used on PCs and laptops.
+ This means Flutter has had to expand its support to cover the additional inputs.<p><div
+ class="share_submission" style="position:relative;"> <a class="slashpop"
+ href="http://twitter.com/home?status=Google+Expands+its+Flutter+Development+Kit+To+Windows+Apps%3A+https%3A%2F%2Fbit.ly%2F32X36MW"><img
+ src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop"
+ href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fdevelopers.slashdot.org%2Fstory%2F20%2F09%2F23%2F1616231%2Fgoogle-expands-its-flutter-development-kit-to-windows-apps%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img
+ src="https://a.fsdn.com/sd/facebook_icon_large.png"></a>
+
+
+ </div></p><p><a
+ href="https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0moreanon&utm_medium=feed">Read
+ more of this story</a> at Slashdot.</p><iframe
+ src="https://slashdot.org/slashdot-it.pl?op=discuss&id=17251868&smallembed=1"
+ style="height: 300px; width: 100%; border: none;"></iframe>
+
+ msmash
+ programming
+ how-about-that
+ developers
+ 1
+ 1,1,1,1,0,0,0
+
+
\ No newline at end of file
diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_link.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_link.xml
new file mode 100644
index 00000000..b927c248
--- /dev/null
+++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_link.xml
@@ -0,0 +1,40 @@
+
+
+ Google Expands its Flutter Development Kit To Windows Apps
+ Google has announced that Flutter, its open source UI development kit for
+ building cross-platform software from the same codebase, is finally available for
+ Windows apps in alpha. From a report:For the world's leading desktop operating system
+ with some 1 billion installations of Windows 10 alone, this has been a long time coming.
+ Flutter's alpha incarnation was initially launched at Google's I/O developer conference
+ back in 2017, before arriving in beta less than a year later. In its original guise,
+ Flutter was designed for Android and iOS app development, but it has since expanded to
+ cover the web, MacOS, and Linux, which are currently available in various alpha or beta
+ iterations. Developers have had to consider unique platform-specific factors when
+ designing for the desktop or mobile phones, such as different screen sizes and how
+ people interact with their devices. On smartphones, people typically use touch and
+ swipe-based gestures, while keyboards and mice are commonly used on PCs and laptops.
+ This means Flutter has had to expand its support to cover the additional inputs.<p><div
+ class="share_submission" style="position:relative;"> <a class="slashpop"
+ href="http://twitter.com/home?status=Google+Expands+its+Flutter+Development+Kit+To+Windows+Apps%3A+https%3A%2F%2Fbit.ly%2F32X36MW"><img
+ src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop"
+ href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fdevelopers.slashdot.org%2Fstory%2F20%2F09%2F23%2F1616231%2Fgoogle-expands-its-flutter-development-kit-to-windows-apps%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img
+ src="https://a.fsdn.com/sd/facebook_icon_large.png"></a>
+
+
+ </div></p><p><a
+ href="https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0moreanon&utm_medium=feed">Read
+ more of this story</a> at Slashdot.</p><iframe
+ src="https://slashdot.org/slashdot-it.pl?op=discuss&id=17251868&smallembed=1"
+ style="height: 300px; width: 100%; border: none;"></iframe>
+
+ msmash
+ 2020-09-23T16:15:00+00:00
+ programming
+ how-about-that
+ developers
+ 1
+ 1,1,1,1,0,0,0
+
+
\ No newline at end of file
diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_title.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_title.xml
new file mode 100644
index 00000000..96e0c123
--- /dev/null
+++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_no_title.xml
@@ -0,0 +1,43 @@
+
+
+
+ https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed
+
+ Google has announced that Flutter, its open source UI development kit for
+ building cross-platform software from the same codebase, is finally available for
+ Windows apps in alpha. From a report:For the world's leading desktop operating system
+ with some 1 billion installations of Windows 10 alone, this has been a long time coming.
+ Flutter's alpha incarnation was initially launched at Google's I/O developer conference
+ back in 2017, before arriving in beta less than a year later. In its original guise,
+ Flutter was designed for Android and iOS app development, but it has since expanded to
+ cover the web, MacOS, and Linux, which are currently available in various alpha or beta
+ iterations. Developers have had to consider unique platform-specific factors when
+ designing for the desktop or mobile phones, such as different screen sizes and how
+ people interact with their devices. On smartphones, people typically use touch and
+ swipe-based gestures, while keyboards and mice are commonly used on PCs and laptops.
+ This means Flutter has had to expand its support to cover the additional inputs.<p><div
+ class="share_submission" style="position:relative;"> <a class="slashpop"
+ href="http://twitter.com/home?status=Google+Expands+its+Flutter+Development+Kit+To+Windows+Apps%3A+https%3A%2F%2Fbit.ly%2F32X36MW"><img
+ src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop"
+ href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fdevelopers.slashdot.org%2Fstory%2F20%2F09%2F23%2F1616231%2Fgoogle-expands-its-flutter-development-kit-to-windows-apps%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img
+ src="https://a.fsdn.com/sd/facebook_icon_large.png"></a>
+
+
+ </div></p><p><a
+ href="https://developers.slashdot.org/story/20/09/23/1616231/google-expands-its-flutter-development-kit-to-windows-apps?utm_source=rss1.0moreanon&utm_medium=feed">Read
+ more of this story</a> at Slashdot.</p><iframe
+ src="https://slashdot.org/slashdot-it.pl?op=discuss&id=17251868&smallembed=1"
+ style="height: 300px; width: 100%; border: none;"></iframe>
+
+ msmash
+ 2020-09-23T16:15:00+00:00
+ programming
+ how-about-that
+ developers
+ 1
+ 1,1,1,1,0,0,0
+
+
\ No newline at end of file
diff --git a/api/src/androidTest/assets/localfeed/rss1/rss1_items_special_cases.xml b/api/src/androidTest/assets/localfeed/rss1/rss1_items_special_cases.xml
new file mode 100644
index 00000000..2624009b
--- /dev/null
+++ b/api/src/androidTest/assets/localfeed/rss1/rss1_items_special_cases.xml
@@ -0,0 +1,120 @@
+
+
+
+ Slashdot
+ https://slashdot.org/
+ News for nerds, stuff that matters
+ en-us
+ Copyright 1997-2016, SlashdotMedia. All Rights Reserved.
+ 2020-09-23T16:20:20+00:00
+ Dice
+ help@slashdot.org
+ Technology
+ 1970-01-01T00:00+00:00
+ 1
+ hourly
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Slashdot
+ https://a.fsdn.com/sd/topics/topicslashdot.gif
+ https://slashdot.org/
+
+
+ A New York Clock That Told Time Now Tells the Time Remaining
+ For more than 20 years, Metronome, which includes a 62-foot-wide 15-digit
+ electronic clock that faces Union Square in Manhattan, has been one of the city's most
+ prominent and baffling public art projects. Its digital display once told the time in
+ its own unique way, counting the hours, minutes and seconds (and fractions thereof) to
+ and from midnight. But for years observers who did not understand how it worked
+ suggested that it was measuring the acres of rainforest destroyed each year, tracking
+ the world population or even that it had something to do with pi. On Saturday Metronome
+ adopted a new ecologically sensitive mission. From a report: Now, instead of measuring
+ 24-hour cycles, it is measuring what two artists, Gan Golan and Andrew Boyd, present as
+ a critical window for action to prevent the effects of global warming from becoming
+ irreversible. On Saturday at 3:20 p.m., messages including "The Earth has a deadline"
+ began to appear on the display. Then numbers -- 7:103:15:40:07 -- showed up,
+ representing the years, days, hours, minutes and seconds until that deadline. As a
+ handful of supporters watched, the number -- which the artists said was based on
+ calculations by the Mercator Research Institute on Global Commons and Climate Change in
+ Berlin -- began ticking down, second by second.
+
+ "This is our way to shout that number from the rooftops." Mr. Golan said just before the
+ countdown began. "The world is literally counting on us." The Climate Clock, as the two
+ artists call their project, will be displayed on the 14th Street building, One Union
+ Square South, through Sept. 27, the end of Climate Week. The creators say their aim is
+ to arrange for the clock to be permanently displayed, there or elsewhere. Mr. Golan said
+ he came up with the idea to publicly illustrate the urgency of combating climate change
+ about two years ago, shortly after his daughter was born. He asked Mr. Boyd, an activist
+ from the Lower East Side, to work with him on the project.<p><div
+ class="share_submission" style="position:relative;"> <a class="slashpop"
+ href="http://twitter.com/home?status=A+New+York+Clock+That+Told+Time+Now+Tells+the+Time+Remaining%3A+https%3A%2F%2Fbit.ly%2F2HrAt2b"><img
+ src="https://a.fsdn.com/sd/twitter_icon_large.png"></a> <a class="slashpop"
+ href="http://www.facebook.com/sharer.php?u=https%3A%2F%2Fnews.slashdot.org%2Fstory%2F20%2F09%2F23%2F1420240%2Fa-new-york-clock-that-told-time-now-tells-the-time-remaining%3Futm_source%3Dslashdot%26utm_medium%3Dfacebook"><img
+ src="https://a.fsdn.com/sd/facebook_icon_large.png"></a>
+
+
+ </div></p><p><a
+ href="https://news.slashdot.org/story/20/09/23/1420240/a-new-york-clock-that-told-time-now-tells-the-time-remaining?utm_source=rss1.0moreanon&utm_medium=feed">Read
+ more of this story</a> at Slashdot.</p><iframe
+ src="https://slashdot.org/slashdot-it.pl?op=discuss&id=17251272&smallembed=1"
+ style="height: 300px; width: 100%; border: none;"></iframe>
+
+ msmash
+
+ creator 2
+ creator 3
+ creator 4
+ creator 5
+ 2020-09-23T14:10:00+00:00
+ news
+ how-about-that
+ news
+ 43
+ 43,38,33,27,6,1,0
+
+
\ No newline at end of file
diff --git a/api/src/androidTest/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapterTest.kt b/api/src/androidTest/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapterTest.kt
new file mode 100644
index 00000000..178220da
--- /dev/null
+++ b/api/src/androidTest/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapterTest.kt
@@ -0,0 +1,70 @@
+package com.readrops.api.localfeed.rss1
+
+import android.content.Context
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.readrops.api.utils.DateUtils
+import com.readrops.api.utils.ParseException
+import junit.framework.TestCase.assertEquals
+import junit.framework.TestCase.assertNotNull
+import org.junit.Assert
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class RSS1ItemsAdapterTest {
+
+ private val context: Context = InstrumentationRegistry.getInstrumentation().context
+
+ private val adapter = RSS1ItemsAdapter()
+
+ @Test
+ fun normalCasesTest() {
+ val stream = context.resources.assets.open("localfeed/rss1/rss1_feed.xml")
+
+ val items = adapter.fromXml(stream)
+ val item = items.first()
+
+ assertEquals(items.size, 4)
+ assertEquals(item.title, "Google Expands its Flutter Development Kit To Windows Apps")
+ assertEquals(item.link.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" +
+ "its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed")
+ assertEquals(item.guid.trim(), "https://developers.slashdot.org/story/20/09/23/1616231/google-expands-" +
+ "its-flutter-development-kit-to-windows-apps?utm_source=rss1.0mainlinkanon&utm_medium=feed")
+ assertEquals(item.pubDate, DateUtils.stringToLocalDateTime("2020-09-23T16:15:00+00:00"))
+ assertEquals(item.author, "msmash")
+ assertNotNull(item.description)
+ }
+
+ @Test
+ fun specialCasesTest() {
+ val stream = context.resources.assets.open("localfeed/rss1/rss1_items_special_cases.xml")
+
+ val item = adapter.fromXml(stream).first()
+
+ assertEquals(item.author, "msmash, creator 2, creator 3, creator 4, ...")
+ assertEquals(item.link, "https://news.slashdot.org/story/20/09/23/1420240/a-new-york-clock-" +
+ "that-told-time-now-tells-the-time-remaining?utm_source=rss1.0mainlinkanon&utm_medium=feed")
+ }
+
+ @Test
+ fun nullTitleTest() {
+ val stream = context.resources.assets.open("localfeed/rss1/rss1_items_no_title.xml")
+
+ Assert.assertThrows(ParseException::class.java) { adapter.fromXml(stream) }
+ }
+
+ @Test
+ fun nullLinkTest() {
+ val stream = context.resources.assets.open("localfeed/rss1/rss1_items_no_link.xml")
+
+ Assert.assertThrows(ParseException::class.java) { adapter.fromXml(stream) }
+ }
+
+ @Test
+ fun nullDateTest() {
+ val stream = context.resources.assets.open("localfeed/rss1/rss1_items_no_date.xml")
+
+ Assert.assertThrows(ParseException::class.java) { adapter.fromXml(stream) }
+ }
+}
\ No newline at end of file
diff --git a/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt
index 1641c00f..91807c54 100644
--- a/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt
+++ b/api/src/main/java/com/readrops/api/localfeed/XmlAdapter.kt
@@ -3,6 +3,7 @@ package com.readrops.api.localfeed
import com.readrops.api.localfeed.atom.ATOMFeedAdapter
import com.readrops.api.localfeed.atom.ATOMItemsAdapter
import com.readrops.api.localfeed.rss1.RSS1FeedAdapter
+import com.readrops.api.localfeed.rss1.RSS1ItemsAdapter
import com.readrops.api.localfeed.rss2.RSS2FeedAdapter
import com.readrops.api.localfeed.rss2.RSS2ItemsAdapter
import com.readrops.db.entities.Feed
@@ -25,6 +26,7 @@ interface XmlAdapter {
fun xmlItemsAdapterFactory(type: LocalRSSHelper.RSSType): XmlAdapter> {
return when (type) {
+ LocalRSSHelper.RSSType.RSS_1 -> RSS1ItemsAdapter()
LocalRSSHelper.RSSType.RSS_2 -> RSS2ItemsAdapter()
LocalRSSHelper.RSSType.ATOM -> ATOMItemsAdapter()
else -> throw IllegalArgumentException("Unknown RSS type : $type")
diff --git a/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapter.kt b/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapter.kt
new file mode 100644
index 00000000..26b6e239
--- /dev/null
+++ b/api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemsAdapter.kt
@@ -0,0 +1,68 @@
+package com.readrops.api.localfeed.rss1
+
+import com.gitlab.mvysny.konsumexml.Names
+import com.gitlab.mvysny.konsumexml.allChildrenAutoIgnore
+import com.gitlab.mvysny.konsumexml.konsumeXml
+import com.readrops.api.localfeed.XmlAdapter
+import com.readrops.api.utils.DateUtils
+import com.readrops.api.utils.ParseException
+import com.readrops.api.utils.nonNullText
+import com.readrops.api.utils.nullableText
+import com.readrops.db.entities.Item
+import java.io.InputStream
+
+class RSS1ItemsAdapter : XmlAdapter> {
+
+ override fun fromXml(inputStream: InputStream): List {
+ val konsume = inputStream.konsumeXml()
+ val items = arrayListOf()
+
+ return try {
+ konsume.child("RDF") {
+ allChildrenAutoIgnore("item") {
+ val authors = arrayListOf()
+ val about = attributes.getValueOpt("about",
+ namespace = "http://www.w3.org/1999/02/22-rdf-syntax-ns#")
+
+ val item = Item().apply {
+ allChildrenAutoIgnore(names) {
+ when (tagName) {
+ "title" -> title = nonNullText()
+ "link" -> link = nullableText()
+ "dc:date" -> pubDate = DateUtils.stringToLocalDateTime(nonNullText())
+ "dc:creator" -> authors += nullableText()
+ "description" -> description = nullableText(failOnElement = false)
+ else -> skipContents()
+ }
+ }
+ }
+
+ item.guid = item.link
+ if (authors.filterNotNull().isNotEmpty()) item.author = authors.filterNotNull().joinToString(limit = 4)
+ if (item.link == null) item.link = about
+
+ validateItem(item)
+
+ items += item
+ }
+ }
+
+ konsume.close()
+ items
+ } catch (e: Exception) {
+ throw ParseException(e.message)
+ }
+ }
+
+ private fun validateItem(item: Item) {
+ when {
+ item.title == null -> throw ParseException("Item title is required")
+ item.link == null -> throw ParseException("Item link is required")
+ item.pubDate == null -> throw ParseException("Item date is required")
+ }
+ }
+
+ companion object {
+ val names = Names.of("title", "description", "date", "link", "creator")
+ }
+}
\ No newline at end of file
diff --git a/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt b/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt
index 47df7eb9..64e73791 100644
--- a/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt
+++ b/api/src/test/java/com/readrops/api/localfeed/XmlAdapterTest.kt
@@ -3,6 +3,7 @@ package com.readrops.api.localfeed
import com.readrops.api.localfeed.atom.ATOMFeedAdapter
import com.readrops.api.localfeed.atom.ATOMItemsAdapter
import com.readrops.api.localfeed.rss1.RSS1FeedAdapter
+import com.readrops.api.localfeed.rss1.RSS1ItemsAdapter
import com.readrops.api.localfeed.rss2.RSS2FeedAdapter
import com.readrops.api.localfeed.rss2.RSS2ItemsAdapter
import junit.framework.TestCase.assertTrue
@@ -22,6 +23,7 @@ class XmlAdapterTest {
@Test
fun xmlItemsAdapterFactoryTest() {
+ assertTrue(XmlAdapter.xmlItemsAdapterFactory(LocalRSSHelper.RSSType.RSS_1) is RSS1ItemsAdapter)
assertTrue(XmlAdapter.xmlItemsAdapterFactory(LocalRSSHelper.RSSType.RSS_2) is RSS2ItemsAdapter)
assertTrue(XmlAdapter.xmlItemsAdapterFactory(LocalRSSHelper.RSSType.ATOM) is ATOMItemsAdapter)