feat: locally store channel info when local streams extraction enabled

This commit is contained in:
Bnyro 2025-03-12 21:15:42 +01:00
parent f1e52a8e6a
commit c84a857a38
No known key found for this signature in database
7 changed files with 797 additions and 27 deletions

View File

@ -0,0 +1,684 @@
{
"formatVersion": 1,
"database": {
"version": 20,
"identityHash": "ebb79071f4df6ea4543f2d0967b3aa7f",
"entities": [
{
"tableName": "watchHistoryItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`videoId` TEXT NOT NULL, `title` TEXT, `uploadDate` TEXT, `uploader` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, `thumbnailUrl` TEXT, `duration` INTEGER, `isShort` INTEGER NOT NULL, PRIMARY KEY(`videoId`))",
"fields": [
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploadDate",
"columnName": "uploadDate",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "uploader",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderUrl",
"columnName": "uploaderUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderAvatar",
"columnName": "uploaderAvatar",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbnailUrl",
"columnName": "thumbnailUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "isShort",
"columnName": "isShort",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"videoId"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "watchPosition",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`videoId` TEXT NOT NULL, `position` INTEGER NOT NULL, PRIMARY KEY(`videoId`))",
"fields": [
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "position",
"columnName": "position",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"videoId"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "searchHistoryItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`query` TEXT NOT NULL, PRIMARY KEY(`query`))",
"fields": [
{
"fieldPath": "query",
"columnName": "query",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"query"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "customInstance",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `apiUrl` TEXT NOT NULL, `frontendUrl` TEXT NOT NULL, PRIMARY KEY(`name`))",
"fields": [
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "apiUrl",
"columnName": "apiUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "frontendUrl",
"columnName": "frontendUrl",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"name"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "localSubscription",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`channelId` TEXT NOT NULL, `name` TEXT DEFAULT NULL, `avatar` TEXT DEFAULT NULL, `verified` INTEGER NOT NULL DEFAULT false, PRIMARY KEY(`channelId`))",
"fields": [
{
"fieldPath": "channelId",
"columnName": "channelId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "NULL"
},
{
"fieldPath": "avatar",
"columnName": "avatar",
"affinity": "TEXT",
"notNull": false,
"defaultValue": "NULL"
},
{
"fieldPath": "verified",
"columnName": "verified",
"affinity": "INTEGER",
"notNull": true,
"defaultValue": "false"
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"channelId"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "playlistBookmark",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`playlistId` TEXT NOT NULL, `playlistName` TEXT, `thumbnailUrl` TEXT, `uploader` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, `videos` INTEGER NOT NULL, PRIMARY KEY(`playlistId`))",
"fields": [
{
"fieldPath": "playlistId",
"columnName": "playlistId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "playlistName",
"columnName": "playlistName",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbnailUrl",
"columnName": "thumbnailUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "uploader",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderUrl",
"columnName": "uploaderUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderAvatar",
"columnName": "uploaderAvatar",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "videos",
"columnName": "videos",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"playlistId"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LocalPlaylist",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `thumbnailUrl` TEXT NOT NULL, `description` TEXT)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "thumbnailUrl",
"columnName": "thumbnailUrl",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "LocalPlaylistItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `playlistId` INTEGER NOT NULL, `videoId` TEXT NOT NULL, `title` TEXT, `uploadDate` TEXT, `uploader` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, `thumbnailUrl` TEXT, `duration` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "playlistId",
"columnName": "playlistId",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploadDate",
"columnName": "uploadDate",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploader",
"columnName": "uploader",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderUrl",
"columnName": "uploaderUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderAvatar",
"columnName": "uploaderAvatar",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbnailUrl",
"columnName": "thumbnailUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "download",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`videoId` TEXT NOT NULL, `title` TEXT NOT NULL, `description` TEXT NOT NULL, `uploader` TEXT NOT NULL, `duration` INTEGER DEFAULT NULL, `uploadDate` TEXT, `thumbnailPath` TEXT, PRIMARY KEY(`videoId`))",
"fields": [
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "description",
"columnName": "description",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "uploader",
"columnName": "uploader",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": false,
"defaultValue": "NULL"
},
{
"fieldPath": "uploadDate",
"columnName": "uploadDate",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbnailPath",
"columnName": "thumbnailPath",
"affinity": "TEXT",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"videoId"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "downloadItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `videoId` TEXT NOT NULL, `fileName` TEXT NOT NULL, `path` TEXT NOT NULL, `url` TEXT, `format` TEXT, `quality` TEXT, `language` TEXT, `downloadSize` INTEGER NOT NULL, FOREIGN KEY(`videoId`) REFERENCES `download`(`videoId`) ON UPDATE NO ACTION ON DELETE CASCADE )",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "type",
"columnName": "type",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "fileName",
"columnName": "fileName",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "path",
"columnName": "path",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "url",
"columnName": "url",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "format",
"columnName": "format",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "quality",
"columnName": "quality",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "language",
"columnName": "language",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "downloadSize",
"columnName": "downloadSize",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_downloadItem_path",
"unique": true,
"columnNames": [
"path"
],
"orders": [],
"createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_downloadItem_path` ON `${TABLE_NAME}` (`path`)"
}
],
"foreignKeys": [
{
"table": "download",
"onDelete": "CASCADE",
"onUpdate": "NO ACTION",
"columns": [
"videoId"
],
"referencedColumns": [
"videoId"
]
}
]
},
{
"tableName": "downloadChapters",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `videoId` TEXT NOT NULL, `name` TEXT NOT NULL, `start` INTEGER NOT NULL, `thumbnailUrl` TEXT NOT NULL)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "start",
"columnName": "start",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "thumbnailUrl",
"columnName": "thumbnailUrl",
"affinity": "TEXT",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "subscriptionGroups",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`name` TEXT NOT NULL, `channels` TEXT NOT NULL, `index` INTEGER NOT NULL, PRIMARY KEY(`name`))",
"fields": [
{
"fieldPath": "name",
"columnName": "name",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "channels",
"columnName": "channels",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "index",
"columnName": "index",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"name"
]
},
"indices": [],
"foreignKeys": []
},
{
"tableName": "feedItem",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`videoId` TEXT NOT NULL, `title` TEXT, `thumbnail` TEXT, `uploaderName` TEXT, `uploaderUrl` TEXT, `uploaderAvatar` TEXT, `duration` INTEGER, `views` INTEGER, `uploaderVerified` INTEGER NOT NULL, `uploaded` INTEGER NOT NULL, `shortDescription` TEXT, `isShort` INTEGER NOT NULL, PRIMARY KEY(`videoId`))",
"fields": [
{
"fieldPath": "videoId",
"columnName": "videoId",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "title",
"columnName": "title",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "thumbnail",
"columnName": "thumbnail",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderName",
"columnName": "uploaderName",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderUrl",
"columnName": "uploaderUrl",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "uploaderAvatar",
"columnName": "uploaderAvatar",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "views",
"columnName": "views",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "uploaderVerified",
"columnName": "uploaderVerified",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "uploaded",
"columnName": "uploaded",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "shortDescription",
"columnName": "shortDescription",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "isShort",
"columnName": "isShort",
"affinity": "INTEGER",
"notNull": true
}
],
"primaryKey": {
"autoGenerate": false,
"columnNames": [
"videoId"
]
},
"indices": [],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ebb79071f4df6ea4543f2d0967b3aa7f')"
]
}
}

View File

@ -11,6 +11,7 @@ import com.github.libretube.repo.FeedRepository
import com.github.libretube.repo.LocalFeedRepository
import com.github.libretube.repo.LocalSubscriptionsRepository
import com.github.libretube.repo.PipedAccountFeedRepository
import com.github.libretube.repo.PipedLocalSubscriptionsRepository
import com.github.libretube.repo.PipedNoAccountFeedRepository
import com.github.libretube.repo.SubscriptionsRepository
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -23,19 +24,20 @@ object SubscriptionHelper {
*/
const val GET_SUBSCRIPTIONS_LIMIT = 100
private val localFeedExtraction get() = PreferenceHelper.getBoolean(
PreferenceKeys.LOCAL_FEED_EXTRACTION,
false
)
private val token get() = PreferenceHelper.getToken()
private val subscriptionsRepository: SubscriptionsRepository
get() = when {
localFeedExtraction -> LocalSubscriptionsRepository()
token.isNotEmpty() -> AccountSubscriptionsRepository()
else -> LocalSubscriptionsRepository()
else -> PipedLocalSubscriptionsRepository()
}
private val feedRepository: FeedRepository
get() = when {
PreferenceHelper.getBoolean(
PreferenceKeys.LOCAL_FEED_EXTRACTION,
false
) -> LocalFeedRepository()
localFeedExtraction -> LocalFeedRepository()
token.isNotEmpty() -> PipedAccountFeedRepository()
else -> PipedNoAccountFeedRepository()
}

View File

@ -44,14 +44,15 @@ import com.github.libretube.db.obj.WatchPosition
SubscriptionGroup::class,
SubscriptionsFeedItem::class
],
version = 19,
version = 20,
autoMigrations = [
AutoMigration(from = 7, to = 8),
AutoMigration(from = 8, to = 9),
AutoMigration(from = 9, to = 10),
AutoMigration(from = 10, to = 11),
AutoMigration(from = 16, to = 17),
AutoMigration(from = 18, to = 19)
AutoMigration(from = 18, to = 19),
AutoMigration(from = 19, to = 20)
]
)
@TypeConverters(Converters::class)
@ -101,5 +102,8 @@ abstract class AppDatabase : RoomDatabase() {
*/
abstract fun subscriptionGroupsDao(): SubscriptionGroupsDao
/**
* Locally cached subscription feed
*/
abstract fun feedDao(): SubscriptionsFeedDao
}

View File

@ -1,7 +1,6 @@
package com.github.libretube.db.dao
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
@ -18,8 +17,14 @@ interface LocalSubscriptionDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertAll(localSubscriptions: List<LocalSubscription>)
@Delete
suspend fun delete(localSubscription: LocalSubscription)
@Query("DELETE FROM localSubscription WHERE channelId = :channelId")
suspend fun deleteById(channelId: String)
/**
* Get all channels that DO NOT contain any meta info (such as their name) yet.
*/
@Query("SELECT * FROM localSubscription WHERE name IS NULL")
suspend fun getChannelsWithoutMetaInfo(): List<LocalSubscription>
@Query("SELECT EXISTS(SELECT * FROM localSubscription WHERE channelId = :channelId)")
suspend fun includes(channelId: String): Boolean

View File

@ -1,5 +1,6 @@
package com.github.libretube.db.obj
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
@ -10,9 +11,16 @@ import kotlinx.serialization.Serializable
@Entity(tableName = "localSubscription")
data class LocalSubscription(
@PrimaryKey val channelId: String,
@Ignore val url: String = ""
@Ignore val url: String = "",
@ColumnInfo(defaultValue = "NULL") val name: String? = null,
@ColumnInfo(defaultValue = "NULL") val avatar: String? = null,
@ColumnInfo(defaultValue = "false") val verified: Boolean = false
) {
constructor(
channelId: String
) : this(channelId, "${ShareDialog.YOUTUBE_FRONTEND_URL}/channel/$channelId")
channelId: String,
name: String? = null,
avatar: String? = null,
verified: Boolean = false
) : this(channelId, "${ShareDialog.YOUTUBE_FRONTEND_URL}/channel/$channelId", name, avatar, verified)
}

View File

@ -1,18 +1,29 @@
package com.github.libretube.repo
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.api.SubscriptionHelper.GET_SUBSCRIPTIONS_LIMIT
import com.github.libretube.api.obj.Subscription
import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.LocalSubscription
import com.github.libretube.extensions.parallelMap
import com.github.libretube.ui.dialogs.ShareDialog.Companion.YOUTUBE_FRONTEND_URL
import org.schabi.newpipe.extractor.channel.ChannelInfo
class LocalSubscriptionsRepository: SubscriptionsRepository {
override suspend fun subscribe(channelId: String) {
Database.localSubscriptionDao().insert(LocalSubscription(channelId))
val channelUrl = "$YOUTUBE_FRONTEND_URL/channel/${channelId}"
val channelInfo = ChannelInfo.getInfo(channelUrl)
val localSubscription = LocalSubscription(
channelId = channelInfo.id,
name = channelInfo.name,
avatar = channelInfo.avatars.maxByOrNull { it.height }?.url,
verified = channelInfo.isVerified
)
Database.localSubscriptionDao().insert(localSubscription)
}
override suspend fun unsubscribe(channelId: String) {
Database.localSubscriptionDao().delete(LocalSubscription(channelId))
Database.localSubscriptionDao().deleteById(channelId)
}
override suspend fun isSubscribed(channelId: String): Boolean {
@ -20,19 +31,26 @@ class LocalSubscriptionsRepository: SubscriptionsRepository {
}
override suspend fun importSubscriptions(newChannels: List<String>) {
Database.localSubscriptionDao().insertAll(newChannels.map { LocalSubscription(it) })
for (chunk in newChannels.chunked(CHANNEL_CHUNK_SIZE)) {
chunk.parallelMap { channelId ->
runCatching { subscribe(channelId) }
}
}
}
override suspend fun getSubscriptions(): List<Subscription> {
val channelIds = getSubscriptionChannelIds()
// load all channels that have not been fetched yet
val unfinished = Database.localSubscriptionDao().getChannelsWithoutMetaInfo()
runCatching {
importSubscriptions(unfinished.map { it.channelId })
}
return when {
channelIds.size > GET_SUBSCRIPTIONS_LIMIT ->
RetrofitInstance.authApi
.unauthenticatedSubscriptions(channelIds)
else -> RetrofitInstance.authApi.unauthenticatedSubscriptions(
channelIds.joinToString(",")
return Database.localSubscriptionDao().getAll().map {
Subscription(
url = it.channelId,
name = it.name.orEmpty(),
avatar = it.avatar,
verified = it.verified
)
}
}
@ -40,4 +58,8 @@ class LocalSubscriptionsRepository: SubscriptionsRepository {
override suspend fun getSubscriptionChannelIds(): List<String> {
return Database.localSubscriptionDao().getAll().map { it.channelId }
}
companion object {
private const val CHANNEL_CHUNK_SIZE = 2
}
}

View File

@ -0,0 +1,45 @@
package com.github.libretube.repo
import com.github.libretube.api.RetrofitInstance
import com.github.libretube.api.SubscriptionHelper.GET_SUBSCRIPTIONS_LIMIT
import com.github.libretube.api.obj.Subscription
import com.github.libretube.db.DatabaseHolder.Database
import com.github.libretube.db.obj.LocalSubscription
class PipedLocalSubscriptionsRepository: SubscriptionsRepository {
override suspend fun subscribe(channelId: String) {
// further meta info is not needed when using Piped local subscriptions
Database.localSubscriptionDao().insert(LocalSubscription(channelId))
}
override suspend fun importSubscriptions(newChannels: List<String>) {
// further meta info is not needed when using Piped local subscriptions
Database.localSubscriptionDao().insertAll(newChannels.map { LocalSubscription(it) })
}
override suspend fun isSubscribed(channelId: String): Boolean {
return Database.localSubscriptionDao().includes(channelId)
}
override suspend fun unsubscribe(channelId: String) {
Database.localSubscriptionDao().deleteById(channelId)
}
override suspend fun getSubscriptions(): List<Subscription> {
val channelIds = getSubscriptionChannelIds()
return when {
channelIds.size > GET_SUBSCRIPTIONS_LIMIT ->
RetrofitInstance.authApi
.unauthenticatedSubscriptions(channelIds)
else -> RetrofitInstance.authApi.unauthenticatedSubscriptions(
channelIds.joinToString(",")
)
}
}
override suspend fun getSubscriptionChannelIds(): List<String> {
return Database.localSubscriptionDao().getAll().map { it.channelId }
}
}