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:
Shinokuni 2024-08-15 17:06:56 +02:00
parent 326c251878
commit b5484861ac
10 changed files with 51 additions and 29 deletions

View File

@ -1,7 +1,6 @@
package com.readrops.api.services
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.FreshRSSService
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) {
companion object {
@JvmStatic
fun toCredentials(account: Account): Credentials {
val endPoint = getEndPoint(account.accountType!!)
@ -28,7 +26,7 @@ abstract class Credentials(val authorization: String?, val url: String) {
return when (accountType) {
AccountType.FRESHRSS -> FreshRSSService.END_POINT
AccountType.NEXTCLOUD_NEWS -> NextcloudNewsService.END_POINT
AccountType.FEVER -> FeverService.END_POINT
AccountType.FEVER -> ""
else -> throw IllegalArgumentException("Unknown account type")
}
}

View File

@ -43,7 +43,7 @@ class FeverDataSource(private val service: FeverService) {
var maxId = unreadIds.first()
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)
if (newItems.isEmpty()) break
@ -77,7 +77,8 @@ class FeverDataSource(private val service: FeverService) {
if (newItems.isEmpty()) break
// always take the highest id
localSinceId = newItems.maxOfOrNull { it.remoteId!!.toLong() }.toString()
localSinceId =
newItems.maxOfOrNull { it.remoteId!!.toLong() }.toString()
addAll(newItems)
}

View File

@ -10,7 +10,7 @@ import kotlin.io.encoding.Base64
import kotlin.io.encoding.ExperimentalEncodingApi
data class Favicon(
val id: String,
val id: Int,
val data: ByteArray
)
@ -51,7 +51,7 @@ class FeverFaviconsAdapter {
if (id > 0 && data != null) {
favicons += Favicon(
id = id.toString(),
id = id,
data = data,
)
}

View File

@ -12,6 +12,7 @@ import com.squareup.moshi.JsonWriter
data class FeverFeeds(
val feeds: List<Feed> = listOf(),
val favicons: Map<Int, String> = mapOf(), // <faviconId, feedRemoteId>
val feedsGroups: Map<Int, List<Int>> = emptyMap()
)
@ -25,6 +26,7 @@ class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
override fun fromJson(reader: JsonReader): FeverFeeds = with(reader) {
return try {
val feeds = arrayListOf<Feed>()
val favicons = mutableMapOf<Int, String>()
val feedsGroups = mutableMapOf<Int, List<Int>>()
beginObject()
@ -45,9 +47,10 @@ class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
with(feed) {
when (selectName(NAMES)) {
0 -> remoteId = nextInt().toString()
1 -> name = nextNonEmptyString()
2 -> url = nextNonEmptyString()
3 -> siteUrl = nextNullableString()
1 -> favicons[nextInt()] = remoteId!!
2 -> name = nextNonEmptyString()
3 -> url = nextNonEmptyString()
4 -> siteUrl = nextNullableString()
else -> skipValue()
}
}
@ -82,13 +85,18 @@ class FeverFeedsAdapter : JsonAdapter<FeverFeeds>() {
endArray()
endObject()
FeverFeeds(feeds, feedsGroups)
FeverFeeds(
feeds = feeds,
favicons = favicons,
feedsGroups = feedsGroups
)
} catch (e: Exception) {
throw ParseException(e.message)
}
}
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")
}
}

View File

@ -24,14 +24,11 @@ class FeverItemsAdapter {
val items = arrayListOf<Item>()
beginObject()
repeat(4) {
skipField()
while (nextName() != "items") {
skipValue()
}
nextName() // beginning of items array
beginArray()
while (hasNext()) {
beginObject()
@ -39,7 +36,13 @@ class FeverItemsAdapter {
while (hasNext()) {
with(item) {
when (selectName(NAMES)) {
0 -> remoteId = nextNonEmptyString()
0 -> {
remoteId = if (reader.peek() == JsonReader.Token.STRING) {
nextNonEmptyString()
} else {
nextInt().toString()
}
}
1 -> feedRemoteId = nextNonEmptyString()
2 -> title = nextNonEmptyString()
3 -> author = nextNullableString()
@ -58,6 +61,11 @@ class FeverItemsAdapter {
}
endArray()
while (peek() != JsonReader.Token.END_OBJECT) {
skipField()
}
endObject()
items

View File

@ -25,7 +25,7 @@ class FeverFaviconsAdapterTest {
assertEquals(favicons.size, 3)
with(favicons[0]) {
assertEquals(id, "85")
assertEquals(id, 85)
assertNotNull(data)
}
}

View File

@ -32,5 +32,10 @@ class FeverFeedsAdapterTest {
assertEquals(key, 3)
assertEquals(value, listOf(5, 4))
}
with(feverFeeds.favicons.entries.first()) {
assertEquals(30, key)
assertEquals("32", value)
}
}
}

View File

@ -5,7 +5,7 @@
"feeds": [
{
"id": 32,
"favicon_id": 32,
"favicon_id": 30,
"title": "xda-developers",
"url": "https:\/\/www.xda-developers.com\/feed\/",
"site_url": "https:\/\/www.xda-developers.com\/",

View File

@ -2,10 +2,9 @@
"api_version": 3,
"auth": 1,
"last_refreshed_on_time": 1635849601,
"total_items": 10814,
"items": [
{
"id": "6",
"id": 6,
"feed_id": 2,
"title": "FreshRSS 1.9.0",
"author": "Alkarex",
@ -27,7 +26,7 @@
"created_on_time": 1515697500
},
{
"id": "8",
"id": 8,
"feed_id": 2,
"title": "FreshRSS 1.9.0",
"author": "Alkarex",
@ -49,7 +48,7 @@
"created_on_time": 1515697500
},
{
"id": "10",
"id": 10,
"feed_id": 2,
"title": "FreshRSS 1.9.0",
"author": "Alkarex",
@ -59,5 +58,6 @@
"is_read": 1,
"created_on_time": 1515697500
}
]
],
"total_items": 10814
}

View File

@ -57,7 +57,9 @@ class FeverRepository(
items = newItems,
feeds = newFeeds,
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 }!!
}
)
}