Skip to content

Commit 455194e

Browse files
committed
Parse RSS1/RSS2/ATOM/JSONFeed tags/categories
1 parent a649527 commit 455194e

File tree

17 files changed

+135
-17
lines changed

17 files changed

+135
-17
lines changed

api/src/main/java/com/readrops/api/localfeed/atom/ATOMItemAdapter.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import com.readrops.api.utils.extensions.nonNullText
1010
import com.readrops.api.utils.extensions.nullableText
1111
import com.readrops.api.utils.extensions.nullableTextRecursively
1212
import com.readrops.db.entities.Item
13+
import com.readrops.db.entities.Tag
1314
import com.readrops.db.util.DateUtils
1415
import java.time.LocalDateTime
1516

1617
class ATOMItemAdapter : XmlAdapter<Item> {
1718

1819
override fun fromXml(konsumer: Konsumer): Item {
1920
val item = Item()
21+
val tags = arrayListOf<Tag>()
2022

2123
return item.apply {
2224
konsumer.allChildrenAutoIgnore(names) {
@@ -36,10 +38,18 @@ class ATOMItemAdapter : XmlAdapter<Item> {
3638
"summary" -> description = nullableTextRecursively()
3739
"content" -> content = nullableTextRecursively()
3840
"media:group" -> RSSMedia.parseMediaGroup(this, item)
41+
"category" -> {
42+
attributes.getValueOrNull("term")?.let {
43+
tags += Tag(name = it)
44+
}
45+
}
46+
3947
else -> skipContents()
4048
}
4149
}
4250

51+
this.tags = tags
52+
4353
validateItem(this)
4454
if (pubDate == null) pubDate = LocalDateTime.now()
4555
if (remoteId == null) remoteId = link
@@ -61,7 +71,7 @@ class ATOMItemAdapter : XmlAdapter<Item> {
6171
companion object {
6272
val names = Names.of(
6373
"title", "id", "updated", "link", "author", "summary",
64-
"content", "group", "published"
74+
"content", "group", "published", "category"
6575
)
6676
}
6777
}

api/src/main/java/com/readrops/api/localfeed/json/JSONItemsAdapter.kt

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import com.readrops.api.utils.exceptions.ParseException
55
import com.readrops.api.utils.extensions.nextNonEmptyString
66
import com.readrops.api.utils.extensions.nextNullableString
77
import com.readrops.db.entities.Item
8+
import com.readrops.db.entities.Tag
89
import com.readrops.db.util.DateUtils
910
import com.squareup.moshi.JsonAdapter
1011
import com.squareup.moshi.JsonReader
@@ -42,6 +43,7 @@ class JSONItemsAdapter : JsonAdapter<List<Item>>() {
4243
7 -> pubDate = DateUtils.parse(nextNullableString())
4344
8 -> author = parseAuthor(reader) // jsonfeed 1.0
4445
9 -> author = parseAuthors(reader) // jsonfeed 1.1
46+
10 -> tags = parseTags(reader)
4547
else -> skipValue()
4648
}
4749
}
@@ -88,14 +90,41 @@ class JSONItemsAdapter : JsonAdapter<List<Item>>() {
8890
authors.filterNotNull().joinToString(limit = AUTHORS_MAX) else null
8991
}
9092

93+
private fun parseTags(reader: JsonReader): List<Tag> = with(reader) {
94+
val tags = arrayListOf<Tag>()
95+
beginArray()
96+
97+
while (hasNext()) {
98+
val name = nextNullableString()
99+
100+
if (!name.isNullOrEmpty()) {
101+
tags += Tag(name = name)
102+
}
103+
}
104+
105+
endArray()
106+
tags
107+
}
108+
91109
private fun validateItem(item: Item): Boolean = when {
92110
item.title == null -> throw ParseException("Item title is required")
93111
item.link == null -> throw ParseException("Item link is required")
94112
else -> true
95113
}
96114

97115
companion object {
98-
val names: JsonReader.Options = JsonReader.Options.of("id", "url", "title",
99-
"content_html", "content_text", "summary", "image", "date_published", "author", "authors")
116+
val names: JsonReader.Options = JsonReader.Options.of(
117+
"id",
118+
"url",
119+
"title",
120+
"content_html",
121+
"content_text",
122+
"summary",
123+
"image",
124+
"date_published",
125+
"author",
126+
"authors",
127+
"tags"
128+
)
100129
}
101130
}

api/src/main/java/com/readrops/api/localfeed/rss1/RSS1ItemAdapter.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import com.readrops.api.utils.extensions.nonNullText
1010
import com.readrops.api.utils.extensions.nullableText
1111
import com.readrops.api.utils.extensions.nullableTextRecursively
1212
import com.readrops.db.entities.Item
13+
import com.readrops.db.entities.Tag
1314
import com.readrops.db.util.DateUtils
1415
import java.time.LocalDateTime
1516

1617
class RSS1ItemAdapter : XmlAdapter<Item> {
1718

1819
override fun fromXml(konsumer: Konsumer): Item {
1920
val item = Item()
21+
val tags = arrayListOf<Tag>()
2022

2123
val authors = arrayListOf<String?>()
2224
val about = konsumer.attributes.getValueOrNull(
@@ -33,10 +35,17 @@ class RSS1ItemAdapter : XmlAdapter<Item> {
3335
"dc:creator" -> authors += nullableText()
3436
"description" -> description = nullableTextRecursively()
3537
"content:encoded" -> content = nullableTextRecursively()
38+
"dc:subject" -> {
39+
nullableText()?.let {
40+
tags += Tag(name = it)
41+
}
42+
}
43+
3644
else -> skipContents()
3745
}
3846
}
3947

48+
this.tags = tags
4049
validateItem(this)
4150

4251
if (pubDate == null) pubDate = LocalDateTime.now()
@@ -54,6 +63,7 @@ class RSS1ItemAdapter : XmlAdapter<Item> {
5463
}
5564

5665
companion object {
57-
val names = Names.of("title", "description", "date", "link", "creator", "encoded")
66+
val names =
67+
Names.of("title", "description", "date", "link", "creator", "encoded", "subject")
5868
}
5969
}

api/src/main/java/com/readrops/api/localfeed/rss2/RSS2ItemAdapter.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import com.readrops.api.utils.extensions.nonNullText
1212
import com.readrops.api.utils.extensions.nullableText
1313
import com.readrops.api.utils.extensions.nullableTextRecursively
1414
import com.readrops.db.entities.Item
15+
import com.readrops.db.entities.Tag
1516
import com.readrops.db.util.DateUtils
1617
import java.time.LocalDateTime
1718

@@ -21,6 +22,7 @@ class RSS2ItemAdapter : XmlAdapter<Item> {
2122
val item = Item()
2223

2324
val creators = arrayListOf<String?>()
25+
val tags = arrayListOf<Tag>()
2426

2527
return item.apply {
2628
konsumer.allChildrenAutoIgnore(names) {
@@ -37,9 +39,17 @@ class RSS2ItemAdapter : XmlAdapter<Item> {
3739
"enclosure" -> RSSMedia.parseMediaContent(this, item = this@apply)
3840
"media:content" -> RSSMedia.parseMediaContent(this, item = this@apply)
3941
"media:group" -> RSSMedia.parseMediaGroup(this, item = this@apply)
42+
"category" -> {
43+
nullableText()?.let {
44+
tags += Tag(name = it)
45+
}
46+
}
47+
4048
else -> skipContents() // for example media:description
4149
}
4250
}
51+
52+
this.tags = tags
4353
finalizeItem(this, creators)
4454
}
4555
}
@@ -63,7 +73,7 @@ class RSS2ItemAdapter : XmlAdapter<Item> {
6373
companion object {
6474
val names = Names.of(
6575
"title", "link", "author", "creator", "pubDate", "date",
66-
"guid", "description", "encoded", "enclosure", "content", "group"
76+
"guid", "description", "encoded", "enclosure", "content", "group", "category"
6777
)
6878
}
6979
}

api/src/test/java/com/readrops/api/localfeed/atom/ATOMAdapterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class ATOMAdapterTest {
3838
assertEquals(description, "Summary")
3939
assertEquals(remoteId, "tag:github.com,2008:Grit::Commit/c15f093a1bc4211e85f8d1817c9073e307afe5ac")
4040
TestCase.assertNotNull(content)
41+
assertEquals(3, tags.size)
4142
}
4243
}
4344

api/src/test/java/com/readrops/api/localfeed/json/JSONFeedAdapterTest.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ class JSONFeedAdapterTest {
4747
assertEquals(pubDate, DateUtils.parse("2017-09-25T14:27:27-07:00"))
4848
assertEquals(author, "Author 1")
4949
TestCase.assertNotNull(content)
50+
51+
assertEquals(3, tags.size)
5052
}
5153

5254
}

api/src/test/java/com/readrops/api/localfeed/rss1/RSS1AdapterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class RSS1AdapterTest {
4242
assertEquals(author, "msmash")
4343
assertNotNull(description)
4444
assertEquals(content, "content:encoded")
45+
assertEquals(1, tags.size)
4546
}
4647
}
4748

api/src/test/java/com/readrops/api/localfeed/rss2/RSS2AdapterTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class RSS2AdapterTest {
3838
assertEquals(author, "Author 1")
3939
assertEquals(description, "<a href=\"https://news.ycombinator.com/item?id=24273602\">Comments</a>")
4040
assertEquals(remoteId, "https://www.bbc.com/news/world-africa-53887947")
41+
assertEquals(3, tags.size)
4142
}
4243
}
4344

api/src/test/resources/localfeed/atom/atom_items.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
<content type="html">
2323
&lt;pre style=&#39;white-space:pre-wrap;width:81ex&#39;&gt;Add an option to open item url in custom tab&lt;/pre&gt;
2424
</content>
25+
<category term="category 1"/>
26+
<category term="category 2"/>
27+
<category term="category 3"/>
2528
</entry>
2629
<entry>
2730
<id>tag:github.com,2008:Grit::Commit/e0945823eecf269e5beea646ac5d7e630e08afbf</id>

api/src/test/resources/localfeed/json/json_feed.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818
"author": {
1919
"url": "this is an url",
2020
"name": "Author 1"
21-
}
21+
},
22+
"tags": [
23+
"Tag 1",
24+
"Tag 2",
25+
"Tag 3"
26+
]
2227
},
2328
{
2429
"id": "http://flyingmeat.com/blog/archives/2018/2/acorn_6.1_is_out.html",

0 commit comments

Comments
 (0)