Skip to content

Commit

Permalink
Sync FreshRSS items star state
Browse files Browse the repository at this point in the history
  • Loading branch information
Shinokuni committed Nov 2, 2020
1 parent c449a94 commit cfa764e
Show file tree
Hide file tree
Showing 9 changed files with 173 additions and 11 deletions.
2 changes: 2 additions & 0 deletions api/src/main/java/com/readrops/api/ApiModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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.FreshRSSFoldersAdapter
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.NextNewsService
import com.readrops.api.services.nextcloudnews.adapters.NextNewsFeedsAdapter
Expand Down Expand Up @@ -60,6 +61,7 @@ val apiModule = module {
single(named("freshrssMoshi")) {
Moshi.Builder()
.add(Types.newParameterizedType(List::class.java, Item::class.java), FreshRSSItemsAdapter())
.add(Types.newParameterizedType(List::class.java, String::class.java), FreshRSSItemsIdsAdapter())
.add(FreshRSSFeedsAdapter())
.add(FreshRSSFoldersAdapter())
.build()
Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/com/readrops/api/services/SyncResult.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,13 @@ class SyncResult {

var items: List<Item> = mutableListOf()

var starredItems: List<Item> = mutableListOf()

var feeds: List<Feed> = listOf()

var folders: List<Folder> = listOf()

var starredIds: List<String>? = null

var isError: Boolean = false
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import com.readrops.db.entities.Item;

import java.io.StringReader;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Properties;

Expand All @@ -22,9 +24,11 @@
public class FreshRSSDataSource {

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_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/";

Expand Down Expand Up @@ -99,14 +103,22 @@ public Single<SyncResult> sync(@NonNull SyncType syncType, @NonNull FreshRSSSync
syncResult.setFeeds(freshRSSFeeds);

if (syncType == SyncType.INITIAL_SYNC) {
return getItems(GOOGLE_READ, MAX_ITEMS, null);
return getItems(Arrays.asList(GOOGLE_READ, GOOGLE_STARRED), MAX_ITEMS, null);
} else {
return getItems(null, MAX_ITEMS, syncData.getLastModified());
return getItems(Collections.singletonList(GOOGLE_STARRED), MAX_ITEMS, syncData.getLastModified());
}
})
.flatMap(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);
}));
}
Expand All @@ -132,13 +144,27 @@ public Single<List<Feed>> getFeeds() {
/**
* Fetch the items
*
* @param excludeTarget type of items to exclude (currently only read items)
* @param max max number of items to fetch
* @param lastModified fetch only items created after this timestamp
* @param excludeTargets type of items to exclude (read items and starred items)
* @param max max number of items to fetch
* @param lastModified fetch only items created after this timestamp
* @return the items
*/
public Single<List<Item>> getItems(@Nullable String excludeTarget, int max, @Nullable Long lastModified) {
return api.getItems(excludeTarget, max, lastModified);
public Single<List<Item>> getItems(@Nullable List<String> excludeTargets, int max, @Nullable Long 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);
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
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.Folder;
import com.readrops.db.entities.Item;
import com.readrops.api.services.freshrss.json.FreshRSSUserInfo;

import java.util.List;

Expand Down Expand Up @@ -35,7 +35,13 @@ public interface FreshRSSService {
Single<List<Feed>> getFeeds();

@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")
Single<List<Folder>> getFolders();
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
}
}

}
Original file line number Diff line number Diff line change
@@ -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"
))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"itemRefs": [
{
"id": "1603918802432899"
},
{
"id": "1603917640272612"
},
{
"id": "1603914602186551"
},
{
"id": "1603909236998803"
},
{
"id": "1603907200327551"
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ public Observable<Feed> sync(List<Feed> feeds) {
insertItems(syncResult.getItems(), syncType == SyncType.INITIAL_SYNC);
logger.addSplit("items insertion");

insertItems(syncResult.getStarredItems(), syncType == SyncType.INITIAL_SYNC);

updateItemsStarState(syncResult.getStarredIds());

account.setLastModified(newLastModified);
database.accountDao().updateLastModified(account.getId(), newLastModified);

Expand Down Expand Up @@ -216,6 +220,8 @@ private void insertFolders(List<Folder> freshRSSFolders) {
}

private void insertItems(List<Item> items, boolean initialSync) {
List<Item> itemsToInsert = new ArrayList<>();

for (Item item : items) {
int feedId = database.feedDao().getFeedIdByRemoteId(item.getFeedRemoteId(), account.getId());

Expand All @@ -226,9 +232,21 @@ private void insertItems(List<Item> items, boolean initialSync) {

item.setFeedId(feedId);
item.setReadTime(Utils.readTimeFromString(item.getContent()));
itemsToInsert.add(item);
}

Collections.sort(items, Item::compareTo);
database.itemDao().insert(items);
if (!itemsToInsert.isEmpty()) {
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());
}
}


}
6 changes: 6 additions & 0 deletions db/src/main/java/com/readrops/db/dao/ItemDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,10 @@ public interface ItemDao extends BaseDao<Item> {

@Query("Update Item set starred = :starred, starred_changed = :starredChanged Where id = :itemId")
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);
}

0 comments on commit cfa764e

Please sign in to comment.