浏览代码

Remove logic for restoring legacy JSON backups

- Protobuf backups have been around for 1.5 years now
- The ability to restore online-dependant data from JSON backups gets harder as time goes on and sources drift
- If users really need a way to restore them, they can use an older version of the app, or a separate tool for translating between the formats could be created
arkon 2 年之前
父节点
当前提交
d1be221d7a
共有 20 个文件被更改,包括 47 次插入904 次删除
  1. 13 12
      app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt
  2. 0 8
      app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestoreValidator.kt
  3. 0 5
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt
  4. 2 8
      app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt
  5. 18 18
      app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt
  6. 2 2
      app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt
  7. 9 3
      app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestoreValidator.kt
  8. 0 252
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt
  9. 0 184
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt
  10. 0 66
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestoreValidator.kt
  11. 0 37
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/models/Backup.kt
  12. 0 3
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/models/DHistory.kt
  13. 0 49
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/CategoryTypeSerializer.kt
  14. 0 66
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/ChapterTypeSerializer.kt
  15. 0 41
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/HistoryTypeSerializer.kt
  16. 0 56
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/MangaTypeSerializer.kt
  17. 0 68
      app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/TrackTypeSerializer.kt
  18. 0 8
      app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt
  19. 3 15
      app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt
  20. 0 3
      app/src/main/res/values/strings.xml

+ 13 - 12
app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupManager.kt

@@ -12,14 +12,15 @@ import eu.kanade.tachiyomi.source.Source
 import eu.kanade.tachiyomi.source.SourceManager
 import eu.kanade.tachiyomi.source.model.toSChapter
 import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
-import uy.kohesive.injekt.injectLazy
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
 
 abstract class AbstractBackupManager(protected val context: Context) {
 
-    internal val databaseHelper: DatabaseHelper by injectLazy()
-    internal val sourceManager: SourceManager by injectLazy()
-    internal val trackManager: TrackManager by injectLazy()
-    protected val preferences: PreferencesHelper by injectLazy()
+    internal val db: DatabaseHelper = Injekt.get()
+    internal val sourceManager: SourceManager = Injekt.get()
+    internal val trackManager: TrackManager = Injekt.get()
+    protected val preferences: PreferencesHelper = Injekt.get()
 
     abstract fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean): String
 
@@ -29,7 +30,7 @@ abstract class AbstractBackupManager(protected val context: Context) {
      * @return [Manga], null if not found
      */
     internal fun getMangaFromDatabase(manga: Manga): Manga? =
-        databaseHelper.getManga(manga.url, manga.source).executeAsBlocking()
+        db.getManga(manga.url, manga.source).executeAsBlocking()
 
     /**
      * Fetches chapter information.
@@ -42,7 +43,7 @@ abstract class AbstractBackupManager(protected val context: Context) {
     internal suspend fun restoreChapters(source: Source, manga: Manga, chapters: List<Chapter>): Pair<List<Chapter>, List<Chapter>> {
         val fetchedChapters = source.getChapterList(manga.toMangaInfo())
             .map { it.toSChapter() }
-        val syncedChapters = syncChaptersWithSource(databaseHelper, fetchedChapters, manga, source)
+        val syncedChapters = syncChaptersWithSource(db, fetchedChapters, manga, source)
         if (syncedChapters.first.isNotEmpty()) {
             chapters.forEach { it.manga_id = manga.id }
             updateChapters(chapters)
@@ -56,7 +57,7 @@ abstract class AbstractBackupManager(protected val context: Context) {
      * @return [Manga] from library
      */
     protected fun getFavoriteManga(): List<Manga> =
-        databaseHelper.getFavoriteMangas().executeAsBlocking()
+        db.getFavoriteMangas().executeAsBlocking()
 
     /**
      * Inserts manga and returns id
@@ -64,27 +65,27 @@ abstract class AbstractBackupManager(protected val context: Context) {
      * @return id of [Manga], null if not found
      */
     internal fun insertManga(manga: Manga): Long? =
-        databaseHelper.insertManga(manga).executeAsBlocking().insertedId()
+        db.insertManga(manga).executeAsBlocking().insertedId()
 
     /**
      * Inserts list of chapters
      */
     protected fun insertChapters(chapters: List<Chapter>) {
-        databaseHelper.insertChapters(chapters).executeAsBlocking()
+        db.insertChapters(chapters).executeAsBlocking()
     }
 
     /**
      * Updates a list of chapters
      */
     protected fun updateChapters(chapters: List<Chapter>) {
-        databaseHelper.updateChaptersBackup(chapters).executeAsBlocking()
+        db.updateChaptersBackup(chapters).executeAsBlocking()
     }
 
     /**
      * Updates a list of chapters with known database ids
      */
     protected fun updateKnownChapters(chapters: List<Chapter>) {
-        databaseHelper.updateKnownChaptersBackup(chapters).executeAsBlocking()
+        db.updateKnownChaptersBackup(chapters).executeAsBlocking()
     }
 
     /**

+ 0 - 8
app/src/main/java/eu/kanade/tachiyomi/data/backup/AbstractBackupRestoreValidator.kt

@@ -2,17 +2,9 @@ package eu.kanade.tachiyomi.data.backup
 
 import android.content.Context
 import android.net.Uri
-import eu.kanade.tachiyomi.data.track.TrackManager
-import eu.kanade.tachiyomi.source.SourceManager
-import uy.kohesive.injekt.injectLazy
 
 abstract class AbstractBackupRestoreValidator {
-    protected val sourceManager: SourceManager by injectLazy()
-    protected val trackManager: TrackManager by injectLazy()
-
     abstract fun validate(context: Context, uri: Uri): Results
 
     data class Results(val missingSources: List<String>, val missingTrackers: List<String>)
 }
-
-class ValidatorParseException(e: Exception) : RuntimeException(e)

+ 0 - 5
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupConst.kt

@@ -6,11 +6,6 @@ object BackupConst {
 
     private const val NAME = "BackupRestoreServices"
     const val EXTRA_URI = "$ID.$NAME.EXTRA_URI"
-    const val EXTRA_FLAGS = "$ID.$NAME.EXTRA_FLAGS"
-    const val EXTRA_MODE = "$ID.$NAME.EXTRA_MODE"
-
-    const val BACKUP_TYPE_LEGACY = 0
-    const val BACKUP_TYPE_FULL = 1
 
     // Filter options
     internal const val BACKUP_CATEGORY = 0x1

+ 2 - 8
app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupRestoreService.kt

@@ -9,7 +9,6 @@ import android.os.PowerManager
 import androidx.core.content.ContextCompat
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.backup.full.FullBackupRestore
-import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupRestore
 import eu.kanade.tachiyomi.data.notification.Notifications
 import eu.kanade.tachiyomi.util.system.acquireWakeLock
 import eu.kanade.tachiyomi.util.system.isServiceRunning
@@ -44,11 +43,10 @@ class BackupRestoreService : Service() {
          * @param context context of application
          * @param uri path of Uri
          */
-        fun start(context: Context, uri: Uri, mode: Int) {
+        fun start(context: Context, uri: Uri) {
             if (!isRunning(context)) {
                 val intent = Intent(context, BackupRestoreService::class.java).apply {
                     putExtra(BackupConst.EXTRA_URI, uri)
-                    putExtra(BackupConst.EXTRA_MODE, mode)
                 }
                 ContextCompat.startForegroundService(context, intent)
             }
@@ -118,15 +116,11 @@ class BackupRestoreService : Service() {
      */
     override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
         val uri = intent?.getParcelableExtra<Uri>(BackupConst.EXTRA_URI) ?: return START_NOT_STICKY
-        val mode = intent.getIntExtra(BackupConst.EXTRA_MODE, BackupConst.BACKUP_TYPE_FULL)
 
         // Cancel any previous job if needed.
         backupRestore?.job?.cancel()
 
-        backupRestore = when (mode) {
-            BackupConst.BACKUP_TYPE_FULL -> FullBackupRestore(this, notifier)
-            else -> LegacyBackupRestore(this, notifier)
-        }
+        backupRestore = FullBackupRestore(this, notifier)
 
         val handler = CoroutineExceptionHandler { _, exception ->
             logcat(LogPriority.ERROR, exception)

+ 18 - 18
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupManager.kt

@@ -50,7 +50,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         // Create root object
         var backup: Backup? = null
 
-        databaseHelper.inTransaction {
+        db.inTransaction {
             val databaseManga = getFavoriteManga()
 
             backup = Backup(
@@ -136,7 +136,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
     private fun backupCategories(options: Int): List<BackupCategory> {
         // Check if user wants category information in backup
         return if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
-            databaseHelper.getCategories()
+            db.getCategories()
                 .executeAsBlocking()
                 .map { BackupCategory.copyFrom(it) }
         } else {
@@ -158,7 +158,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         // Check if user wants chapter information in backup
         if (options and BACKUP_CHAPTER_MASK == BACKUP_CHAPTER) {
             // Backup all the chapters
-            val chapters = databaseHelper.getChapters(manga).executeAsBlocking()
+            val chapters = db.getChapters(manga).executeAsBlocking()
             if (chapters.isNotEmpty()) {
                 mangaObject.chapters = chapters.map { BackupChapter.copyFrom(it) }
             }
@@ -167,7 +167,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         // Check if user wants category information in backup
         if (options and BACKUP_CATEGORY_MASK == BACKUP_CATEGORY) {
             // Backup categories for this manga
-            val categoriesForManga = databaseHelper.getCategoriesForManga(manga).executeAsBlocking()
+            val categoriesForManga = db.getCategoriesForManga(manga).executeAsBlocking()
             if (categoriesForManga.isNotEmpty()) {
                 mangaObject.categories = categoriesForManga.mapNotNull { it.order }
             }
@@ -175,7 +175,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
 
         // Check if user wants track information in backup
         if (options and BACKUP_TRACK_MASK == BACKUP_TRACK) {
-            val tracks = databaseHelper.getTracks(manga).executeAsBlocking()
+            val tracks = db.getTracks(manga).executeAsBlocking()
             if (tracks.isNotEmpty()) {
                 mangaObject.tracking = tracks.map { BackupTracking.copyFrom(it) }
             }
@@ -183,10 +183,10 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
 
         // Check if user wants history information in backup
         if (options and BACKUP_HISTORY_MASK == BACKUP_HISTORY) {
-            val historyForManga = databaseHelper.getHistoryByMangaId(manga.id!!).executeAsBlocking()
+            val historyForManga = db.getHistoryByMangaId(manga.id!!).executeAsBlocking()
             if (historyForManga.isNotEmpty()) {
                 val history = historyForManga.mapNotNull { history ->
-                    val url = databaseHelper.getChapter(history.chapter_id).executeAsBlocking()?.url
+                    val url = db.getChapter(history.chapter_id).executeAsBlocking()?.url
                     url?.let { BackupHistory(url, history.last_read) }
                 }
                 if (history.isNotEmpty()) {
@@ -224,7 +224,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      */
     internal fun restoreCategories(backupCategories: List<BackupCategory>) {
         // Get categories from file and from db
-        val dbCategories = databaseHelper.getCategories().executeAsBlocking()
+        val dbCategories = db.getCategories().executeAsBlocking()
 
         // Iterate over them
         backupCategories.map { it.getCategoryImpl() }.forEach { category ->
@@ -244,7 +244,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
             if (!found) {
                 // Let the db assign the id
                 category.id = null
-                val result = databaseHelper.insertCategory(category).executeAsBlocking()
+                val result = db.insertCategory(category).executeAsBlocking()
                 category.id = result.insertedId()?.toInt()
             }
         }
@@ -257,7 +257,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
      * @param categories the categories to restore.
      */
     internal fun restoreCategoriesForManga(manga: Manga, categories: List<Int>, backupCategories: List<BackupCategory>) {
-        val dbCategories = databaseHelper.getCategories().executeAsBlocking()
+        val dbCategories = db.getCategories().executeAsBlocking()
         val mangaCategoriesToUpdate = ArrayList<MangaCategory>(categories.size)
         categories.forEach { backupCategoryOrder ->
             backupCategories.firstOrNull {
@@ -273,8 +273,8 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
 
         // Update database
         if (mangaCategoriesToUpdate.isNotEmpty()) {
-            databaseHelper.deleteOldMangasCategories(listOf(manga)).executeAsBlocking()
-            databaseHelper.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking()
+            db.deleteOldMangasCategories(listOf(manga)).executeAsBlocking()
+            db.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking()
         }
     }
 
@@ -287,7 +287,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         // List containing history to be updated
         val historyToBeUpdated = ArrayList<History>(history.size)
         for ((url, lastRead) in history) {
-            val dbHistory = databaseHelper.getHistoryByChapterUrl(url).executeAsBlocking()
+            val dbHistory = db.getHistoryByChapterUrl(url).executeAsBlocking()
             // Check if history already in database and update
             if (dbHistory != null) {
                 dbHistory.apply {
@@ -296,7 +296,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
                 historyToBeUpdated.add(dbHistory)
             } else {
                 // If not in database create
-                databaseHelper.getChapter(url).executeAsBlocking()?.let {
+                db.getChapter(url).executeAsBlocking()?.let {
                     val historyToAdd = History.create(it).apply {
                         last_read = lastRead
                     }
@@ -304,7 +304,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
                 }
             }
         }
-        databaseHelper.upsertHistoryLastRead(historyToBeUpdated).executeAsBlocking()
+        db.upsertHistoryLastRead(historyToBeUpdated).executeAsBlocking()
     }
 
     /**
@@ -318,7 +318,7 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         tracks.map { it.manga_id = manga.id!! }
 
         // Get tracks from database
-        val dbTracks = databaseHelper.getTracks(manga).executeAsBlocking()
+        val dbTracks = db.getTracks(manga).executeAsBlocking()
         val trackToUpdate = mutableListOf<Track>()
 
         tracks.forEach { track ->
@@ -346,12 +346,12 @@ class FullBackupManager(context: Context) : AbstractBackupManager(context) {
         }
         // Update database
         if (trackToUpdate.isNotEmpty()) {
-            databaseHelper.insertTracks(trackToUpdate).executeAsBlocking()
+            db.insertTracks(trackToUpdate).executeAsBlocking()
         }
     }
 
     internal fun restoreChaptersForManga(manga: Manga, chapters: List<Chapter>) {
-        val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
+        val dbChapters = db.getChapters(manga).executeAsBlocking()
 
         chapters.forEach { chapter ->
             val dbChapter = dbChapters.find { it.url == chapter.url }

+ 2 - 2
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestore.kt

@@ -34,8 +34,8 @@ class FullBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBa
         }
 
         // Store source mapping for error messages
-        var backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources
-        sourceMapping = backupMaps.map { it.sourceId to it.name }.toMap()
+        val backupMaps = backup.backupBrokenSources.map { BackupSource(it.name, it.sourceId) } + backup.backupSources
+        sourceMapping = backupMaps.associate { it.sourceId to it.name }
 
         // Restore individual manga
         backup.backupManga.forEach {

+ 9 - 3
app/src/main/java/eu/kanade/tachiyomi/data/backup/full/FullBackupRestoreValidator.kt

@@ -4,14 +4,20 @@ import android.content.Context
 import android.net.Uri
 import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
-import eu.kanade.tachiyomi.data.backup.ValidatorParseException
 import eu.kanade.tachiyomi.data.backup.full.models.BackupSerializer
+import eu.kanade.tachiyomi.data.track.TrackManager
+import eu.kanade.tachiyomi.source.SourceManager
 import okio.buffer
 import okio.gzip
 import okio.source
+import uy.kohesive.injekt.Injekt
+import uy.kohesive.injekt.api.get
 
 class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
 
+    private val sourceManager: SourceManager = Injekt.get()
+    private val trackManager: TrackManager = Injekt.get()
+
     /**
      * Checks for critical backup file data.
      *
@@ -27,11 +33,11 @@ class FullBackupRestoreValidator : AbstractBackupRestoreValidator() {
                     .use { it.readByteArray() }
             backupManager.parser.decodeFromByteArray(BackupSerializer, backupString)
         } catch (e: Exception) {
-            throw ValidatorParseException(e)
+            throw IllegalStateException(e)
         }
 
         if (backup.backupManga.isEmpty()) {
-            throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
+            throw IllegalStateException(context.getString(R.string.invalid_backup_file_missing_manga))
         }
 
         val sources = backup.backupSources.associate { it.sourceId to it.name }

+ 0 - 252
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupManager.kt

@@ -1,252 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy
-
-import android.content.Context
-import android.net.Uri
-import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
-import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.Companion.CURRENT_VERSION
-import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryImplTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterImplTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.HistoryTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaImplTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackImplTypeSerializer
-import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackTypeSerializer
-import eu.kanade.tachiyomi.data.database.models.Category
-import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.History
-import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.data.database.models.MangaCategory
-import eu.kanade.tachiyomi.data.database.models.Track
-import eu.kanade.tachiyomi.data.database.models.toMangaInfo
-import eu.kanade.tachiyomi.source.Source
-import eu.kanade.tachiyomi.source.model.toSManga
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.modules.SerializersModule
-import kotlinx.serialization.modules.contextual
-import kotlin.math.max
-
-class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : AbstractBackupManager(context) {
-
-    val parser: Json = when (version) {
-        2 -> Json {
-            // Forks may have added items to backup
-            ignoreUnknownKeys = true
-
-            // Register custom serializers
-            serializersModule = SerializersModule {
-                contextual(MangaTypeSerializer)
-                contextual(MangaImplTypeSerializer)
-                contextual(ChapterTypeSerializer)
-                contextual(ChapterImplTypeSerializer)
-                contextual(CategoryTypeSerializer)
-                contextual(CategoryImplTypeSerializer)
-                contextual(TrackTypeSerializer)
-                contextual(TrackImplTypeSerializer)
-                contextual(HistoryTypeSerializer)
-            }
-        }
-        else -> throw Exception("Unknown backup version")
-    }
-
-    /**
-     * Create backup Json file from database
-     *
-     * @param uri path of Uri
-     * @param isAutoBackup backup called from scheduled backup job
-     */
-    override fun createBackup(uri: Uri, flags: Int, isAutoBackup: Boolean) =
-        throw IllegalStateException("Legacy backup creation is not supported")
-
-    fun restoreMangaNoFetch(manga: Manga, dbManga: Manga) {
-        manga.id = dbManga.id
-        manga.copyFrom(dbManga)
-        manga.favorite = true
-        insertManga(manga)
-    }
-
-    /**
-     * Fetches manga information
-     *
-     * @param source source of manga
-     * @param manga manga that needs updating
-     * @return Updated manga.
-     */
-    suspend fun fetchManga(source: Source, manga: Manga): Manga {
-        val networkManga = source.getMangaDetails(manga.toMangaInfo())
-        return manga.also {
-            it.copyFrom(networkManga.toSManga())
-            it.favorite = true
-            it.initialized = true
-            it.id = insertManga(manga)
-        }
-    }
-
-    /**
-     * Restore the categories from Json
-     *
-     * @param backupCategories array containing categories
-     */
-    internal fun restoreCategories(backupCategories: List<Category>) {
-        // Get categories from file and from db
-        val dbCategories = databaseHelper.getCategories().executeAsBlocking()
-
-        // Iterate over them
-        backupCategories.forEach { category ->
-            // Used to know if the category is already in the db
-            var found = false
-            for (dbCategory in dbCategories) {
-                // If the category is already in the db, assign the id to the file's category
-                // and do nothing
-                if (category.name == dbCategory.name) {
-                    category.id = dbCategory.id
-                    found = true
-                    break
-                }
-            }
-            // If the category isn't in the db, remove the id and insert a new category
-            // Store the inserted id in the category
-            if (!found) {
-                // Let the db assign the id
-                category.id = null
-                val result = databaseHelper.insertCategory(category).executeAsBlocking()
-                category.id = result.insertedId()?.toInt()
-            }
-        }
-    }
-
-    /**
-     * Restores the categories a manga is in.
-     *
-     * @param manga the manga whose categories have to be restored.
-     * @param categories the categories to restore.
-     */
-    internal fun restoreCategoriesForManga(manga: Manga, categories: List<String>) {
-        val dbCategories = databaseHelper.getCategories().executeAsBlocking()
-        val mangaCategoriesToUpdate = ArrayList<MangaCategory>(categories.size)
-        for (backupCategoryStr in categories) {
-            for (dbCategory in dbCategories) {
-                if (backupCategoryStr == dbCategory.name) {
-                    mangaCategoriesToUpdate.add(MangaCategory.create(manga, dbCategory))
-                    break
-                }
-            }
-        }
-
-        // Update database
-        if (mangaCategoriesToUpdate.isNotEmpty()) {
-            databaseHelper.deleteOldMangasCategories(listOf(manga)).executeAsBlocking()
-            databaseHelper.insertMangasCategories(mangaCategoriesToUpdate).executeAsBlocking()
-        }
-    }
-
-    /**
-     * Restore history from Json
-     *
-     * @param history list containing history to be restored
-     */
-    internal fun restoreHistoryForManga(history: List<DHistory>) {
-        // List containing history to be updated
-        val historyToBeUpdated = ArrayList<History>(history.size)
-        for ((url, lastRead) in history) {
-            val dbHistory = databaseHelper.getHistoryByChapterUrl(url).executeAsBlocking()
-            // Check if history already in database and update
-            if (dbHistory != null) {
-                dbHistory.apply {
-                    last_read = max(lastRead, dbHistory.last_read)
-                }
-                historyToBeUpdated.add(dbHistory)
-            } else {
-                // If not in database create
-                databaseHelper.getChapter(url).executeAsBlocking()?.let {
-                    val historyToAdd = History.create(it).apply {
-                        last_read = lastRead
-                    }
-                    historyToBeUpdated.add(historyToAdd)
-                }
-            }
-        }
-        databaseHelper.upsertHistoryLastRead(historyToBeUpdated).executeAsBlocking()
-    }
-
-    /**
-     * Restores the sync of a manga.
-     *
-     * @param manga the manga whose sync have to be restored.
-     * @param tracks the track list to restore.
-     */
-    internal fun restoreTrackForManga(manga: Manga, tracks: List<Track>) {
-        // Get tracks from database
-        val dbTracks = databaseHelper.getTracks(manga).executeAsBlocking()
-        val trackToUpdate = ArrayList<Track>(tracks.size)
-
-        tracks.forEach { track ->
-            // Fix foreign keys with the current manga id
-            track.manga_id = manga.id!!
-
-            val service = trackManager.getService(track.sync_id)
-            if (service != null && service.isLogged) {
-                var isInDatabase = false
-                for (dbTrack in dbTracks) {
-                    if (track.sync_id == dbTrack.sync_id) {
-                        // The sync is already in the db, only update its fields
-                        if (track.media_id != dbTrack.media_id) {
-                            dbTrack.media_id = track.media_id
-                        }
-                        if (track.library_id != dbTrack.library_id) {
-                            dbTrack.library_id = track.library_id
-                        }
-                        dbTrack.last_chapter_read = max(dbTrack.last_chapter_read, track.last_chapter_read)
-                        isInDatabase = true
-                        trackToUpdate.add(dbTrack)
-                        break
-                    }
-                }
-                if (!isInDatabase) {
-                    // Insert new sync. Let the db assign the id
-                    track.id = null
-                    trackToUpdate.add(track)
-                }
-            }
-        }
-        // Update database
-        if (trackToUpdate.isNotEmpty()) {
-            databaseHelper.insertTracks(trackToUpdate).executeAsBlocking()
-        }
-    }
-
-    /**
-     * Restore the chapters for manga if chapters already in database
-     *
-     * @param manga manga of chapters
-     * @param chapters list containing chapters that get restored
-     * @return boolean answering if chapter fetch is not needed
-     */
-    internal fun restoreChaptersForManga(manga: Manga, chapters: List<Chapter>): Boolean {
-        val dbChapters = databaseHelper.getChapters(manga).executeAsBlocking()
-
-        // Return if fetch is needed
-        if (dbChapters.isEmpty() || dbChapters.size < chapters.size) {
-            return false
-        }
-
-        for (chapter in chapters) {
-            val pos = dbChapters.indexOf(chapter)
-            if (pos != -1) {
-                val dbChapter = dbChapters[pos]
-                chapter.id = dbChapter.id
-                chapter.copyFrom(dbChapter)
-                break
-            }
-
-            chapter.manga_id = manga.id
-        }
-
-        // Filter the chapters that couldn't be found.
-        updateChapters(chapters.filter { it.id != null })
-
-        return true
-    }
-}

+ 0 - 184
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestore.kt

@@ -1,184 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy
-
-import android.content.Context
-import android.net.Uri
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
-import eu.kanade.tachiyomi.data.backup.BackupNotifier
-import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
-import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
-import eu.kanade.tachiyomi.data.backup.legacy.models.MangaObject
-import eu.kanade.tachiyomi.data.database.models.Category
-import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.data.database.models.Track
-import eu.kanade.tachiyomi.source.Source
-import kotlinx.serialization.json.Json
-import kotlinx.serialization.json.JsonObject
-import kotlinx.serialization.json.decodeFromJsonElement
-import kotlinx.serialization.json.decodeFromStream
-import kotlinx.serialization.json.intOrNull
-import kotlinx.serialization.json.jsonPrimitive
-import java.util.Date
-
-class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
-
-    override suspend fun performRestore(uri: Uri): Boolean {
-        // Read the json and create a Json Object,
-        // cannot use the backupManager json deserializer one because its not initialized yet
-        val backupObject = Json.decodeFromStream<JsonObject>(
-            context.contentResolver.openInputStream(uri)!!,
-        )
-
-        // Get parser version
-        val version = backupObject["version"]?.jsonPrimitive?.intOrNull ?: 1
-
-        // Initialize manager
-        backupManager = LegacyBackupManager(context, version)
-
-        // Decode the json object to a Backup object
-        val backup = backupManager.parser.decodeFromJsonElement<Backup>(backupObject)
-
-        restoreAmount = backup.mangas.size + 1 // +1 for categories
-
-        // Restore categories
-        backup.categories?.let { restoreCategories(it) }
-
-        // Store source mapping for error messages
-        sourceMapping = LegacyBackupRestoreValidator.getSourceMapping(backup.extensions ?: emptyList())
-
-        // Restore individual manga
-        backup.mangas.forEach {
-            if (job?.isActive != true) {
-                return false
-            }
-
-            restoreManga(it)
-        }
-
-        return true
-    }
-
-    private fun restoreCategories(categoriesJson: List<Category>) {
-        db.inTransaction {
-            backupManager.restoreCategories(categoriesJson)
-        }
-
-        restoreProgress += 1
-        showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
-    }
-
-    private suspend fun restoreManga(mangaJson: MangaObject) {
-        val manga = mangaJson.manga
-        val chapters = mangaJson.chapters ?: emptyList()
-        val categories = mangaJson.categories ?: emptyList()
-        val history = mangaJson.history ?: emptyList()
-        val tracks = mangaJson.track ?: emptyList()
-
-        val source = backupManager.sourceManager.get(manga.source)
-        val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
-
-        try {
-            if (source != null) {
-                restoreMangaData(manga, source, chapters, categories, history, tracks)
-            } else {
-                errors.add(Date() to "${manga.title} [$sourceName]: ${context.getString(R.string.source_not_found_name, sourceName)}")
-            }
-        } catch (e: Exception) {
-            errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
-        }
-
-        restoreProgress += 1
-        showRestoreProgress(restoreProgress, restoreAmount, manga.title)
-    }
-
-    /**
-     * Returns a manga restore observable
-     *
-     * @param manga manga data from json
-     * @param source source to get manga data from
-     * @param chapters chapters data from json
-     * @param categories categories data from json
-     * @param history history data from json
-     * @param tracks tracking data from json
-     */
-    private suspend fun restoreMangaData(
-        manga: Manga,
-        source: Source,
-        chapters: List<Chapter>,
-        categories: List<String>,
-        history: List<DHistory>,
-        tracks: List<Track>,
-    ) {
-        val dbManga = backupManager.getMangaFromDatabase(manga)
-
-        db.inTransaction {
-            if (dbManga == null) {
-                // Manga not in database
-                restoreMangaFetch(source, manga, chapters, categories, history, tracks)
-            } else { // Manga in database
-                // Copy information from manga already in database
-                backupManager.restoreMangaNoFetch(manga, dbManga)
-                // Fetch rest of manga information
-                restoreMangaNoFetch(source, manga, chapters, categories, history, tracks)
-            }
-        }
-    }
-
-    /**
-     * Fetches manga information.
-     *
-     * @param manga manga that needs updating
-     * @param chapters chapters of manga that needs updating
-     * @param categories categories that need updating
-     */
-    private suspend fun restoreMangaFetch(
-        source: Source,
-        manga: Manga,
-        chapters: List<Chapter>,
-        categories: List<String>,
-        history: List<DHistory>,
-        tracks: List<Track>,
-    ) {
-        try {
-            val fetchedManga = backupManager.fetchManga(source, manga)
-            fetchedManga.id ?: return
-
-            updateChapters(source, fetchedManga, chapters)
-
-            restoreExtraForManga(fetchedManga, categories, history, tracks)
-
-            updateTracking(fetchedManga, tracks)
-        } catch (e: Exception) {
-            errors.add(Date() to "${manga.title} - ${e.message}")
-        }
-    }
-
-    private suspend fun restoreMangaNoFetch(
-        source: Source,
-        backupManga: Manga,
-        chapters: List<Chapter>,
-        categories: List<String>,
-        history: List<DHistory>,
-        tracks: List<Track>,
-    ) {
-        if (!backupManager.restoreChaptersForManga(backupManga, chapters)) {
-            updateChapters(source, backupManga, chapters)
-        }
-
-        restoreExtraForManga(backupManga, categories, history, tracks)
-
-        updateTracking(backupManga, tracks)
-    }
-
-    private fun restoreExtraForManga(manga: Manga, categories: List<String>, history: List<DHistory>, tracks: List<Track>) {
-        // Restore categories
-        backupManager.restoreCategoriesForManga(manga, categories)
-
-        // Restore history
-        backupManager.restoreHistoryForManga(history)
-
-        // Restore tracking
-        backupManager.restoreTrackForManga(manga, tracks)
-    }
-}

+ 0 - 66
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/LegacyBackupRestoreValidator.kt

@@ -1,66 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy
-
-import android.content.Context
-import android.net.Uri
-import eu.kanade.tachiyomi.R
-import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
-import eu.kanade.tachiyomi.data.backup.ValidatorParseException
-import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
-import kotlinx.serialization.json.decodeFromStream
-
-class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
-
-    /**
-     * Checks for critical backup file data.
-     *
-     * @throws Exception if version or manga cannot be found.
-     * @return List of missing sources or missing trackers.
-     */
-    override fun validate(context: Context, uri: Uri): Results {
-        val backupManager = LegacyBackupManager(context)
-
-        val backup = try {
-            backupManager.parser.decodeFromStream<Backup>(
-                context.contentResolver.openInputStream(uri)!!,
-            )
-        } catch (e: Exception) {
-            throw ValidatorParseException(e)
-        }
-
-        if (backup.version == null) {
-            throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
-        }
-
-        if (backup.mangas.isEmpty()) {
-            throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
-        }
-
-        val sources = getSourceMapping(backup.extensions ?: emptyList())
-        val missingSources = sources
-            .filter { sourceManager.get(it.key) == null }
-            .values
-            .sorted()
-
-        val trackers = backup.mangas
-            .filterNot { it.track.isNullOrEmpty() }
-            .flatMap { it.track ?: emptyList() }
-            .map { it.sync_id }
-            .distinct()
-        val missingTrackers = trackers
-            .mapNotNull { trackManager.getService(it) }
-            .filter { !it.isLogged }
-            .map { context.getString(it.nameRes()) }
-            .sorted()
-
-        return Results(missingSources, missingTrackers)
-    }
-
-    companion object {
-        fun getSourceMapping(extensionsMapping: List<String>): Map<Long, String> {
-            return extensionsMapping.associate {
-                val items = it.split(":")
-                items[0].toLong() to items[1]
-            }
-        }
-    }
-}

+ 0 - 37
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/models/Backup.kt

@@ -1,37 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.models
-
-import eu.kanade.tachiyomi.data.database.models.Category
-import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.data.database.models.Track
-import kotlinx.serialization.Contextual
-import kotlinx.serialization.Serializable
-import java.text.SimpleDateFormat
-import java.util.Date
-import java.util.Locale
-
-@Serializable
-data class Backup(
-    val version: Int? = null,
-    var mangas: MutableList<MangaObject> = mutableListOf(),
-    var categories: List<@Contextual Category>? = null,
-    var extensions: List<String>? = null,
-) {
-    companion object {
-        const val CURRENT_VERSION = 2
-
-        fun getDefaultFilename(): String {
-            val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
-            return "tachiyomi_$date.json"
-        }
-    }
-}
-
-@Serializable
-data class MangaObject(
-    var manga: @Contextual Manga,
-    var chapters: List<@Contextual Chapter>? = null,
-    var categories: List<String>? = null,
-    var track: List<@Contextual Track>? = null,
-    var history: List<@Contextual DHistory>? = null,
-)

+ 0 - 3
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/models/DHistory.kt

@@ -1,3 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.models
-
-data class DHistory(val url: String, val lastRead: Long)

+ 0 - 49
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/CategoryTypeSerializer.kt

@@ -1,49 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.serializer
-
-import eu.kanade.tachiyomi.data.database.models.Category
-import eu.kanade.tachiyomi.data.database.models.CategoryImpl
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.descriptors.buildClassSerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.json.JsonDecoder
-import kotlinx.serialization.json.JsonEncoder
-import kotlinx.serialization.json.add
-import kotlinx.serialization.json.buildJsonArray
-import kotlinx.serialization.json.int
-import kotlinx.serialization.json.jsonArray
-import kotlinx.serialization.json.jsonPrimitive
-
-/**
- * JSON Serializer used to write / read [CategoryImpl] to / from json
- */
-open class CategoryBaseSerializer<T : Category> : KSerializer<T> {
-    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Category")
-
-    override fun serialize(encoder: Encoder, value: T) {
-        encoder as JsonEncoder
-        encoder.encodeJsonElement(
-            buildJsonArray {
-                add(value.name)
-                add(value.order)
-            },
-        )
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    override fun deserialize(decoder: Decoder): T {
-        // make a category impl and cast as T so that the serializer accepts it
-        return CategoryImpl().apply {
-            decoder as JsonDecoder
-            val array = decoder.decodeJsonElement().jsonArray
-            name = array[0].jsonPrimitive.content
-            order = array[1].jsonPrimitive.int
-        } as T
-    }
-}
-
-// Allow for serialization of a category and category impl
-object CategoryTypeSerializer : CategoryBaseSerializer<Category>()
-
-object CategoryImplTypeSerializer : CategoryBaseSerializer<CategoryImpl>()

+ 0 - 66
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/ChapterTypeSerializer.kt

@@ -1,66 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.serializer
-
-import eu.kanade.tachiyomi.data.database.models.Chapter
-import eu.kanade.tachiyomi.data.database.models.ChapterImpl
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.buildClassSerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.json.JsonDecoder
-import kotlinx.serialization.json.JsonEncoder
-import kotlinx.serialization.json.buildJsonObject
-import kotlinx.serialization.json.intOrNull
-import kotlinx.serialization.json.jsonObject
-import kotlinx.serialization.json.jsonPrimitive
-import kotlinx.serialization.json.put
-
-/**
- * JSON Serializer used to write / read [ChapterImpl] to / from json
- */
-open class ChapterBaseSerializer<T : Chapter> : KSerializer<T> {
-
-    override val descriptor = buildClassSerialDescriptor("Chapter")
-
-    override fun serialize(encoder: Encoder, value: T) {
-        encoder as JsonEncoder
-        encoder.encodeJsonElement(
-            buildJsonObject {
-                put(URL, value.url)
-                if (value.read) {
-                    put(READ, 1)
-                }
-                if (value.bookmark) {
-                    put(BOOKMARK, 1)
-                }
-                if (value.last_page_read != 0) {
-                    put(LAST_READ, value.last_page_read)
-                }
-            },
-        )
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    override fun deserialize(decoder: Decoder): T {
-        // make a chapter impl and cast as T so that the serializer accepts it
-        return ChapterImpl().apply {
-            decoder as JsonDecoder
-            val jsonObject = decoder.decodeJsonElement().jsonObject
-            url = jsonObject[URL]!!.jsonPrimitive.content
-            read = jsonObject[READ]?.jsonPrimitive?.intOrNull == 1
-            bookmark = jsonObject[BOOKMARK]?.jsonPrimitive?.intOrNull == 1
-            last_page_read = jsonObject[LAST_READ]?.jsonPrimitive?.intOrNull ?: last_page_read
-        } as T
-    }
-
-    companion object {
-        private const val URL = "u"
-        private const val READ = "r"
-        private const val BOOKMARK = "b"
-        private const val LAST_READ = "l"
-    }
-}
-
-// Allow for serialization of a chapter and chapter impl
-object ChapterTypeSerializer : ChapterBaseSerializer<Chapter>()
-
-object ChapterImplTypeSerializer : ChapterBaseSerializer<ChapterImpl>()

+ 0 - 41
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/HistoryTypeSerializer.kt

@@ -1,41 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.serializer
-
-import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.descriptors.buildClassSerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.json.JsonDecoder
-import kotlinx.serialization.json.JsonEncoder
-import kotlinx.serialization.json.add
-import kotlinx.serialization.json.buildJsonArray
-import kotlinx.serialization.json.jsonArray
-import kotlinx.serialization.json.jsonPrimitive
-import kotlinx.serialization.json.long
-
-/**
- * JSON Serializer used to write / read [DHistory] to / from json
- */
-object HistoryTypeSerializer : KSerializer<DHistory> {
-    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("History")
-
-    override fun serialize(encoder: Encoder, value: DHistory) {
-        encoder as JsonEncoder
-        encoder.encodeJsonElement(
-            buildJsonArray {
-                add(value.url)
-                add(value.lastRead)
-            },
-        )
-    }
-
-    override fun deserialize(decoder: Decoder): DHistory {
-        decoder as JsonDecoder
-        val array = decoder.decodeJsonElement().jsonArray
-        return DHistory(
-            url = array[0].jsonPrimitive.content,
-            lastRead = array[1].jsonPrimitive.long,
-        )
-    }
-}

+ 0 - 56
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/MangaTypeSerializer.kt

@@ -1,56 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.serializer
-
-import eu.kanade.tachiyomi.data.database.models.Manga
-import eu.kanade.tachiyomi.data.database.models.MangaImpl
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.descriptors.buildClassSerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.json.JsonDecoder
-import kotlinx.serialization.json.JsonEncoder
-import kotlinx.serialization.json.add
-import kotlinx.serialization.json.buildJsonArray
-import kotlinx.serialization.json.int
-import kotlinx.serialization.json.jsonArray
-import kotlinx.serialization.json.jsonPrimitive
-import kotlinx.serialization.json.long
-
-/**
- * JSON Serializer used to write / read [MangaImpl] to / from json
- */
-open class MangaBaseSerializer<T : Manga> : KSerializer<T> {
-    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Manga")
-
-    override fun serialize(encoder: Encoder, value: T) {
-        encoder as JsonEncoder
-        encoder.encodeJsonElement(
-            buildJsonArray {
-                add(value.url)
-                add(value.title)
-                add(value.source)
-                add(value.viewer_flags)
-                add(value.chapter_flags)
-            },
-        )
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    override fun deserialize(decoder: Decoder): T {
-        // make a manga impl and cast as T so that the serializer accepts it
-        return MangaImpl().apply {
-            decoder as JsonDecoder
-            val array = decoder.decodeJsonElement().jsonArray
-            url = array[0].jsonPrimitive.content
-            title = array[1].jsonPrimitive.content
-            source = array[2].jsonPrimitive.long
-            viewer_flags = array[3].jsonPrimitive.int
-            chapter_flags = array[4].jsonPrimitive.int
-        } as T
-    }
-}
-
-// Allow for serialization of a manga and manga impl
-object MangaTypeSerializer : MangaBaseSerializer<Manga>()
-
-object MangaImplTypeSerializer : MangaBaseSerializer<MangaImpl>()

+ 0 - 68
app/src/main/java/eu/kanade/tachiyomi/data/backup/legacy/serializer/TrackTypeSerializer.kt

@@ -1,68 +0,0 @@
-package eu.kanade.tachiyomi.data.backup.legacy.serializer
-
-import eu.kanade.tachiyomi.data.database.models.Track
-import eu.kanade.tachiyomi.data.database.models.TrackImpl
-import kotlinx.serialization.KSerializer
-import kotlinx.serialization.descriptors.SerialDescriptor
-import kotlinx.serialization.descriptors.buildClassSerialDescriptor
-import kotlinx.serialization.encoding.Decoder
-import kotlinx.serialization.encoding.Encoder
-import kotlinx.serialization.json.JsonDecoder
-import kotlinx.serialization.json.JsonEncoder
-import kotlinx.serialization.json.buildJsonObject
-import kotlinx.serialization.json.float
-import kotlinx.serialization.json.int
-import kotlinx.serialization.json.jsonObject
-import kotlinx.serialization.json.jsonPrimitive
-import kotlinx.serialization.json.long
-import kotlinx.serialization.json.put
-
-/**
- * JSON Serializer used to write / read [TrackImpl] to / from json
- */
-open class TrackBaseSerializer<T : Track> : KSerializer<T> {
-    override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Track")
-
-    override fun serialize(encoder: Encoder, value: T) {
-        encoder as JsonEncoder
-        encoder.encodeJsonElement(
-            buildJsonObject {
-                put(TITLE, value.title)
-                put(SYNC, value.sync_id)
-                put(MEDIA, value.media_id)
-                put(LIBRARY, value.library_id)
-                put(LAST_READ, value.last_chapter_read)
-                put(TRACKING_URL, value.tracking_url)
-            },
-        )
-    }
-
-    @Suppress("UNCHECKED_CAST")
-    override fun deserialize(decoder: Decoder): T {
-        // make a track impl and cast as T so that the serializer accepts it
-        return TrackImpl().apply {
-            decoder as JsonDecoder
-            val jsonObject = decoder.decodeJsonElement().jsonObject
-            title = jsonObject[TITLE]!!.jsonPrimitive.content
-            sync_id = jsonObject[SYNC]!!.jsonPrimitive.int
-            media_id = jsonObject[MEDIA]!!.jsonPrimitive.long
-            library_id = jsonObject[LIBRARY]!!.jsonPrimitive.long
-            last_chapter_read = jsonObject[LAST_READ]!!.jsonPrimitive.float
-            tracking_url = jsonObject[TRACKING_URL]!!.jsonPrimitive.content
-        } as T
-    }
-
-    companion object {
-        private const val SYNC = "s"
-        private const val MEDIA = "r"
-        private const val LIBRARY = "ml"
-        private const val TITLE = "t"
-        private const val LAST_READ = "l"
-        private const val TRACKING_URL = "u"
-    }
-}
-
-// Allow for serialization of a track and track impl
-object TrackTypeSerializer : TrackBaseSerializer<Track>()
-
-object TrackImplTypeSerializer : TrackBaseSerializer<TrackImpl>()

+ 0 - 8
app/src/main/java/eu/kanade/tachiyomi/data/database/tables/TrackTable.kt

@@ -29,12 +29,4 @@ object TrackTable {
     const val COL_START_DATE = "start_date"
 
     const val COL_FINISH_DATE = "finish_date"
-
-    val insertFromTempTable: String
-        get() =
-            """
-            |INSERT INTO $TABLE($COL_ID,$COL_MANGA_ID,$COL_SYNC_ID,$COL_MEDIA_ID,$COL_LIBRARY_ID,$COL_TITLE,$COL_LAST_CHAPTER_READ,$COL_TOTAL_CHAPTERS,$COL_STATUS,$COL_SCORE,$COL_TRACKING_URL,$COL_START_DATE,$COL_FINISH_DATE)
-            |SELECT $COL_ID,$COL_MANGA_ID,$COL_SYNC_ID,$COL_MEDIA_ID,$COL_LIBRARY_ID,$COL_TITLE,$COL_LAST_CHAPTER_READ,$COL_TOTAL_CHAPTERS,$COL_STATUS,$COL_SCORE,$COL_TRACKING_URL,$COL_START_DATE,$COL_FINISH_DATE
-            |FROM ${TABLE}_tmp
-            """.trimMargin()
 }

+ 3 - 15
app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt

@@ -22,10 +22,8 @@ import eu.kanade.tachiyomi.R
 import eu.kanade.tachiyomi.data.backup.BackupConst
 import eu.kanade.tachiyomi.data.backup.BackupCreatorJob
 import eu.kanade.tachiyomi.data.backup.BackupRestoreService
-import eu.kanade.tachiyomi.data.backup.ValidatorParseException
 import eu.kanade.tachiyomi.data.backup.full.FullBackupRestoreValidator
 import eu.kanade.tachiyomi.data.backup.full.models.BackupFull
-import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupRestoreValidator
 import eu.kanade.tachiyomi.ui.base.controller.DialogController
 import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe
 import eu.kanade.tachiyomi.util.preference.bindTo
@@ -272,19 +270,9 @@ class SettingsBackupController : SettingsController() {
             val uri: Uri = args.getParcelable(KEY_URI)!!
 
             return try {
-                var type = BackupConst.BACKUP_TYPE_FULL
-                val results = try {
-                    FullBackupRestoreValidator().validate(activity, uri)
-                } catch (_: ValidatorParseException) {
-                    type = BackupConst.BACKUP_TYPE_LEGACY
-                    LegacyBackupRestoreValidator().validate(activity, uri)
-                }
+                val results = FullBackupRestoreValidator().validate(activity, uri)
 
-                var message = if (type == BackupConst.BACKUP_TYPE_FULL) {
-                    activity.getString(R.string.backup_restore_content_full)
-                } else {
-                    activity.getString(R.string.backup_restore_content)
-                }
+                var message = activity.getString(R.string.backup_restore_content_full)
                 if (results.missingSources.isNotEmpty()) {
                     message += "\n\n${activity.getString(R.string.backup_restore_missing_sources)}\n${results.missingSources.joinToString("\n") { "- $it" }}"
                 }
@@ -296,7 +284,7 @@ class SettingsBackupController : SettingsController() {
                     .setTitle(R.string.pref_restore_backup)
                     .setMessage(message)
                     .setPositiveButton(R.string.action_restore) { _, _ ->
-                        BackupRestoreService.start(activity, uri, type)
+                        BackupRestoreService.start(activity, uri)
                     }
                     .create()
             } catch (e: Exception) {

+ 0 - 3
app/src/main/res/values/strings.xml

@@ -436,16 +436,13 @@
     <string name="pref_backup_service_category">Automatic backups</string>
     <string name="pref_backup_interval">Backup frequency</string>
     <string name="pref_backup_slots">Maximum backups</string>
-    <string name="source_not_found_name">Source not found: %1$s</string>
     <string name="tracker_not_logged_in">Not logged in: %1$s</string>
     <string name="backup_restore_invalid_uri">Error: empty URI</string>
     <string name="backup_created">Backup created</string>
     <string name="invalid_backup_file">Invalid backup file</string>
-    <string name="invalid_backup_file_missing_data">File is missing data.</string>
     <string name="invalid_backup_file_missing_manga">Backup does not contain any manga.</string>
     <string name="backup_restore_missing_sources">Missing sources:</string>
     <string name="backup_restore_missing_trackers">Trackers not logged into:</string>
-    <string name="backup_restore_content">Restore uses sources to fetch data, carrier costs may apply.\n\nMake sure you have installed all necessary extensions and are logged in to sources and tracking services before restoring.</string>
     <string name="backup_restore_content_full">Data from the backup file will be restored.\n\nYou will need to install any missing extensions and log in to tracking services afterwards to use them.</string>
     <string name="restore_completed">Restore completed</string>
     <string name="restore_duration">%02d min, %02d sec</string>