Make Fever API implementation work with Miniflux one
* Rely on favicon_id when mapping favicon to feed * Item ids are integers in Miniflux and strings in FreshRSS * Make FeverItemsAdapter more robust to some non useful properties
This commit is contained in:
parent
326c251878
commit
b5484861ac
@ -1,7 +1,6 @@
|
|||||||
package com.readrops.api.services
|
package com.readrops.api.services
|
||||||
|
|
||||||
import com.readrops.api.services.fever.FeverCredentials
|
import com.readrops.api.services.fever.FeverCredentials
|
||||||
import com.readrops.api.services.fever.FeverService
|
|
||||||
import com.readrops.api.services.freshrss.FreshRSSCredentials
|
import com.readrops.api.services.freshrss.FreshRSSCredentials
|
||||||
import com.readrops.api.services.freshrss.FreshRSSService
|
import com.readrops.api.services.freshrss.FreshRSSService
|
||||||
import com.readrops.api.services.nextcloudnews.NextcloudNewsCredentials
|
import com.readrops.api.services.nextcloudnews.NextcloudNewsCredentials
|
||||||
@ -12,7 +11,6 @@ import com.readrops.db.entities.account.AccountType
|
|||||||
abstract class Credentials(val authorization: String?, val url: String) {
|
abstract class Credentials(val authorization: String?, val url: String) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
|
||||||
fun toCredentials(account: Account): Credentials {
|
fun toCredentials(account: Account): Credentials {
|
||||||
val endPoint = getEndPoint(account.accountType!!)
|
val endPoint = getEndPoint(account.accountType!!)
|
||||||
|
|
||||||
@ -28,7 +26,7 @@ abstract class Credentials(val authorization: String?, val url: String) {
|
|||||||
return when (accountType) {
|
return when (accountType) {
|
||||||
AccountType.FRESHRSS -> FreshRSSService.END_POINT
|
AccountType.FRESHRSS -> FreshRSSService.END_POINT
|
||||||
AccountType.NEXTCLOUD_NEWS -> NextcloudNewsService.END_POINT
|
AccountType.NEXTCLOUD_NEWS -> NextcloudNewsService.END_POINT
|
||||||
AccountType.FEVER -> FeverService.END_POINT
|
AccountType.FEVER -> ""
|
||||||
else -> throw IllegalArgumentException("Unknown account type")
|
else -> throw IllegalArgumentException("Unknown account type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ class FeverDataSource(private val service: FeverService) {
|
|||||||
|
|
||||||
var maxId = unreadIds.first()
|
var maxId = unreadIds.first()
|
||||||
items = buildList {
|
items = buildList {
|
||||||
for(index in 0 until INITIAL_SYNC_ITEMS_REQUESTS_COUNT) {
|
for (index in 0 until INITIAL_SYNC_ITEMS_REQUESTS_COUNT) {
|
||||||
val newItems = service.getItems(body, maxId, null)
|
val newItems = service.getItems(body, maxId, null)
|
||||||
|
|
||||||
if (newItems.isEmpty()) break
|
if (newItems.isEmpty()) break
|
||||||
@ -77,7 +77,8 @@ class FeverDataSource(private val service: FeverService) {
|
|||||||
|
|
||||||
if (newItems.isEmpty()) break
|
if (newItems.isEmpty()) break
|
||||||
// always take the highest id
|
// always take the highest id
|
||||||
localSinceId = newItems.maxOfOrNull { it.remoteId!!.toLong() }.toString()
|
localSinceId =
|
||||||
|
newItems.maxOfOrNull { it.remoteId!!.toLong() }.toString()
|
||||||
addAll(newItems)
|
addAll(newItems)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import kotlin.io.encoding.Base64
|
|||||||
import kotlin.io.encoding.ExperimentalEncodingApi
|
import kotlin.io.encoding.ExperimentalEncodingApi
|
||||||
|
|
||||||
data class Favicon(
|
data class Favicon(
|
||||||
val id: String,
|
val id: Int,
|
||||||
val data: ByteArray
|
val data: ByteArray
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -51,7 +51,7 @@ class FeverFaviconsAdapter {
|
|||||||
|
|
||||||
if (id > 0 && data != null) {
|
if (id > 0 && data != null) {
|
||||||
favicons += Favicon(
|
favicons += Favicon(
|
||||||
id = id.toString(),
|
id = id,
|
||||||
data = data,
|
data = data,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import com.squareup.moshi.JsonWriter
|
|||||||
|
|
||||||
data class FeverFeeds(
|
data class FeverFeeds(
|
||||||
val feeds: List<Feed> = listOf(),
|
val feeds: List<Feed> = listOf(),
|
||||||
|
val favicons: Map<Int, String> = mapOf(), // <faviconId, feedRemoteId>
|
||||||
val feedsGroups: Map<Int, List<Int>> = emptyMap()
|
val feedsGroups: Map<Int, List<Int>> = emptyMap()
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -25,6 +26,7 @@ class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
|
|||||||
override fun fromJson(reader: JsonReader): FeverFeeds = with(reader) {
|
override fun fromJson(reader: JsonReader): FeverFeeds = with(reader) {
|
||||||
return try {
|
return try {
|
||||||
val feeds = arrayListOf<Feed>()
|
val feeds = arrayListOf<Feed>()
|
||||||
|
val favicons = mutableMapOf<Int, String>()
|
||||||
val feedsGroups = mutableMapOf<Int, List<Int>>()
|
val feedsGroups = mutableMapOf<Int, List<Int>>()
|
||||||
|
|
||||||
beginObject()
|
beginObject()
|
||||||
@ -45,9 +47,10 @@ class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
|
|||||||
with(feed) {
|
with(feed) {
|
||||||
when (selectName(NAMES)) {
|
when (selectName(NAMES)) {
|
||||||
0 -> remoteId = nextInt().toString()
|
0 -> remoteId = nextInt().toString()
|
||||||
1 -> name = nextNonEmptyString()
|
1 -> favicons[nextInt()] = remoteId!!
|
||||||
2 -> url = nextNonEmptyString()
|
2 -> name = nextNonEmptyString()
|
||||||
3 -> siteUrl = nextNullableString()
|
3 -> url = nextNonEmptyString()
|
||||||
|
4 -> siteUrl = nextNullableString()
|
||||||
else -> skipValue()
|
else -> skipValue()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,13 +85,18 @@ class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
|
|||||||
endArray()
|
endArray()
|
||||||
endObject()
|
endObject()
|
||||||
|
|
||||||
FeverFeeds(feeds, feedsGroups)
|
FeverFeeds(
|
||||||
|
feeds = feeds,
|
||||||
|
favicons = favicons,
|
||||||
|
feedsGroups = feedsGroups
|
||||||
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
throw ParseException(e.message)
|
throw ParseException(e.message)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val NAMES: JsonReader.Options = JsonReader.Options.of("id", "title", "url", "site_url")
|
val NAMES: JsonReader.Options =
|
||||||
|
JsonReader.Options.of("id", "favicon_id", "title", "url", "site_url")
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -24,14 +24,11 @@ class FeverItemsAdapter {
|
|||||||
val items = arrayListOf<Item>()
|
val items = arrayListOf<Item>()
|
||||||
|
|
||||||
beginObject()
|
beginObject()
|
||||||
|
while (nextName() != "items") {
|
||||||
repeat(4) {
|
skipValue()
|
||||||
skipField()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nextName() // beginning of items array
|
|
||||||
beginArray()
|
beginArray()
|
||||||
|
|
||||||
while (hasNext()) {
|
while (hasNext()) {
|
||||||
beginObject()
|
beginObject()
|
||||||
|
|
||||||
@ -39,7 +36,13 @@ class FeverItemsAdapter {
|
|||||||
while (hasNext()) {
|
while (hasNext()) {
|
||||||
with(item) {
|
with(item) {
|
||||||
when (selectName(NAMES)) {
|
when (selectName(NAMES)) {
|
||||||
0 -> remoteId = nextNonEmptyString()
|
0 -> {
|
||||||
|
remoteId = if (reader.peek() == JsonReader.Token.STRING) {
|
||||||
|
nextNonEmptyString()
|
||||||
|
} else {
|
||||||
|
nextInt().toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
1 -> feedRemoteId = nextNonEmptyString()
|
1 -> feedRemoteId = nextNonEmptyString()
|
||||||
2 -> title = nextNonEmptyString()
|
2 -> title = nextNonEmptyString()
|
||||||
3 -> author = nextNullableString()
|
3 -> author = nextNullableString()
|
||||||
@ -58,6 +61,11 @@ class FeverItemsAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
endArray()
|
endArray()
|
||||||
|
|
||||||
|
while (peek() != JsonReader.Token.END_OBJECT) {
|
||||||
|
skipField()
|
||||||
|
}
|
||||||
|
|
||||||
endObject()
|
endObject()
|
||||||
|
|
||||||
items
|
items
|
||||||
|
@ -25,7 +25,7 @@ class FeverFaviconsAdapterTest {
|
|||||||
assertEquals(favicons.size, 3)
|
assertEquals(favicons.size, 3)
|
||||||
|
|
||||||
with(favicons[0]) {
|
with(favicons[0]) {
|
||||||
assertEquals(id, "85")
|
assertEquals(id, 85)
|
||||||
assertNotNull(data)
|
assertNotNull(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,9 @@ import kotlin.test.assertEquals
|
|||||||
class FeverFeedsAdapterTest {
|
class FeverFeedsAdapterTest {
|
||||||
|
|
||||||
val adapter = Moshi.Builder()
|
val adapter = Moshi.Builder()
|
||||||
.add(FeverFeeds::class.java, FeverFeedsAdapter())
|
.add(FeverFeeds::class.java, FeverFeedsAdapter())
|
||||||
.build()
|
.build()
|
||||||
.adapter(FeverFeeds::class.java)!!
|
.adapter(FeverFeeds::class.java)!!
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun validFeedsTest() {
|
fun validFeedsTest() {
|
||||||
@ -32,5 +32,10 @@ class FeverFeedsAdapterTest {
|
|||||||
assertEquals(key, 3)
|
assertEquals(key, 3)
|
||||||
assertEquals(value, listOf(5, 4))
|
assertEquals(value, listOf(5, 4))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with(feverFeeds.favicons.entries.first()) {
|
||||||
|
assertEquals(30, key)
|
||||||
|
assertEquals("32", value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@
|
|||||||
"feeds": [
|
"feeds": [
|
||||||
{
|
{
|
||||||
"id": 32,
|
"id": 32,
|
||||||
"favicon_id": 32,
|
"favicon_id": 30,
|
||||||
"title": "xda-developers",
|
"title": "xda-developers",
|
||||||
"url": "https:\/\/www.xda-developers.com\/feed\/",
|
"url": "https:\/\/www.xda-developers.com\/feed\/",
|
||||||
"site_url": "https:\/\/www.xda-developers.com\/",
|
"site_url": "https:\/\/www.xda-developers.com\/",
|
||||||
|
@ -2,10 +2,9 @@
|
|||||||
"api_version": 3,
|
"api_version": 3,
|
||||||
"auth": 1,
|
"auth": 1,
|
||||||
"last_refreshed_on_time": 1635849601,
|
"last_refreshed_on_time": 1635849601,
|
||||||
"total_items": 10814,
|
|
||||||
"items": [
|
"items": [
|
||||||
{
|
{
|
||||||
"id": "6",
|
"id": 6,
|
||||||
"feed_id": 2,
|
"feed_id": 2,
|
||||||
"title": "FreshRSS 1.9.0",
|
"title": "FreshRSS 1.9.0",
|
||||||
"author": "Alkarex",
|
"author": "Alkarex",
|
||||||
@ -27,7 +26,7 @@
|
|||||||
"created_on_time": 1515697500
|
"created_on_time": 1515697500
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "8",
|
"id": 8,
|
||||||
"feed_id": 2,
|
"feed_id": 2,
|
||||||
"title": "FreshRSS 1.9.0",
|
"title": "FreshRSS 1.9.0",
|
||||||
"author": "Alkarex",
|
"author": "Alkarex",
|
||||||
@ -49,7 +48,7 @@
|
|||||||
"created_on_time": 1515697500
|
"created_on_time": 1515697500
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "10",
|
"id": 10,
|
||||||
"feed_id": 2,
|
"feed_id": 2,
|
||||||
"title": "FreshRSS 1.9.0",
|
"title": "FreshRSS 1.9.0",
|
||||||
"author": "Alkarex",
|
"author": "Alkarex",
|
||||||
@ -59,5 +58,6 @@
|
|||||||
"is_read": 1,
|
"is_read": 1,
|
||||||
"created_on_time": 1515697500
|
"created_on_time": 1515697500
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"total_items": 10814
|
||||||
}
|
}
|
@ -57,7 +57,9 @@ class FeverRepository(
|
|||||||
items = newItems,
|
items = newItems,
|
||||||
feeds = newFeeds,
|
feeds = newFeeds,
|
||||||
favicons = favicons.associateBy { favicon ->
|
favicons = favicons.associateBy { favicon ->
|
||||||
feverFeeds.feeds.find { it.remoteId == favicon.id }!!
|
val feedId = feverFeeds.favicons.entries.find { it.key == favicon.id }!!.value
|
||||||
|
|
||||||
|
feverFeeds.feeds.find { it.remoteId == feedId }!!
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user