Sync FreshRSS items star state
This commit is contained in:
parent
c449a94260
commit
cfa764e78b
@ -6,6 +6,7 @@ import com.readrops.api.services.freshrss.FreshRSSService
|
|||||||
import com.readrops.api.services.freshrss.adapters.FreshRSSFeedsAdapter
|
import com.readrops.api.services.freshrss.adapters.FreshRSSFeedsAdapter
|
||||||
import com.readrops.api.services.freshrss.adapters.FreshRSSFoldersAdapter
|
import com.readrops.api.services.freshrss.adapters.FreshRSSFoldersAdapter
|
||||||
import com.readrops.api.services.freshrss.adapters.FreshRSSItemsAdapter
|
import com.readrops.api.services.freshrss.adapters.FreshRSSItemsAdapter
|
||||||
|
import com.readrops.api.services.freshrss.adapters.FreshRSSItemsIdsAdapter
|
||||||
import com.readrops.api.services.nextcloudnews.NextNewsDataSource
|
import com.readrops.api.services.nextcloudnews.NextNewsDataSource
|
||||||
import com.readrops.api.services.nextcloudnews.NextNewsService
|
import com.readrops.api.services.nextcloudnews.NextNewsService
|
||||||
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFeedsAdapter
|
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFeedsAdapter
|
||||||
@ -60,6 +61,7 @@ val apiModule = module {
|
|||||||
single(named("freshrssMoshi")) {
|
single(named("freshrssMoshi")) {
|
||||||
Moshi.Builder()
|
Moshi.Builder()
|
||||||
.add(Types.newParameterizedType(List::class.java, Item::class.java), FreshRSSItemsAdapter())
|
.add(Types.newParameterizedType(List::class.java, Item::class.java), FreshRSSItemsAdapter())
|
||||||
|
.add(Types.newParameterizedType(List::class.java, String::class.java), FreshRSSItemsIdsAdapter())
|
||||||
.add(FreshRSSFeedsAdapter())
|
.add(FreshRSSFeedsAdapter())
|
||||||
.add(FreshRSSFoldersAdapter())
|
.add(FreshRSSFoldersAdapter())
|
||||||
.build()
|
.build()
|
||||||
|
@ -8,9 +8,13 @@ class SyncResult {
|
|||||||
|
|
||||||
var items: List<Item> = mutableListOf()
|
var items: List<Item> = mutableListOf()
|
||||||
|
|
||||||
|
var starredItems: List<Item> = mutableListOf()
|
||||||
|
|
||||||
var feeds: List<Feed> = listOf()
|
var feeds: List<Feed> = listOf()
|
||||||
|
|
||||||
var folders: List<Folder> = listOf()
|
var folders: List<Folder> = listOf()
|
||||||
|
|
||||||
|
var starredIds: List<String>? = null
|
||||||
|
|
||||||
var isError: Boolean = false
|
var isError: Boolean = false
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ import com.readrops.db.entities.Folder;
|
|||||||
import com.readrops.db.entities.Item;
|
import com.readrops.db.entities.Item;
|
||||||
|
|
||||||
import java.io.StringReader;
|
import java.io.StringReader;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
|
||||||
@ -22,9 +24,11 @@ import okhttp3.RequestBody;
|
|||||||
public class FreshRSSDataSource {
|
public class FreshRSSDataSource {
|
||||||
|
|
||||||
private static final int MAX_ITEMS = 5000;
|
private static final int MAX_ITEMS = 5000;
|
||||||
|
private static final int MAX_STARRED_ITEMS = 999;
|
||||||
|
|
||||||
public static final String GOOGLE_READ = "user/-/state/com.google/read";
|
public static final String GOOGLE_READ = "user/-/state/com.google/read";
|
||||||
public static final String GOOGLE_STARRED = "user/-/state/com.google/starred";
|
public static final String GOOGLE_STARRED = "user/-/state/com.google/starred";
|
||||||
|
public static final String GOOGLE_READING_LIST = "user/-/state/com.google/reading-list";
|
||||||
|
|
||||||
private static final String FEED_PREFIX = "feed/";
|
private static final String FEED_PREFIX = "feed/";
|
||||||
|
|
||||||
@ -99,14 +103,22 @@ public class FreshRSSDataSource {
|
|||||||
syncResult.setFeeds(freshRSSFeeds);
|
syncResult.setFeeds(freshRSSFeeds);
|
||||||
|
|
||||||
if (syncType == SyncType.INITIAL_SYNC) {
|
if (syncType == SyncType.INITIAL_SYNC) {
|
||||||
return getItems(GOOGLE_READ, MAX_ITEMS, null);
|
return getItems(Arrays.asList(GOOGLE_READ, GOOGLE_STARRED), MAX_ITEMS, null);
|
||||||
} else {
|
} else {
|
||||||
return getItems(null, MAX_ITEMS, syncData.getLastModified());
|
return getItems(Collections.singletonList(GOOGLE_STARRED), MAX_ITEMS, syncData.getLastModified());
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.flatMap(freshRSSItems -> {
|
.flatMap(freshRSSItems -> {
|
||||||
syncResult.setItems(freshRSSItems);
|
syncResult.setItems(freshRSSItems);
|
||||||
|
|
||||||
|
return getStarredItems(MAX_STARRED_ITEMS);
|
||||||
|
}).flatMap(starredItems -> {
|
||||||
|
syncResult.setStarredItems(starredItems);
|
||||||
|
|
||||||
|
return getItemsIds(null, GOOGLE_STARRED, MAX_STARRED_ITEMS);
|
||||||
|
}).flatMap(starredIds -> {
|
||||||
|
syncResult.setStarredIds(starredIds);
|
||||||
|
|
||||||
return Single.just(syncResult);
|
return Single.just(syncResult);
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
@ -132,13 +144,27 @@ public class FreshRSSDataSource {
|
|||||||
/**
|
/**
|
||||||
* Fetch the items
|
* Fetch the items
|
||||||
*
|
*
|
||||||
* @param excludeTarget type of items to exclude (currently only read items)
|
* @param excludeTargets type of items to exclude (read items and starred items)
|
||||||
* @param max max number of items to fetch
|
* @param max max number of items to fetch
|
||||||
* @param lastModified fetch only items created after this timestamp
|
* @param lastModified fetch only items created after this timestamp
|
||||||
* @return the items
|
* @return the items
|
||||||
*/
|
*/
|
||||||
public Single<List<Item>> getItems(@Nullable String excludeTarget, int max, @Nullable Long lastModified) {
|
public Single<List<Item>> getItems(@Nullable List<String> excludeTargets, int max, @Nullable Long lastModified) {
|
||||||
return api.getItems(excludeTarget, max, lastModified);
|
return api.getItems(excludeTargets, max, lastModified);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch starred items
|
||||||
|
*
|
||||||
|
* @param max max number of items to fetch
|
||||||
|
* @return items
|
||||||
|
*/
|
||||||
|
public Single<List<Item>> getStarredItems(int max) {
|
||||||
|
return api.getStarredItems(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Single<List<String>> getItemsIds(String excludeTarget, String includeTarget, int max) {
|
||||||
|
return api.getItemsIds(excludeTarget, includeTarget, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
package com.readrops.api.services.freshrss;
|
package com.readrops.api.services.freshrss;
|
||||||
|
|
||||||
|
import com.readrops.api.services.freshrss.json.FreshRSSUserInfo;
|
||||||
import com.readrops.db.entities.Feed;
|
import com.readrops.db.entities.Feed;
|
||||||
import com.readrops.db.entities.Folder;
|
import com.readrops.db.entities.Folder;
|
||||||
import com.readrops.db.entities.Item;
|
import com.readrops.db.entities.Item;
|
||||||
import com.readrops.api.services.freshrss.json.FreshRSSUserInfo;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@ -35,7 +35,13 @@ public interface FreshRSSService {
|
|||||||
Single<List<Feed>> getFeeds();
|
Single<List<Feed>> getFeeds();
|
||||||
|
|
||||||
@GET("reader/api/0/stream/contents/user/-/state/com.google/reading-list")
|
@GET("reader/api/0/stream/contents/user/-/state/com.google/reading-list")
|
||||||
Single<List<Item>> getItems(@Query("xt") String excludeTarget, @Query("n") int max, @Query("ot") Long lastModified);
|
Single<List<Item>> getItems(@Query("xt") List<String> excludeTarget, @Query("n") int max, @Query("ot") Long lastModified);
|
||||||
|
|
||||||
|
@GET("reader/api/0/stream/contents/user/-/state/com.google/starred")
|
||||||
|
Single<List<Item>> getStarredItems(@Query("n") int max);
|
||||||
|
|
||||||
|
@GET("reader/api/0/stream/items/ids")
|
||||||
|
Single<List<String>> getItemsIds(@Query("xt") String excludeTarget, @Query("s") String includeTarget, @Query("n") int max);
|
||||||
|
|
||||||
@GET("reader/api/0/tag/list?output=json")
|
@GET("reader/api/0/tag/list?output=json")
|
||||||
Single<List<Folder>> getFolders();
|
Single<List<Folder>> getFolders();
|
||||||
|
@ -0,0 +1,51 @@
|
|||||||
|
package com.readrops.api.services.freshrss.adapters
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import com.readrops.api.utils.exceptions.ParseException
|
||||||
|
import com.readrops.api.utils.extensions.nextNonEmptyString
|
||||||
|
import com.squareup.moshi.JsonAdapter
|
||||||
|
import com.squareup.moshi.JsonReader
|
||||||
|
import com.squareup.moshi.JsonWriter
|
||||||
|
|
||||||
|
class FreshRSSItemsIdsAdapter : JsonAdapter<List<String>>() {
|
||||||
|
|
||||||
|
override fun toJson(writer: JsonWriter, value: List<String>?) {
|
||||||
|
// not useful here
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("CheckResult")
|
||||||
|
override fun fromJson(reader: JsonReader): List<String>? = with(reader) {
|
||||||
|
val ids = arrayListOf<String>()
|
||||||
|
|
||||||
|
return try {
|
||||||
|
beginObject()
|
||||||
|
nextName()
|
||||||
|
beginArray()
|
||||||
|
|
||||||
|
while (hasNext()) {
|
||||||
|
beginObject()
|
||||||
|
|
||||||
|
when (nextName()) {
|
||||||
|
"id" -> {
|
||||||
|
val value = nextNonEmptyString()
|
||||||
|
ids += "tag:google.com,2005:reader/item/${
|
||||||
|
value.toLong()
|
||||||
|
.toString(16).padStart(value.length, '0')
|
||||||
|
}"
|
||||||
|
}
|
||||||
|
else -> skipValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
endObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
endArray()
|
||||||
|
endObject()
|
||||||
|
|
||||||
|
ids
|
||||||
|
} catch (e: Exception) {
|
||||||
|
throw ParseException(e.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
package com.readrops.api.services.freshrss.adapters
|
||||||
|
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
|
import junit.framework.TestCase.assertEquals
|
||||||
|
import okio.Buffer
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class FreshRSSItemsIdsAdapterTest {
|
||||||
|
|
||||||
|
private val adapter = Moshi.Builder()
|
||||||
|
.add(Types.newParameterizedType(List::class.java, String::class.java), FreshRSSItemsIdsAdapter())
|
||||||
|
.build()
|
||||||
|
.adapter<List<String>>(Types.newParameterizedType(List::class.java, String::class.java))
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun validIdsTest() {
|
||||||
|
val stream = javaClass.classLoader!!.getResourceAsStream("services/freshrss/adapters/items_starred_ids.json")
|
||||||
|
|
||||||
|
val ids = adapter.fromJson(Buffer().readFrom(stream))!!
|
||||||
|
|
||||||
|
assertEquals(ids, listOf(
|
||||||
|
"tag:google.com,2005:reader/item/0005b2c17277b383",
|
||||||
|
"tag:google.com,2005:reader/item/0005b2c12d328ae4",
|
||||||
|
"tag:google.com,2005:reader/item/0005b2c0781d0737",
|
||||||
|
"tag:google.com,2005:reader/item/0005b2bf3852c293",
|
||||||
|
"tag:google.com,2005:reader/item/0005b2bebeed9f7f"
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"itemRefs": [
|
||||||
|
{
|
||||||
|
"id": "1603918802432899"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1603917640272612"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1603914602186551"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1603909236998803"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "1603907200327551"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -107,6 +107,10 @@ public class FreshRSSRepository extends ARepository {
|
|||||||
insertItems(syncResult.getItems(), syncType == SyncType.INITIAL_SYNC);
|
insertItems(syncResult.getItems(), syncType == SyncType.INITIAL_SYNC);
|
||||||
logger.addSplit("items insertion");
|
logger.addSplit("items insertion");
|
||||||
|
|
||||||
|
insertItems(syncResult.getStarredItems(), syncType == SyncType.INITIAL_SYNC);
|
||||||
|
|
||||||
|
updateItemsStarState(syncResult.getStarredIds());
|
||||||
|
|
||||||
account.setLastModified(newLastModified);
|
account.setLastModified(newLastModified);
|
||||||
database.accountDao().updateLastModified(account.getId(), newLastModified);
|
database.accountDao().updateLastModified(account.getId(), newLastModified);
|
||||||
|
|
||||||
@ -216,6 +220,8 @@ public class FreshRSSRepository extends ARepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void insertItems(List<Item> items, boolean initialSync) {
|
private void insertItems(List<Item> items, boolean initialSync) {
|
||||||
|
List<Item> itemsToInsert = new ArrayList<>();
|
||||||
|
|
||||||
for (Item item : items) {
|
for (Item item : items) {
|
||||||
int feedId = database.feedDao().getFeedIdByRemoteId(item.getFeedRemoteId(), account.getId());
|
int feedId = database.feedDao().getFeedIdByRemoteId(item.getFeedRemoteId(), account.getId());
|
||||||
|
|
||||||
@ -226,9 +232,21 @@ public class FreshRSSRepository extends ARepository {
|
|||||||
|
|
||||||
item.setFeedId(feedId);
|
item.setFeedId(feedId);
|
||||||
item.setReadTime(Utils.readTimeFromString(item.getContent()));
|
item.setReadTime(Utils.readTimeFromString(item.getContent()));
|
||||||
|
itemsToInsert.add(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
Collections.sort(items, Item::compareTo);
|
if (!itemsToInsert.isEmpty()) {
|
||||||
database.itemDao().insert(items);
|
Collections.sort(itemsToInsert, Item::compareTo);
|
||||||
|
database.itemDao().insert(itemsToInsert);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void updateItemsStarState(List<String> itemsIds) {
|
||||||
|
if (itemsIds != null && !itemsIds.isEmpty()) {
|
||||||
|
database.itemDao().unstarItems(itemsIds, account.getId());
|
||||||
|
database.itemDao().starItems(itemsIds, account.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -94,4 +94,10 @@ public interface ItemDao extends BaseDao<Item> {
|
|||||||
|
|
||||||
@Query("Update Item set starred = :starred, starred_changed = :starredChanged Where id = :itemId")
|
@Query("Update Item set starred = :starred, starred_changed = :starredChanged Where id = :itemId")
|
||||||
Completable setStarState(int itemId, boolean starred, boolean starredChanged);
|
Completable setStarState(int itemId, boolean starred, boolean starredChanged);
|
||||||
|
|
||||||
|
@Query("Update Item set starred = 1 Where remoteId In (:ids) And feed_id In (Select id From Feed Where account_id = :accountId)")
|
||||||
|
void starItems(List<String> ids, int accountId);
|
||||||
|
|
||||||
|
@Query("Update Item set starred = 0 Where remoteId Not In (:ids) And feed_id In (Select id From Feed Where account_id = :accountId)")
|
||||||
|
void unstarItems(List<String> ids, int accountId);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user