mirror of
https://gitlab.futo.org/videostreaming/grayjay.git
synced 2025-04-20 03:24:50 +00:00
WIP Channel content cache
This commit is contained in:
parent
c49b9f7841
commit
aeb29c54cd
3 changed files with 170 additions and 3 deletions
106
app/src/main/java/com/futo/platformplayer/states/StateCache.kt
Normal file
106
app/src/main/java/com/futo/platformplayer/states/StateCache.kt
Normal file
|
@ -0,0 +1,106 @@
|
|||
package com.futo.platformplayer.states
|
||||
|
||||
import com.futo.platformplayer.api.media.models.contents.IPlatformContent
|
||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent
|
||||
import com.futo.platformplayer.api.media.structures.DedupContentPager
|
||||
import com.futo.platformplayer.api.media.structures.IPager
|
||||
import com.futo.platformplayer.api.media.structures.MultiChronoContentPager
|
||||
import com.futo.platformplayer.api.media.structures.PlatformContentPager
|
||||
import com.futo.platformplayer.cache.ChannelContentCache
|
||||
import com.futo.platformplayer.logging.Logger
|
||||
import com.futo.platformplayer.polycentric.PolycentricCache
|
||||
import com.futo.platformplayer.resolveChannelUrl
|
||||
import com.futo.platformplayer.serializers.PlatformContentSerializer
|
||||
import com.futo.platformplayer.stores.FragmentedStorage
|
||||
import com.futo.platformplayer.stores.db.ManagedDBStore
|
||||
import com.futo.platformplayer.stores.db.types.DBChannelCache
|
||||
import com.futo.platformplayer.stores.db.types.DBHistory
|
||||
import com.futo.platformplayer.toSafeFileName
|
||||
import java.time.OffsetDateTime
|
||||
|
||||
class StateCache {
|
||||
private val _channelCache = ManagedDBStore.create("channelCache", DBChannelCache.Descriptor(), PlatformContentSerializer())
|
||||
.load();
|
||||
|
||||
fun clear() {
|
||||
_channelCache.deleteAll();
|
||||
}
|
||||
fun clearToday() {
|
||||
val today = _channelCache.queryGreater(DBChannelCache.Index::datetime, OffsetDateTime.now().toEpochSecond());
|
||||
for(content in today)
|
||||
_channelCache.delete(content);
|
||||
}
|
||||
|
||||
fun getChannelCachePager(channelUrl: String): IPager<IPlatformContent> {
|
||||
return _channelCache.queryPager(DBChannelCache.Index::channelUrl, channelUrl, 20) {
|
||||
it.obj;
|
||||
}
|
||||
}
|
||||
fun getSubscriptionCachePager(): DedupContentPager {
|
||||
Logger.i(TAG, "Subscriptions CachePager get subscriptions");
|
||||
val subs = StateSubscriptions.instance.getSubscriptions();
|
||||
Logger.i(TAG, "Subscriptions CachePager polycentric urls");
|
||||
val allUrls = subs.map {
|
||||
val otherUrls = PolycentricCache.instance.getCachedProfile(it.channel.url)?.profile?.ownedClaims?.mapNotNull { c -> c.claim.resolveChannelUrl() } ?: listOf();
|
||||
if(!otherUrls.contains(it.channel.url))
|
||||
return@map listOf(listOf(it.channel.url), otherUrls).flatten();
|
||||
else
|
||||
return@map otherUrls;
|
||||
}.flatten().distinct();
|
||||
Logger.i(TAG, "Subscriptions CachePager compiling");
|
||||
|
||||
val pagers = MultiChronoContentPager(allUrls.map { getChannelCachePager(it) }, false, 20);
|
||||
return DedupContentPager(pagers, StatePlatform.instance.getEnabledClients().map { it.id });
|
||||
}
|
||||
|
||||
|
||||
fun getCachedContent(url: String): DBChannelCache.Index? {
|
||||
return _channelCache.query(DBChannelCache.Index::url, url).firstOrNull();
|
||||
}
|
||||
|
||||
fun uncacheContent(content: SerializedPlatformContent) {
|
||||
val item = getCachedContent(content.url);
|
||||
if(item != null)
|
||||
_channelCache.delete(item);
|
||||
}
|
||||
fun cacheContents(contents: List<IPlatformContent>): List<IPlatformContent> {
|
||||
return contents.filter { cacheContent(it) };
|
||||
}
|
||||
fun cacheContent(content: IPlatformContent, doUpdate: Boolean = false): Boolean {
|
||||
if(content.author.url.isEmpty())
|
||||
return false;
|
||||
|
||||
val serialized = SerializedPlatformContent.fromContent(content);
|
||||
val existing = getCachedContent(content.url);
|
||||
|
||||
if(existing != null && doUpdate) {
|
||||
_channelCache.update(existing.id!!, serialized);
|
||||
return true;
|
||||
}
|
||||
else if(existing == null) {
|
||||
_channelCache.insert(serialized);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
private val TAG = "StateCache";
|
||||
|
||||
private var _instance : StateCache? = null;
|
||||
val instance : StateCache
|
||||
get(){
|
||||
if(_instance == null)
|
||||
_instance = StateCache();
|
||||
return _instance!!;
|
||||
};
|
||||
|
||||
fun finish() {
|
||||
_instance?.let {
|
||||
_instance = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -225,12 +225,32 @@ class ManagedDBStore<I: ManagedDBIndex<T>, T, D: ManagedDBDatabase<T, I, DA>, DA
|
|||
return deserializeIndexes(dbDaoBase.getMultiple(_sqlGetAll(id)));
|
||||
}
|
||||
|
||||
fun query(field: KProperty<*>, obj: Any): List<I> = query(validateFieldName(field), obj);
|
||||
fun query(field: String, obj: Any): List<I> {
|
||||
val queryStr = "SELECT * FROM ${descriptor.table_name} WHERE ${field} = ?";
|
||||
val query = SimpleSQLiteQuery(queryStr, arrayOf(obj));
|
||||
return deserializeIndexes(dbDaoBase.getMultiple(query));
|
||||
}
|
||||
fun query(field: KProperty<*>, obj: Any): List<I> = query(validateFieldName(field), obj);
|
||||
fun queryGreater(field: KProperty<*>, obj: Any): List<I> = queryGreater(validateFieldName(field), obj);
|
||||
fun queryGreater(field: String, obj: Any): List<I> {
|
||||
val queryStr = "SELECT * FROM ${descriptor.table_name} WHERE ${field} > ?";
|
||||
val query = SimpleSQLiteQuery(queryStr, arrayOf(obj));
|
||||
return deserializeIndexes(dbDaoBase.getMultiple(query));
|
||||
}
|
||||
fun querySmaller(field: KProperty<*>, obj: Any): List<I> = querySmaller(validateFieldName(field), obj);
|
||||
fun querySmaller(field: String, obj: Any): List<I> {
|
||||
val queryStr = "SELECT * FROM ${descriptor.table_name} WHERE ${field} < ?";
|
||||
val query = SimpleSQLiteQuery(queryStr, arrayOf(obj));
|
||||
return deserializeIndexes(dbDaoBase.getMultiple(query));
|
||||
}
|
||||
fun queryBetween(field: KProperty<*>, greaterThan: Any, smallerThan: Any): List<I> = queryBetween(validateFieldName(field), greaterThan, smallerThan);
|
||||
fun queryBetween(field: String, greaterThan: Any, smallerThan: Any): List<I> {
|
||||
val queryStr = "SELECT * FROM ${descriptor.table_name} WHERE ${field} > ? AND ${field} < ?";
|
||||
val query = SimpleSQLiteQuery(queryStr, arrayOf(greaterThan, smallerThan));
|
||||
return deserializeIndexes(dbDaoBase.getMultiple(query));
|
||||
}
|
||||
|
||||
|
||||
fun queryPage(field: String, obj: Any, page: Int, pageSize: Int): List<I> {
|
||||
val queryStr = "SELECT * FROM ${descriptor.table_name} WHERE ${field} = ? ${_orderSQL} LIMIT ? OFFSET ?";
|
||||
val query = SimpleSQLiteQuery(queryStr, arrayOf(obj, pageSize, page * pageSize));
|
||||
|
@ -247,6 +267,12 @@ class ManagedDBStore<I: ManagedDBIndex<T>, T, D: ManagedDBDatabase<T, I, DA>, DA
|
|||
queryPage(field, obj, it - 1, pageSize);
|
||||
});
|
||||
}
|
||||
fun <X> queryPager(field: KProperty<*>, obj: Any, pageSize: Int, convert: (I)->X): IPager<X> = queryPager(validateFieldName(field), obj, pageSize, convert);
|
||||
fun <X> queryPager(field: String, obj: Any, pageSize: Int, convert: (I)->X): IPager<X> {
|
||||
return AdhocPager({
|
||||
queryPage(field, obj, it - 1, pageSize).map(convert);
|
||||
});
|
||||
}
|
||||
|
||||
fun queryObjectPager(field: KProperty<*>, obj: Any, pageSize: Int): IPager<T> = queryObjectPager(validateFieldName(field), obj, pageSize);
|
||||
fun queryObjectPager(field: String, obj: Any, pageSize: Int): IPager<T> {
|
||||
|
|
|
@ -1,30 +1,65 @@
|
|||
package com.futo.platformplayer.stores.db.types
|
||||
|
||||
import androidx.room.ColumnInfo
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Database
|
||||
import androidx.room.Ignore
|
||||
import androidx.room.PrimaryKey
|
||||
import com.futo.platformplayer.api.media.models.video.SerializedPlatformContent
|
||||
import com.futo.platformplayer.models.HistoryVideo
|
||||
import com.futo.platformplayer.stores.db.ColumnIndex
|
||||
import com.futo.platformplayer.stores.db.ColumnOrdered
|
||||
import com.futo.platformplayer.stores.db.ManagedDBDAOBase
|
||||
import com.futo.platformplayer.stores.db.ManagedDBDatabase
|
||||
import com.futo.platformplayer.stores.db.ManagedDBDescriptor
|
||||
import com.futo.platformplayer.stores.db.ManagedDBIndex
|
||||
import java.time.OffsetDateTime
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
class DBChannelCache {
|
||||
companion object {
|
||||
const val TABLE_NAME = "channelCache";
|
||||
const val TABLE_NAME = "feed_cache";
|
||||
}
|
||||
|
||||
|
||||
//These classes solely exist for bounding generics for type erasure
|
||||
@Dao
|
||||
interface DBDAO: ManagedDBDAOBase<SerializedPlatformContent, Index> {}
|
||||
@Database(entities = [Index::class], version = 2)
|
||||
abstract class DB: ManagedDBDatabase<SerializedPlatformContent, Index, DBDAO>() {
|
||||
abstract override fun base(): DBDAO;
|
||||
}
|
||||
|
||||
class Descriptor: ManagedDBDescriptor<SerializedPlatformContent, Index, DB, DBDAO>() {
|
||||
override val table_name: String = TABLE_NAME;
|
||||
override fun create(obj: SerializedPlatformContent): Index = Index(obj);
|
||||
override fun dbClass(): KClass<DB> = DB::class;
|
||||
override fun indexClass(): KClass<Index> = Index::class;
|
||||
}
|
||||
|
||||
class Index: ManagedDBIndex<SerializedPlatformContent> {
|
||||
@ColumnIndex
|
||||
@PrimaryKey(true)
|
||||
@ColumnOrdered(1)
|
||||
override var id: Long? = null;
|
||||
|
||||
var feedType: String? = null;
|
||||
@ColumnIndex
|
||||
var url: String? = null;
|
||||
@ColumnIndex
|
||||
var channelUrl: String? = null;
|
||||
|
||||
@ColumnIndex
|
||||
@ColumnOrdered(0)
|
||||
var datetime: Long? = null;
|
||||
|
||||
|
||||
constructor() {}
|
||||
constructor(sCache: SerializedPlatformContent) {
|
||||
id = null;
|
||||
serialized = null;
|
||||
url = sCache.url;
|
||||
channelUrl = sCache.author.url;
|
||||
datetime = sCache.datetime?.toEpochSecond();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue