Change extension repo to extension store and add support for newer extension index format (#3349)
This commit is contained in:
@@ -6,13 +6,13 @@ import com.hippo.unifile.UniFile
|
||||
import eu.kanade.tachiyomi.BuildConfig
|
||||
import eu.kanade.tachiyomi.data.backup.BackupFileValidator
|
||||
import eu.kanade.tachiyomi.data.backup.create.creators.CategoriesBackupCreator
|
||||
import eu.kanade.tachiyomi.data.backup.create.creators.ExtensionRepoBackupCreator
|
||||
import eu.kanade.tachiyomi.data.backup.create.creators.ExtensionStoresBackupCreator
|
||||
import eu.kanade.tachiyomi.data.backup.create.creators.MangaBackupCreator
|
||||
import eu.kanade.tachiyomi.data.backup.create.creators.PreferenceBackupCreator
|
||||
import eu.kanade.tachiyomi.data.backup.create.creators.SourcesBackupCreator
|
||||
import eu.kanade.tachiyomi.data.backup.models.Backup
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupSource
|
||||
@@ -49,7 +49,7 @@ class BackupCreator(
|
||||
private val categoriesBackupCreator: CategoriesBackupCreator = CategoriesBackupCreator(),
|
||||
private val mangaBackupCreator: MangaBackupCreator = MangaBackupCreator(),
|
||||
private val preferenceBackupCreator: PreferenceBackupCreator = PreferenceBackupCreator(),
|
||||
private val extensionRepoBackupCreator: ExtensionRepoBackupCreator = ExtensionRepoBackupCreator(),
|
||||
private val extensionStoresBackupCreator: ExtensionStoresBackupCreator = ExtensionStoresBackupCreator(),
|
||||
private val sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(),
|
||||
) {
|
||||
|
||||
@@ -85,7 +85,7 @@ class BackupCreator(
|
||||
backupCategories = backupCategories(options),
|
||||
backupSources = backupSources(backupManga),
|
||||
backupPreferences = backupAppPreferences(options),
|
||||
backupExtensionRepo = backupExtensionRepos(options),
|
||||
backupExtensionStores = backupExtensionStores(options),
|
||||
backupSourcePreferences = backupSourcePreferences(options),
|
||||
)
|
||||
|
||||
@@ -141,10 +141,10 @@ class BackupCreator(
|
||||
return preferenceBackupCreator.createApp(includePrivatePreferences = options.privateSettings)
|
||||
}
|
||||
|
||||
private suspend fun backupExtensionRepos(options: BackupOptions): List<BackupExtensionRepos> {
|
||||
if (!options.extensionRepoSettings) return emptyList()
|
||||
private suspend fun backupExtensionStores(options: BackupOptions): List<BackupExtensionStore> {
|
||||
if (!options.extensionStores) return emptyList()
|
||||
|
||||
return extensionRepoBackupCreator()
|
||||
return extensionStoresBackupCreator()
|
||||
}
|
||||
|
||||
private fun backupSourcePreferences(options: BackupOptions): List<BackupSourcePreferences> {
|
||||
|
||||
@@ -12,7 +12,7 @@ data class BackupOptions(
|
||||
val history: Boolean = true,
|
||||
val readEntries: Boolean = true,
|
||||
val appSettings: Boolean = true,
|
||||
val extensionRepoSettings: Boolean = true,
|
||||
val extensionStores: Boolean = true,
|
||||
val sourceSettings: Boolean = true,
|
||||
val privateSettings: Boolean = false,
|
||||
) {
|
||||
@@ -25,12 +25,12 @@ data class BackupOptions(
|
||||
history,
|
||||
readEntries,
|
||||
appSettings,
|
||||
extensionRepoSettings,
|
||||
extensionStores,
|
||||
sourceSettings,
|
||||
privateSettings,
|
||||
)
|
||||
|
||||
fun canCreate() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings
|
||||
fun canCreate() = libraryEntries || categories || appSettings || extensionStores || sourceSettings
|
||||
|
||||
companion object {
|
||||
val libraryOptions = persistentListOf(
|
||||
@@ -77,9 +77,9 @@ data class BackupOptions(
|
||||
setter = { options, enabled -> options.copy(appSettings = enabled) },
|
||||
),
|
||||
Entry(
|
||||
label = MR.strings.extensionRepo_settings,
|
||||
getter = BackupOptions::extensionRepoSettings,
|
||||
setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) },
|
||||
label = MR.strings.extensionStores,
|
||||
getter = BackupOptions::extensionStores,
|
||||
setter = { options, enabled -> options.copy(extensionStores = enabled) },
|
||||
),
|
||||
Entry(
|
||||
label = MR.strings.source_settings,
|
||||
@@ -102,7 +102,7 @@ data class BackupOptions(
|
||||
history = array[4],
|
||||
readEntries = array[5],
|
||||
appSettings = array[6],
|
||||
extensionRepoSettings = array[7],
|
||||
extensionStores = array[7],
|
||||
sourceSettings = array[8],
|
||||
privateSettings = array[9],
|
||||
)
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||
import eu.kanade.tachiyomi.data.backup.models.backupExtensionReposMapper
|
||||
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionRepoBackupCreator(
|
||||
private val getExtensionRepos: GetExtensionRepo = Injekt.get(),
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): List<BackupExtensionRepos> {
|
||||
return getExtensionRepos.getAll()
|
||||
.map(backupExtensionReposMapper)
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
package eu.kanade.tachiyomi.data.backup.create.creators
|
||||
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
||||
import eu.kanade.tachiyomi.data.backup.models.backupExtensionStoreMapper
|
||||
import mihon.domain.extension.interactor.GetExtensionStores
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionStoresBackupCreator(
|
||||
private val getExtensionStores: GetExtensionStores = Injekt.get(),
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(): List<BackupExtensionStore> {
|
||||
return getExtensionStores.get()
|
||||
.map(backupExtensionStoreMapper)
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,5 @@ data class Backup(
|
||||
@ProtoNumber(101) var backupSources: List<BackupSource> = emptyList(),
|
||||
@ProtoNumber(104) var backupPreferences: List<BackupPreference> = emptyList(),
|
||||
@ProtoNumber(105) var backupSourcePreferences: List<BackupSourcePreferences> = emptyList(),
|
||||
@ProtoNumber(106) var backupExtensionRepo: List<BackupExtensionRepos> = emptyList(),
|
||||
@ProtoNumber(106) var backupExtensionStores: List<BackupExtensionStore> = emptyList(),
|
||||
)
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.backup.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import mihon.domain.extensionrepo.model.ExtensionRepo
|
||||
|
||||
@Serializable
|
||||
class BackupExtensionRepos(
|
||||
@ProtoNumber(1) var baseUrl: String,
|
||||
@ProtoNumber(2) var name: String,
|
||||
@ProtoNumber(3) var shortName: String?,
|
||||
@ProtoNumber(4) var website: String,
|
||||
@ProtoNumber(5) var signingKeyFingerprint: String,
|
||||
)
|
||||
|
||||
val backupExtensionReposMapper = { repo: ExtensionRepo ->
|
||||
BackupExtensionRepos(
|
||||
baseUrl = repo.baseUrl,
|
||||
name = repo.name,
|
||||
shortName = repo.shortName,
|
||||
website = repo.website,
|
||||
signingKeyFingerprint = repo.signingKeyFingerprint,
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package eu.kanade.tachiyomi.data.backup.models
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import mihon.domain.extension.model.ExtensionStore
|
||||
|
||||
@Serializable
|
||||
class BackupExtensionStore(
|
||||
@ProtoNumber(1) var indexUrl: String,
|
||||
@ProtoNumber(2) var name: String,
|
||||
@ProtoNumber(3) var badgeLabel: String?,
|
||||
@ProtoNumber(5) var signingKey: String,
|
||||
@ProtoNumber(4) var contactWebsite: String,
|
||||
@ProtoNumber(6) var contactDiscord: String?,
|
||||
@ProtoNumber(7) var isLegacy: Boolean?,
|
||||
)
|
||||
|
||||
val backupExtensionStoreMapper = { store: ExtensionStore ->
|
||||
BackupExtensionStore(
|
||||
indexUrl = store.indexUrl,
|
||||
name = store.name,
|
||||
badgeLabel = store.badgeLabel,
|
||||
signingKey = store.signingKey,
|
||||
contactWebsite = store.contact.website,
|
||||
contactDiscord = store.contact.discord,
|
||||
isLegacy = store.isLegacy,
|
||||
)
|
||||
}
|
||||
@@ -5,12 +5,12 @@ import android.net.Uri
|
||||
import eu.kanade.tachiyomi.data.backup.BackupDecoder
|
||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupCategory
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupManga
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupSourcePreferences
|
||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.CategoriesRestorer
|
||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.ExtensionRepoRestorer
|
||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.ExtensionStoreRestorer
|
||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.MangaRestorer
|
||||
import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer
|
||||
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
|
||||
@@ -32,7 +32,7 @@ class BackupRestorer(
|
||||
|
||||
private val categoriesRestorer: CategoriesRestorer = CategoriesRestorer(),
|
||||
private val preferenceRestorer: PreferenceRestorer = PreferenceRestorer(context),
|
||||
private val extensionRepoRestorer: ExtensionRepoRestorer = ExtensionRepoRestorer(),
|
||||
private val extensionStoreRestorer: ExtensionStoreRestorer = ExtensionStoreRestorer(),
|
||||
private val mangaRestorer: MangaRestorer = MangaRestorer(),
|
||||
) {
|
||||
|
||||
@@ -79,8 +79,8 @@ class BackupRestorer(
|
||||
if (options.appSettings) {
|
||||
restoreAmount += 1
|
||||
}
|
||||
if (options.extensionRepoSettings) {
|
||||
restoreAmount += backup.backupExtensionRepo.size
|
||||
if (options.extensionStores) {
|
||||
restoreAmount += backup.backupExtensionStores.size
|
||||
}
|
||||
if (options.sourceSettings) {
|
||||
restoreAmount += 1
|
||||
@@ -99,8 +99,8 @@ class BackupRestorer(
|
||||
if (options.libraryEntries) {
|
||||
restoreManga(backup.backupManga, if (options.categories) backup.backupCategories else emptyList())
|
||||
}
|
||||
if (options.extensionRepoSettings) {
|
||||
restoreExtensionRepos(backup.backupExtensionRepo)
|
||||
if (options.extensionStores) {
|
||||
restoreExtensionStores(backup.backupExtensionStores)
|
||||
}
|
||||
|
||||
// TODO: optionally trigger online library + tracker update
|
||||
@@ -172,22 +172,22 @@ class BackupRestorer(
|
||||
)
|
||||
}
|
||||
|
||||
private fun CoroutineScope.restoreExtensionRepos(
|
||||
backupExtensionRepo: List<BackupExtensionRepos>,
|
||||
private fun CoroutineScope.restoreExtensionStores(
|
||||
backupExtensionStores: List<BackupExtensionStore>,
|
||||
) = launch {
|
||||
backupExtensionRepo
|
||||
backupExtensionStores
|
||||
.forEach {
|
||||
ensureActive()
|
||||
|
||||
try {
|
||||
extensionRepoRestorer(it)
|
||||
extensionStoreRestorer(it)
|
||||
} catch (e: Exception) {
|
||||
errors.add(Date() to "Error Adding Repo: ${it.name} : ${e.message}")
|
||||
}
|
||||
|
||||
restoreProgress += 1
|
||||
notifier.showRestoreProgress(
|
||||
context.stringResource(MR.strings.extensionRepo_settings),
|
||||
context.stringResource(MR.strings.extensionStores),
|
||||
restoreProgress,
|
||||
restoreAmount,
|
||||
isSync,
|
||||
|
||||
@@ -8,7 +8,7 @@ data class RestoreOptions(
|
||||
val libraryEntries: Boolean = true,
|
||||
val categories: Boolean = true,
|
||||
val appSettings: Boolean = true,
|
||||
val extensionRepoSettings: Boolean = true,
|
||||
val extensionStores: Boolean = true,
|
||||
val sourceSettings: Boolean = true,
|
||||
) {
|
||||
|
||||
@@ -16,11 +16,11 @@ data class RestoreOptions(
|
||||
libraryEntries,
|
||||
categories,
|
||||
appSettings,
|
||||
extensionRepoSettings,
|
||||
extensionStores,
|
||||
sourceSettings,
|
||||
)
|
||||
|
||||
fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings
|
||||
fun canRestore() = libraryEntries || categories || appSettings || extensionStores || sourceSettings
|
||||
|
||||
companion object {
|
||||
val options = persistentListOf(
|
||||
@@ -40,9 +40,9 @@ data class RestoreOptions(
|
||||
setter = { options, enabled -> options.copy(appSettings = enabled) },
|
||||
),
|
||||
Entry(
|
||||
label = MR.strings.extensionRepo_settings,
|
||||
getter = RestoreOptions::extensionRepoSettings,
|
||||
setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) },
|
||||
label = MR.strings.extensionStores,
|
||||
getter = RestoreOptions::extensionStores,
|
||||
setter = { options, enabled -> options.copy(extensionStores = enabled) },
|
||||
),
|
||||
Entry(
|
||||
label = MR.strings.source_settings,
|
||||
@@ -55,7 +55,7 @@ data class RestoreOptions(
|
||||
libraryEntries = array[0],
|
||||
categories = array[1],
|
||||
appSettings = array[2],
|
||||
extensionRepoSettings = array[3],
|
||||
extensionStores = array[3],
|
||||
sourceSettings = array[4],
|
||||
)
|
||||
}
|
||||
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionRepos
|
||||
import mihon.domain.extensionrepo.interactor.GetExtensionRepo
|
||||
import tachiyomi.data.Database
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionRepoRestorer(
|
||||
private val database: Database = Injekt.get(),
|
||||
private val getExtensionRepos: GetExtensionRepo = Injekt.get(),
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
backupRepo: BackupExtensionRepos,
|
||||
) {
|
||||
val dbRepos = getExtensionRepos.getAll()
|
||||
val existingReposBySHA = dbRepos.associateBy { it.signingKeyFingerprint }
|
||||
val existingReposByUrl = dbRepos.associateBy { it.baseUrl }
|
||||
|
||||
val urlExists = existingReposByUrl[backupRepo.baseUrl]
|
||||
val shaExists = existingReposBySHA[backupRepo.signingKeyFingerprint]
|
||||
|
||||
if (urlExists != null && urlExists.signingKeyFingerprint != backupRepo.signingKeyFingerprint) {
|
||||
error("Already Exists with different signing key fingerprint")
|
||||
} else if (shaExists != null) {
|
||||
error("${shaExists.name} has the same signing key fingerprint")
|
||||
} else {
|
||||
database.extension_reposQueries.insert(
|
||||
backupRepo.baseUrl,
|
||||
backupRepo.name,
|
||||
backupRepo.shortName,
|
||||
backupRepo.website,
|
||||
backupRepo.signingKeyFingerprint,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package eu.kanade.tachiyomi.data.backup.restore.restorers
|
||||
|
||||
import eu.kanade.tachiyomi.data.backup.models.BackupExtensionStore
|
||||
import tachiyomi.data.Database
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
|
||||
class ExtensionStoreRestorer(
|
||||
private val database: Database = Injekt.get(),
|
||||
) {
|
||||
|
||||
suspend operator fun invoke(
|
||||
backupStore: BackupExtensionStore,
|
||||
) {
|
||||
database.extension_storeQueries.upsert(
|
||||
indexUrl = backupStore.indexUrl,
|
||||
name = backupStore.name,
|
||||
badgeLabel = backupStore.badgeLabel ?: backupStore.name,
|
||||
signingKey = backupStore.signingKey,
|
||||
contactWebsite = backupStore.contactWebsite,
|
||||
contactDiscord = backupStore.contactDiscord,
|
||||
isLegacy = backupStore.isLegacy ?: true,
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user