Aayush Gupta committed 2026-10-21 12:27:58 +08:00
1 parent f46290f28a
commit 05cdfcd822
36 files changed
+268 -229

No files matched your search

+4 -2
View File
@@ -14,6 +14,7 @@ plugins {
alias(libs.plugins.jetbrains.kotlinx.serialization)
alias(libs.plugins.sonarqube)
alias(libs.plugins.about.libraries)
alias(libs.plugins.androidx.room)
checkstyle
}
@@ -140,8 +141,8 @@ configure<ApplicationExtension> {
}
}
ksp {
arg("room.schemaLocation", "$projectDir/schemas")
room3 {
schemaDirectory("$projectDir/schemas")
}
// Custom dependency configuration for ktlint
@@ -244,6 +245,7 @@ dependencies {
implementation(libs.androidx.recyclerview)
implementation(libs.androidx.room.runtime)
implementation(libs.androidx.room.rxjava3)
implementation(libs.androidx.sqlite.bundled)
ksp(libs.androidx.room.compiler)
implementation(libs.androidx.swiperefreshlayout)
implementation(libs.androidx.viewpager2)
@@ -7,8 +7,11 @@
package org.schabi.newpipe
import android.content.Context
import androidx.room.Room.databaseBuilder
import androidx.room3.Room.databaseBuilder
import androidx.room3.useWriterConnection
import androidx.sqlite.driver.bundled.BundledSQLiteDriver
import kotlin.concurrent.Volatile
import kotlinx.coroutines.runBlocking
import org.schabi.newpipe.database.AppDatabase
import org.schabi.newpipe.database.Migrations.MIGRATION_1_2
import org.schabi.newpipe.database.Migrations.MIGRATION_2_3
@@ -28,7 +31,7 @@ object NewPipeDatabase {
return databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
AppDatabase.Companion.DATABASE_NAME
AppDatabase.DATABASE_NAME
).addMigrations(
MIGRATION_1_2,
MIGRATION_2_3,
@@ -38,7 +41,7 @@ object NewPipeDatabase {
MIGRATION_6_7,
MIGRATION_7_8,
MIGRATION_8_9
).build()
).setDriver(BundledSQLiteDriver()).build()
}
@JvmStatic
@@ -59,10 +62,15 @@ object NewPipeDatabase {
@JvmStatic
fun checkpoint() {
checkNotNull(databaseInstance) { "database is not initialized" }
val c = databaseInstance!!.query("pragma wal_checkpoint(full)", null)
if (c.moveToFirst() && c.getInt(0) == 1) {
throw RuntimeException("Checkpoint was blocked from completing")
val database = checkNotNull(databaseInstance) { "database is not initialized" }
runBlocking {
database.useWriterConnection { transactor ->
transactor.usePrepared("pragma wal_checkpoint(full)") { statement ->
if (statement.step() && statement.getInt(0) == 1) {
throw RuntimeException("Checkpoint was blocked from completing")
}
}
}
}
}
@@ -6,9 +6,9 @@
package org.schabi.newpipe.database
import androidx.room.Database
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
import androidx.room3.ColumnTypeConverters
import androidx.room3.Database
import androidx.room3.RoomDatabase
import org.schabi.newpipe.database.feed.dao.FeedDAO
import org.schabi.newpipe.database.feed.dao.FeedGroupDAO
import org.schabi.newpipe.database.feed.model.FeedEntity
@@ -32,7 +32,7 @@ import org.schabi.newpipe.database.stream.model.StreamStateEntity
import org.schabi.newpipe.database.subscription.SubscriptionDAO
import org.schabi.newpipe.database.subscription.SubscriptionEntity
@TypeConverters(Converters::class)
@ColumnTypeConverters(Converters::class)
@Database(
version = Migrations.DB_VER_9,
entities = [
@@ -6,10 +6,10 @@
package org.schabi.newpipe.database
import androidx.room.Dao
import androidx.room.Delete
import androidx.room.Insert
import androidx.room.Update
import androidx.room3.Dao
import androidx.room3.Delete
import androidx.room3.Insert
import androidx.room3.Update
import io.reactivex.rxjava3.core.Flowable
@Dao
@@ -1,6 +1,6 @@
package org.schabi.newpipe.database
import androidx.room.TypeConverter
import androidx.room3.ColumnTypeConverter
import java.time.Instant
import java.time.OffsetDateTime
import java.time.ZoneOffset
@@ -14,7 +14,7 @@ class Converters {
* @param value the long value
* @return the `OffsetDateTime`
*/
@TypeConverter
@ColumnTypeConverter
fun offsetDateTimeFromTimestamp(value: Long?): OffsetDateTime? {
return value?.let { OffsetDateTime.ofInstant(Instant.ofEpochMilli(it), ZoneOffset.UTC) }
}
@@ -25,27 +25,27 @@ class Converters {
* @param offsetDateTime the `OffsetDateTime`
* @return the long value
*/
@TypeConverter
@ColumnTypeConverter
fun offsetDateTimeToTimestamp(offsetDateTime: OffsetDateTime?): Long? {
return offsetDateTime?.withOffsetSameInstant(ZoneOffset.UTC)?.toInstant()?.toEpochMilli()
}
@TypeConverter
@ColumnTypeConverter
fun streamTypeOf(value: String): StreamType {
return StreamType.valueOf(value)
}
@TypeConverter
@ColumnTypeConverter
fun stringOf(streamType: StreamType): String {
return streamType.name
}
@TypeConverter
@ColumnTypeConverter
fun integerOf(feedGroupIcon: FeedGroupIcon): Int {
return feedGroupIcon.id
}
@TypeConverter
@ColumnTypeConverter
fun feedGroupIconOf(id: Int): FeedGroupIcon {
return FeedGroupIcon.entries.first { it.id == id }
}
@@ -7,7 +7,8 @@
package org.schabi.newpipe.database
import android.util.Log
import androidx.room.migration.Migration
import androidx.room3.migration.Migration
import androidx.sqlite.execSQL
import org.schabi.newpipe.MainActivity
object Migrations {
@@ -33,7 +34,7 @@ object Migrations {
private val TAG = Migrations::class.java.getName()
private val isDebug = MainActivity.DEBUG
val MIGRATION_1_2 = Migration(DB_VER_1, DB_VER_2) { db ->
val MIGRATION_1_2 = Migration(DB_VER_1, DB_VER_2) { connection ->
if (isDebug) {
Log.d(TAG, "Start migrating database")
}
@@ -46,45 +47,45 @@ object Migrations {
// Not much we can do about this, since room doesn't create tables before migration.
// It's either this or blasting the entire database anew.
db.execSQL(
connection.execSQL(
"CREATE INDEX `index_search_history_search` " +
"ON `search_history` (`search`)"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `streams` " +
"(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"`service_id` INTEGER NOT NULL, `url` TEXT, `title` TEXT, " +
"`stream_type` TEXT, `duration` INTEGER, `uploader` TEXT, " +
"`thumbnail_url` TEXT)"
)
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX `index_streams_service_id_url` " +
"ON `streams` (`service_id`, `url`)"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `stream_history` " +
"(`stream_id` INTEGER NOT NULL, `access_date` INTEGER NOT NULL, " +
"`repeat_count` INTEGER NOT NULL, PRIMARY KEY(`stream_id`, `access_date`), " +
"FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) " +
"ON UPDATE CASCADE ON DELETE CASCADE )"
)
db.execSQL(
connection.execSQL(
"CREATE INDEX `index_stream_history_stream_id` " +
"ON `stream_history` (`stream_id`)"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `stream_state` " +
"(`stream_id` INTEGER NOT NULL, `progress_time` INTEGER NOT NULL, " +
"PRIMARY KEY(`stream_id`), FOREIGN KEY(`stream_id`) " +
"REFERENCES `streams`(`uid`) ON UPDATE CASCADE ON DELETE CASCADE )"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `playlists` " +
"(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"`name` TEXT, `thumbnail_url` TEXT)"
)
db.execSQL("CREATE INDEX `index_playlists_name` ON `playlists` (`name`)")
db.execSQL(
connection.execSQL("CREATE INDEX `index_playlists_name` ON `playlists` (`name`)")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `playlist_stream_join` " +
"(`playlist_id` INTEGER NOT NULL, `stream_id` INTEGER NOT NULL, " +
"`join_index` INTEGER NOT NULL, PRIMARY KEY(`playlist_id`, `join_index`), " +
@@ -93,33 +94,33 @@ object Migrations {
"FOREIGN KEY(`stream_id`) REFERENCES `streams`(`uid`) " +
"ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
)
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX " +
"`index_playlist_stream_join_playlist_id_join_index` " +
"ON `playlist_stream_join` (`playlist_id`, `join_index`)"
)
db.execSQL(
connection.execSQL(
"CREATE INDEX `index_playlist_stream_join_stream_id` " +
"ON `playlist_stream_join` (`stream_id`)"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `remote_playlists` " +
"(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"`service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, " +
"`thumbnail_url` TEXT, `uploader` TEXT, `stream_count` INTEGER)"
)
db.execSQL(
connection.execSQL(
"CREATE INDEX `index_remote_playlists_name` " +
"ON `remote_playlists` (`name`)"
)
db.execSQL(
connection.execSQL(
"CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` " +
"ON `remote_playlists` (`service_id`, `url`)"
)
// Populate streams table with existing entries in watch history
// Latest data first, thus ignoring older entries with the same indices
db.execSQL(
connection.execSQL(
"INSERT OR IGNORE INTO streams (service_id, url, title, " +
"stream_type, duration, uploader, thumbnail_url) " +
@@ -132,7 +133,7 @@ object Migrations {
// Once the streams have PKs, join them with the normalized history table
// and populate it with the remaining data from watch history
db.execSQL(
connection.execSQL(
"INSERT INTO stream_history (stream_id, access_date, repeat_count)" +
"SELECT uid, creation_date, 1 " +
"FROM watch_history INNER JOIN streams " +
@@ -141,16 +142,16 @@ object Migrations {
"ORDER BY creation_date DESC"
)
db.execSQL("DROP TABLE IF EXISTS watch_history")
connection.execSQL("DROP TABLE IF EXISTS watch_history")
if (isDebug) {
Log.d(TAG, "Stop migrating database")
}
}
val MIGRATION_2_3 = Migration(DB_VER_2, DB_VER_3) { db ->
val MIGRATION_2_3 = Migration(DB_VER_2, DB_VER_3) { connection ->
// Add NOT NULLs and new fields
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS streams_new " +
"(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"service_id INTEGER NOT NULL, url TEXT NOT NULL, title TEXT NOT NULL, " +
@@ -160,7 +161,7 @@ object Migrations {
"is_upload_date_approximation INTEGER)"
)
db.execSQL(
connection.execSQL(
"INSERT INTO streams_new (uid, service_id, url, title, stream_type, " +
"duration, uploader, thumbnail_url, view_count, textual_upload_date, " +
"upload_date, is_upload_date_approximation) " +
@@ -172,15 +173,15 @@ object Migrations {
"FROM streams WHERE url IS NOT NULL"
)
db.execSQL("DROP TABLE streams")
db.execSQL("ALTER TABLE streams_new RENAME TO streams")
db.execSQL(
connection.execSQL("DROP TABLE streams")
connection.execSQL("ALTER TABLE streams_new RENAME TO streams")
connection.execSQL(
"CREATE UNIQUE INDEX index_streams_service_id_url " +
"ON streams (service_id, url)"
)
// Tables for feed feature
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS feed " +
"(stream_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, " +
"PRIMARY KEY(stream_id, subscription_id), " +
@@ -189,14 +190,14 @@ object Migrations {
"FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) " +
"ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
)
db.execSQL("CREATE INDEX index_feed_subscription_id ON feed (subscription_id)")
db.execSQL(
connection.execSQL("CREATE INDEX index_feed_subscription_id ON feed (subscription_id)")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS feed_group " +
"(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, name TEXT NOT NULL, " +
"icon_id INTEGER NOT NULL, sort_order INTEGER NOT NULL)"
)
db.execSQL("CREATE INDEX index_feed_group_sort_order ON feed_group (sort_order)")
db.execSQL(
connection.execSQL("CREATE INDEX index_feed_group_sort_order ON feed_group (sort_order)")
connection.execSQL(
"CREATE TABLE IF NOT EXISTS feed_group_subscription_join " +
"(group_id INTEGER NOT NULL, subscription_id INTEGER NOT NULL, " +
"PRIMARY KEY(group_id, subscription_id), " +
@@ -205,11 +206,11 @@ object Migrations {
"FOREIGN KEY(subscription_id) REFERENCES subscriptions(uid) " +
"ON UPDATE CASCADE ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED)"
)
db.execSQL(
connection.execSQL(
"CREATE INDEX index_feed_group_subscription_join_subscription_id " +
"ON feed_group_subscription_join (subscription_id)"
)
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS feed_last_updated " +
"(subscription_id INTEGER NOT NULL, last_updated INTEGER, " +
"PRIMARY KEY(subscription_id), " +
@@ -218,33 +219,33 @@ object Migrations {
)
}
val MIGRATION_3_4 = Migration(DB_VER_3, DB_VER_4) { db ->
db.execSQL("ALTER TABLE streams ADD COLUMN uploader_url TEXT")
val MIGRATION_3_4 = Migration(DB_VER_3, DB_VER_4) { connection ->
connection.execSQL("ALTER TABLE streams ADD COLUMN uploader_url TEXT")
}
val MIGRATION_4_5 = Migration(DB_VER_4, DB_VER_5) { db ->
db.execSQL(
val MIGRATION_4_5 = Migration(DB_VER_4, DB_VER_5) { connection ->
connection.execSQL(
"ALTER TABLE `subscriptions` ADD COLUMN `notification_mode` " +
"INTEGER NOT NULL DEFAULT 0"
)
}
val MIGRATION_5_6 = Migration(DB_VER_5, DB_VER_6) { db ->
db.execSQL(
val MIGRATION_5_6 = Migration(DB_VER_5, DB_VER_6) { connection ->
connection.execSQL(
"ALTER TABLE `playlists` ADD COLUMN `is_thumbnail_permanent` " +
"INTEGER NOT NULL DEFAULT 0"
)
}
val MIGRATION_6_7 = Migration(DB_VER_6, DB_VER_7) { db ->
val MIGRATION_6_7 = Migration(DB_VER_6, DB_VER_7) { connection ->
// Create a new column thumbnail_stream_id
db.execSQL(
connection.execSQL(
"ALTER TABLE `playlists` ADD COLUMN `thumbnail_stream_id` " +
"INTEGER NOT NULL DEFAULT -1"
)
// Migrate the thumbnail_url to the thumbnail_stream_id
db.execSQL(
connection.execSQL(
"UPDATE playlists SET thumbnail_stream_id = (" +
" SELECT CASE WHEN COUNT(*) != 0 then stream_uid ELSE -1 END" +
" FROM (" +
@@ -257,7 +258,7 @@ object Migrations {
)
// Remove the thumbnail_url field in the playlist table
db.execSQL(
connection.execSQL(
"CREATE TABLE IF NOT EXISTS `playlists_new`" +
"(uid INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"name TEXT, " +
@@ -265,87 +266,79 @@ object Migrations {
"thumbnail_stream_id INTEGER NOT NULL)"
)
db.execSQL(
connection.execSQL(
"INSERT INTO playlists_new" +
" SELECT uid, name, is_thumbnail_permanent, thumbnail_stream_id " +
" FROM playlists"
)
db.execSQL("DROP TABLE playlists")
db.execSQL("ALTER TABLE playlists_new RENAME TO playlists")
db.execSQL(
connection.execSQL("DROP TABLE playlists")
connection.execSQL("ALTER TABLE playlists_new RENAME TO playlists")
connection.execSQL(
"CREATE INDEX IF NOT EXISTS " +
"`index_playlists_name` ON `playlists` (`name`)"
)
}
val MIGRATION_7_8 = Migration(DB_VER_7, DB_VER_8) { db ->
db.execSQL(
val MIGRATION_7_8 = Migration(DB_VER_7, DB_VER_8) { connection ->
connection.execSQL(
"DELETE FROM search_history WHERE id NOT IN (SELECT id FROM (SELECT " +
"MIN(id) as id FROM search_history GROUP BY trim(search), service_id ) tmp)"
)
db.execSQL("UPDATE search_history SET search = trim(search)")
connection.execSQL("UPDATE search_history SET search = trim(search)")
}
val MIGRATION_8_9 = Migration(DB_VER_8, DB_VER_9) { db ->
try {
db.beginTransaction()
// Update playlists.
// Create a temp table to initialize display_index.
db.execSQL(
"CREATE TABLE `playlists_tmp` " +
val MIGRATION_8_9 = Migration(DB_VER_8, DB_VER_9) { connection ->
// Update playlists.
// Create a temp table to initialize display_index.
connection.execSQL(
"CREATE TABLE `playlists_tmp` " +
"(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"`name` TEXT, `is_thumbnail_permanent` INTEGER NOT NULL, " +
"`thumbnail_stream_id` INTEGER NOT NULL, " +
"`display_index` INTEGER NOT NULL)"
)
db.execSQL(
"INSERT INTO `playlists_tmp` " +
)
connection.execSQL(
"INSERT INTO `playlists_tmp` " +
"(`uid`, `name`, `is_thumbnail_permanent`, `thumbnail_stream_id`, " +
"`display_index`) " +
"SELECT `uid`, `name`, `is_thumbnail_permanent`, `thumbnail_stream_id`, " +
"-1 " +
"FROM `playlists`"
)
)
// Replace the old table, note that this also removes the index on the name which
// we don't need anymore.
db.execSQL("DROP TABLE `playlists`")
db.execSQL("ALTER TABLE `playlists_tmp` RENAME TO `playlists`")
// Replace the old table, note that this also removes the index on the name which
// we don't need anymore.
connection.execSQL("DROP TABLE `playlists`")
connection.execSQL("ALTER TABLE `playlists_tmp` RENAME TO `playlists`")
// Update remote_playlists.
// Create a temp table to initialize display_index.
db.execSQL(
"CREATE TABLE `remote_playlists_tmp` " +
// Update remote_playlists.
// Create a temp table to initialize display_index.
connection.execSQL(
"CREATE TABLE `remote_playlists_tmp` " +
"(`uid` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
"`service_id` INTEGER NOT NULL, `name` TEXT, `url` TEXT, " +
"`thumbnail_url` TEXT, `uploader` TEXT, " +
"`display_index` INTEGER NOT NULL," +
"`stream_count` INTEGER)"
)
db.execSQL(
"INSERT INTO `remote_playlists_tmp` (`uid`, `service_id`, " +
)
connection.execSQL(
"INSERT INTO `remote_playlists_tmp` (`uid`, `service_id`, " +
"`name`, `url`, `thumbnail_url`, `uploader`, `display_index`, " +
"`stream_count`)" +
"SELECT `uid`, `service_id`, `name`, `url`, `thumbnail_url`, `uploader`, " +
"-1, `stream_count` FROM `remote_playlists`"
)
)
// Replace the old table, note that this also removes the index on the name which
// we don't need anymore.
db.execSQL("DROP TABLE `remote_playlists`")
db.execSQL("ALTER TABLE `remote_playlists_tmp` RENAME TO `remote_playlists`")
// Replace the old table, note that this also removes the index on the name which
// we don't need anymore.
connection.execSQL("DROP TABLE `remote_playlists`")
connection.execSQL("ALTER TABLE `remote_playlists_tmp` RENAME TO `remote_playlists`")
// Create index on the new table.
db.execSQL(
"CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` " +
// Create index on the new table.
connection.execSQL(
"CREATE UNIQUE INDEX `index_remote_playlists_service_id_url` " +
"ON `remote_playlists` (`service_id`, `url`)"
)
db.setTransactionSuccessful()
} finally {
db.endTransaction()
}
)
}
}
@@ -1,11 +1,13 @@
package org.schabi.newpipe.database.feed.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Insert
import androidx.room3.OnConflictStrategy
import androidx.room3.Query
import androidx.room3.Transaction
import androidx.room3.Update
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import java.time.OffsetDateTime
@@ -18,6 +20,7 @@ import org.schabi.newpipe.database.subscription.NotificationMode
import org.schabi.newpipe.database.subscription.SubscriptionEntity
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
abstract class FeedDAO {
@Query("DELETE FROM feed")
abstract fun deleteAll(): Int
@@ -1,17 +1,20 @@
package org.schabi.newpipe.database.feed.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room.Update
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Insert
import androidx.room3.OnConflictStrategy
import androidx.room3.Query
import androidx.room3.Transaction
import androidx.room3.Update
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import org.schabi.newpipe.database.feed.model.FeedGroupEntity
import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
abstract class FeedGroupDAO {
@Query("SELECT * FROM feed_group ORDER BY sort_order ASC")
@@ -1,9 +1,9 @@
package org.schabi.newpipe.database.feed.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.ForeignKey
import androidx.room3.Index
import org.schabi.newpipe.database.feed.model.FeedEntity.Companion.FEED_TABLE
import org.schabi.newpipe.database.feed.model.FeedEntity.Companion.STREAM_ID
import org.schabi.newpipe.database.feed.model.FeedEntity.Companion.SUBSCRIPTION_ID
@@ -1,9 +1,9 @@
package org.schabi.newpipe.database.feed.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.Index
import androidx.room3.PrimaryKey
import org.schabi.newpipe.database.feed.model.FeedGroupEntity.Companion.FEED_GROUP_TABLE
import org.schabi.newpipe.database.feed.model.FeedGroupEntity.Companion.SORT_ORDER
import org.schabi.newpipe.local.subscription.FeedGroupIcon
@@ -1,9 +1,9 @@
package org.schabi.newpipe.database.feed.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.Index
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.ForeignKey
import androidx.room3.Index
import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity.Companion.FEED_GROUP_SUBSCRIPTION_TABLE
import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity.Companion.GROUP_ID
import org.schabi.newpipe.database.feed.model.FeedGroupSubscriptionEntity.Companion.SUBSCRIPTION_ID
@@ -1,9 +1,9 @@
package org.schabi.newpipe.database.feed.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.ForeignKey
import androidx.room3.PrimaryKey
import java.time.OffsetDateTime
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.FEED_LAST_UPDATED_TABLE
import org.schabi.newpipe.database.feed.model.FeedLastUpdatedEntity.Companion.SUBSCRIPTION_ID
@@ -6,13 +6,16 @@
package org.schabi.newpipe.database.history.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Query
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.history.model.SearchHistoryEntry
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
interface SearchHistoryDAO : BasicDAO<SearchHistoryEntry> {
@get:Query("SELECT * FROM search_history WHERE id = (SELECT MAX(id) FROM search_history)")
@@ -6,9 +6,11 @@
package org.schabi.newpipe.database.history.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Query
import androidx.room3.RewriteQueriesToDropUnusedColumns
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.history.model.StreamHistoryEntity
@@ -16,6 +18,7 @@ import org.schabi.newpipe.database.history.model.StreamHistoryEntry
import org.schabi.newpipe.database.stream.StreamStatisticsEntry
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
abstract class StreamHistoryDAO : BasicDAO<StreamHistoryEntity> {
@Query("SELECT * FROM stream_history")
@@ -6,11 +6,11 @@
package org.schabi.newpipe.database.history.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.Ignore
import androidx.room3.Index
import androidx.room3.PrimaryKey
import java.time.OffsetDateTime
@Entity(
@@ -6,11 +6,11 @@
package org.schabi.newpipe.database.history.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.ForeignKey.Companion.CASCADE
import androidx.room.Index
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.ForeignKey
import androidx.room3.ForeignKey.Companion.CASCADE
import androidx.room3.Index
import java.time.OffsetDateTime
import org.schabi.newpipe.database.history.model.StreamHistoryEntity.Companion.JOIN_STREAM_ID
import org.schabi.newpipe.database.history.model.StreamHistoryEntity.Companion.STREAM_ACCESS_DATE
@@ -1,7 +1,7 @@
package org.schabi.newpipe.database.history.model
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room3.ColumnInfo
import androidx.room3.Embedded
import java.time.OffsetDateTime
import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.extractor.stream.StreamInfoItem
@@ -6,7 +6,7 @@
package org.schabi.newpipe.database.playlist
import androidx.room.ColumnInfo
import androidx.room3.ColumnInfo
import org.schabi.newpipe.database.playlist.model.PlaylistEntity
/**
@@ -6,7 +6,7 @@
package org.schabi.newpipe.database.playlist
import androidx.room.ColumnInfo
import androidx.room3.ColumnInfo
import org.schabi.newpipe.database.LocalItem.LocalItemType
import org.schabi.newpipe.database.playlist.model.PlaylistEntity
@@ -6,8 +6,8 @@
package org.schabi.newpipe.database.playlist
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room3.ColumnInfo
import androidx.room3.Embedded
import org.schabi.newpipe.database.LocalItem
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
import org.schabi.newpipe.database.stream.model.StreamEntity
@@ -6,14 +6,17 @@
package org.schabi.newpipe.database.playlist.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Query
import androidx.room3.Transaction
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.playlist.model.PlaylistEntity
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
interface PlaylistDAO : BasicDAO<PlaylistEntity> {
@Query("SELECT * FROM playlists")
@@ -6,14 +6,17 @@
package org.schabi.newpipe.database.playlist.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room.Transaction
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Query
import androidx.room3.Transaction
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
interface PlaylistRemoteDAO : BasicDAO<PlaylistRemoteEntity> {
@Query("SELECT * FROM remote_playlists")
@@ -6,10 +6,12 @@
package org.schabi.newpipe.database.playlist.dao
import androidx.room.Dao
import androidx.room.Query
import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room.Transaction
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Query
import androidx.room3.RewriteQueriesToDropUnusedColumns
import androidx.room3.Transaction
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.playlist.PlaylistDuplicatesEntry
@@ -19,6 +21,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistEntity.Companion.DEFAU
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
interface PlaylistStreamDAO : BasicDAO<PlaylistStreamEntity> {
@Query("SELECT * FROM playlist_stream_join")
@@ -6,13 +6,13 @@
package org.schabi.newpipe.database.playlist.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.Ignore
import androidx.room3.PrimaryKey
import org.schabi.newpipe.database.playlist.PlaylistMetadataEntry
@Entity(tableName = PlaylistEntity.Companion.PLAYLIST_TABLE)
@Entity(tableName = PlaylistEntity.PLAYLIST_TABLE)
data class PlaylistEntity @JvmOverloads constructor(
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = PLAYLIST_ID)
@@ -7,11 +7,11 @@
package org.schabi.newpipe.database.playlist.model
import android.text.TextUtils
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.Ignore
import androidx.room3.Index
import androidx.room3.PrimaryKey
import org.schabi.newpipe.database.LocalItem.LocalItemType
import org.schabi.newpipe.database.playlist.PlaylistLocalItem
import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.Companion.REMOTE_PLAYLIST_SERVICE_ID
@@ -6,11 +6,11 @@
package org.schabi.newpipe.database.playlist.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.ForeignKey.Companion.CASCADE
import androidx.room.Index
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.ForeignKey
import androidx.room3.ForeignKey.Companion.CASCADE
import androidx.room3.Index
import org.schabi.newpipe.database.LocalItem
import org.schabi.newpipe.database.playlist.model.PlaylistEntity.Companion.PLAYLIST_ID
import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity.Companion.JOIN_INDEX
@@ -6,9 +6,9 @@
package org.schabi.newpipe.database.stream
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room.Ignore
import androidx.room3.ColumnInfo
import androidx.room3.Embedded
import androidx.room3.Ignore
import java.time.OffsetDateTime
import org.schabi.newpipe.database.LocalItem
import org.schabi.newpipe.database.history.model.StreamHistoryEntity
@@ -1,7 +1,7 @@
package org.schabi.newpipe.database.stream
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room3.ColumnInfo
import androidx.room3.Embedded
import org.schabi.newpipe.database.stream.model.StreamEntity
import org.schabi.newpipe.database.stream.model.StreamStateEntity
@@ -1,11 +1,13 @@
package org.schabi.newpipe.database.stream.dao
import androidx.room.ColumnInfo
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room3.ColumnInfo
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Insert
import androidx.room3.OnConflictStrategy
import androidx.room3.Query
import androidx.room3.Transaction
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Flowable
import java.time.OffsetDateTime
@@ -16,6 +18,7 @@ import org.schabi.newpipe.extractor.stream.StreamType
import org.schabi.newpipe.util.StreamTypeUtil
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
abstract class StreamDAO : BasicDAO<StreamEntity> {
@Query("SELECT * FROM streams")
abstract override fun getAll(): Flowable<List<StreamEntity>>
@@ -6,16 +6,19 @@
package org.schabi.newpipe.database.stream.dao
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.Transaction
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Insert
import androidx.room3.OnConflictStrategy
import androidx.room3.Query
import androidx.room3.Transaction
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import org.schabi.newpipe.database.BasicDAO
import org.schabi.newpipe.database.stream.model.StreamStateEntity
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
interface StreamStateDAO : BasicDAO<StreamStateEntity> {
@Query("SELECT * FROM " + StreamStateEntity.STREAM_STATE_TABLE)
@@ -34,7 +37,7 @@ interface StreamStateDAO : BasicDAO<StreamStateEntity> {
@Query("DELETE FROM " + StreamStateEntity.STREAM_STATE_TABLE + " WHERE " + StreamStateEntity.JOIN_STREAM_ID + " = :streamId")
fun deleteState(streamId: Long): Int
@Insert(onConflict = OnConflictStrategy.Companion.IGNORE)
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun silentInsertInternal(streamState: StreamStateEntity)
@Transaction
@@ -1,10 +1,10 @@
package org.schabi.newpipe.database.stream.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.Ignore
import androidx.room3.Index
import androidx.room3.PrimaryKey
import java.io.Serializable
import java.time.OffsetDateTime
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_SERVICE_ID
@@ -6,13 +6,12 @@
package org.schabi.newpipe.database.stream.model
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.ForeignKey
import androidx.room.ForeignKey.Companion.CASCADE
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.ForeignKey
import androidx.room3.ForeignKey.Companion.CASCADE
import org.schabi.newpipe.database.stream.model.StreamEntity.Companion.STREAM_ID
import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.JOIN_STREAM_ID
import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.PLAYBACK_FINISHED_END_MILLISECONDS
import org.schabi.newpipe.database.stream.model.StreamStateEntity.Companion.STREAM_STATE_TABLE
@Entity(
@@ -1,16 +1,19 @@
package org.schabi.newpipe.database.subscription
import androidx.room.Dao
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RewriteQueriesToDropUnusedColumns
import androidx.room.Transaction
import androidx.room3.Dao
import androidx.room3.DaoReturnTypeConverters
import androidx.room3.Insert
import androidx.room3.OnConflictStrategy
import androidx.room3.Query
import androidx.room3.RewriteQueriesToDropUnusedColumns
import androidx.room3.Transaction
import androidx.room3.rxjava3.RxDaoReturnTypeConverters
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import org.schabi.newpipe.database.BasicDAO
@Dao
@DaoReturnTypeConverters(RxDaoReturnTypeConverters::class)
abstract class SubscriptionDAO : BasicDAO<SubscriptionEntity> {
@Query("SELECT COUNT(*) FROM subscriptions")
abstract fun rowCount(): Flowable<Long>
@@ -6,21 +6,24 @@
package org.schabi.newpipe.database.subscription
import androidx.room.ColumnInfo
import androidx.room.Entity
import androidx.room.Ignore
import androidx.room.Index
import androidx.room.PrimaryKey
import androidx.room3.ColumnInfo
import androidx.room3.Entity
import androidx.room3.Ignore
import androidx.room3.Index
import androidx.room3.PrimaryKey
import org.schabi.newpipe.extractor.channel.ChannelInfo
import org.schabi.newpipe.extractor.channel.ChannelInfoItem
import org.schabi.newpipe.util.NO_SERVICE_ID
import org.schabi.newpipe.util.image.ImageStrategy
@Entity(
tableName = SubscriptionEntity.Companion.SUBSCRIPTION_TABLE,
tableName = SubscriptionEntity.SUBSCRIPTION_TABLE,
indices = [
Index(
value = [SubscriptionEntity.Companion.SUBSCRIPTION_SERVICE_ID, SubscriptionEntity.Companion.SUBSCRIPTION_URL],
value = [
SubscriptionEntity.SUBSCRIPTION_SERVICE_ID,
SubscriptionEntity.SUBSCRIPTION_URL
],
unique = true
)
]
+1
View File
@@ -24,4 +24,5 @@ plugins {
alias(libs.plugins.sonarqube) apply false
alias(libs.plugins.koin) apply false
alias(libs.plugins.about.libraries) apply false
alias(libs.plugins.androidx.room) apply false
}
+8 -5
View File
@@ -54,7 +54,7 @@ phoenix = "3.0.0"
preference = "1.2.1"
prettytime = "5.0.8.Final"
recyclerview = "1.4.0"
room = "2.8.5" # Needs migration to 3.x, may as well be moved to shared
room = "3.0.3"
runner = "1.7.0"
rxandroid = "3.0.2"
rxbinding = "4.0.0"
@@ -63,6 +63,7 @@ settings = "1.3.0"
sonarqube = "7.5.0.8588"
statesaver = "1.4.1" # TODO: Drop because it is deprecated and incompatible with KSP2
stetho = "1.6.0"
sqlite = "2.7.1"
swiperefreshlayout = "1.2.0"
# You can use a local version by uncommenting a few lines in settings.gradle
# Or you can use a commit you pushed to GitHub by just replacing TeamNewPipe with your GitHub
@@ -99,12 +100,13 @@ androidx-localbroadcastmanager = { module = "androidx.localbroadcastmanager:loca
androidx-media = { module = "androidx.media:media", version.ref = "media" }
androidx-preference = { module = "androidx.preference:preference", version.ref = "preference" }
androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
androidx-room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
androidx-room-runtime = { module = "androidx.room:room-runtime", version.ref = "room" }
androidx-room-rxjava3 = { module = "androidx.room:room-rxjava3", version.ref = "room" }
androidx-room-testing = { module = "androidx.room:room-testing", version.ref = "room" }
androidx-room-compiler = { module = "androidx.room3:room3-compiler", version.ref = "room" }
androidx-room-runtime = { module = "androidx.room3:room3-runtime", version.ref = "room" }
androidx-room-rxjava3 = { module = "androidx.room3:room3-rxjava3", version.ref = "room" }
androidx-room-testing = { module = "androidx.room3:room3-testing", version.ref = "room" }
androidx-runner = { module = "androidx.test:runner", version.ref = "runner" }
androidx-swiperefreshlayout = { module = "androidx.swiperefreshlayout:swiperefreshlayout", version.ref = "swiperefreshlayout" }
androidx-sqlite-bundled = { module = "androidx.sqlite:sqlite-bundled", version.ref = "sqlite" }
androidx-test-espresso-core = { module = "androidx.test.espresso:espresso-core", version.ref = "espresso" }
androidx-viewpager2 = { module = "androidx.viewpager2:viewpager2", version.ref = "viewpager2" }
androidx-webkit = { module = "androidx.webkit:webkit", version.ref = "webkit" }
@@ -179,6 +181,7 @@ about-libraries = { id = "com.mikepenz.aboutlibraries.plugin", version.ref = "ab
android-application = { id = "com.android.application", version.ref = "agp" }
android-legacy-kapt = { id = "com.android.legacy-kapt", version.ref = "agp" } # Needed for statesaver
android-library = { id = "com.android.kotlin.multiplatform.library", version.ref = "agp" }
androidx-room = { id = "androidx.room3", version.ref = "room" }
google-ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
jetbrains-compose-multiplatform = { id = "org.jetbrains.compose", version.ref = "multiplatform" }
jetbrains-kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }