Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for Backup and Restore of Extension Repos #1057

Merged
merged 8 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +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.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.BackupManga
import eu.kanade.tachiyomi.data.backup.models.BackupPreference
import eu.kanade.tachiyomi.data.backup.models.BackupSource
Expand Down Expand Up @@ -45,6 +47,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 sourcesBackupCreator: SourcesBackupCreator = SourcesBackupCreator(),
) {

Expand Down Expand Up @@ -78,6 +81,7 @@ class BackupCreator(
backupCategories = backupCategories(options),
backupSources = backupSources(backupManga),
backupPreferences = backupAppPreferences(options),
backupExtensionRepo = backupExtensionRepos(options),
Animeboynz marked this conversation as resolved.
Show resolved Hide resolved
backupSourcePreferences = backupSourcePreferences(options),
)

Expand Down Expand Up @@ -133,6 +137,12 @@ class BackupCreator(
return preferenceBackupCreator.createApp(includePrivatePreferences = options.privateSettings)
}

private suspend fun backupExtensionRepos(options: BackupOptions): List<BackupExtensionRepos> {
if (!options.extensionRepoSettings) return emptyList()

return extensionRepoBackupCreator()
}

private fun backupSourcePreferences(options: BackupOptions): List<BackupSourcePreferences> {
if (!options.sourceSettings) return emptyList()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ data class BackupOptions(
val tracking: Boolean = true,
val history: Boolean = true,
val appSettings: Boolean = true,
val extensionRepoSettings: Boolean = true,
val sourceSettings: Boolean = true,
val privateSettings: Boolean = false,
) {
Expand All @@ -22,11 +23,12 @@ data class BackupOptions(
tracking,
history,
appSettings,
extensionRepoSettings,
sourceSettings,
privateSettings,
)

fun canCreate() = libraryEntries || categories || appSettings || sourceSettings
fun canCreate() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings

companion object {
val libraryOptions = persistentListOf(
Expand Down Expand Up @@ -66,6 +68,11 @@ data class BackupOptions(
getter = BackupOptions::appSettings,
setter = { options, enabled -> options.copy(appSettings = enabled) },
),
Entry(
label = MR.strings.extensionRepo_settings,
getter = BackupOptions::extensionRepoSettings,
setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) },
),
Animeboynz marked this conversation as resolved.
Show resolved Hide resolved
Entry(
label = MR.strings.source_settings,
getter = BackupOptions::sourceSettings,
Expand All @@ -86,8 +93,9 @@ data class BackupOptions(
tracking = array[3],
history = array[4],
appSettings = array[5],
sourceSettings = array[6],
privateSettings = array[7],
extensionRepoSettings = array[6],
sourceSettings = array[7],
privateSettings = array[8],
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eu.kanade.tachiyomi.data.backup.models
import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber

@Suppress("MagicNumber")
@Serializable
data class Backup(
@ProtoNumber(1) val backupManga: List<BackupManga>,
Expand All @@ -11,4 +12,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(),
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package eu.kanade.tachiyomi.data.backup.models

import kotlinx.serialization.Serializable
import kotlinx.serialization.protobuf.ProtoNumber
import mihon.domain.extensionrepo.model.ExtensionRepo

@Suppress("MagicNumber")
@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,
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +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.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.MangaRestorer
import eu.kanade.tachiyomi.data.backup.restore.restorers.PreferenceRestorer
import eu.kanade.tachiyomi.util.system.createFileInCacheDir
Expand All @@ -30,6 +32,7 @@ class BackupRestorer(

private val categoriesRestorer: CategoriesRestorer = CategoriesRestorer(),
private val preferenceRestorer: PreferenceRestorer = PreferenceRestorer(context),
private val extensionRepoRestorer: ExtensionRepoRestorer = ExtensionRepoRestorer(),
private val mangaRestorer: MangaRestorer = MangaRestorer(),
) {

Expand Down Expand Up @@ -76,6 +79,9 @@ class BackupRestorer(
if (options.appSettings) {
restoreAmount += 1
}
if (options.extensionRepoSettings) {
restoreAmount += backup.backupExtensionRepo.size
}
if (options.sourceSettings) {
restoreAmount += 1
}
Expand All @@ -93,6 +99,9 @@ class BackupRestorer(
if (options.libraryEntries) {
restoreManga(backup.backupManga, if (options.categories) backup.backupCategories else emptyList())
}
if (options.extensionRepoSettings) {
restoreExtensionRepos(backup.backupExtensionRepo)
}

// TODO: optionally trigger online library + tracker update
}
Expand Down Expand Up @@ -157,6 +166,29 @@ class BackupRestorer(
)
}

private fun CoroutineScope.restoreExtensionRepos(
backupExtensionRepo: List<BackupExtensionRepos>
) = launch {
backupExtensionRepo
.forEach {
ensureActive()

try {
extensionRepoRestorer(it)
} catch (e: Exception) {
errors.add(Date() to "Error Adding Repo: ${it.name} : ${e.message}")
}

restoreProgress += 1
Animeboynz marked this conversation as resolved.
Show resolved Hide resolved
notifier.showRestoreProgress(
context.stringResource(MR.strings.extensionRepo_settings),
restoreProgress,
restoreAmount,
isSync,
)
}
}

private fun writeErrorLog(): File {
try {
if (errors.isNotEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,19 @@ data class RestoreOptions(
val libraryEntries: Boolean = true,
val categories: Boolean = true,
val appSettings: Boolean = true,
val sourceSettings: Boolean = true,
val extensionRepoSettings: Boolean = true,
val sourceSettings: Boolean = true
) {

fun asBooleanArray() = booleanArrayOf(
libraryEntries,
categories,
appSettings,
sourceSettings,
extensionRepoSettings,
sourceSettings
)

fun canRestore() = libraryEntries || categories || appSettings || sourceSettings
fun canRestore() = libraryEntries || categories || appSettings || extensionRepoSettings || sourceSettings

companion object {
val options = persistentListOf(
Expand All @@ -37,6 +39,11 @@ data class RestoreOptions(
getter = RestoreOptions::appSettings,
setter = { options, enabled -> options.copy(appSettings = enabled) },
),
Entry(
label = MR.strings.extensionRepo_settings,
getter = RestoreOptions::extensionRepoSettings,
setter = { options, enabled -> options.copy(extensionRepoSettings = enabled) },
),
Animeboynz marked this conversation as resolved.
Show resolved Hide resolved
Entry(
label = MR.strings.source_settings,
getter = RestoreOptions::sourceSettings,
Expand All @@ -48,7 +55,8 @@ data class RestoreOptions(
libraryEntries = array[0],
categories = array[1],
appSettings = array[2],
sourceSettings = array[3],
extensionRepoSettings = array[3],
sourceSettings = array[4],
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
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.DatabaseHandler
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get

class ExtensionRepoRestorer(
private val handler: DatabaseHandler = 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 {
handler.await {
extension_reposQueries.insert(
backupRepo.baseUrl,
backupRepo.name,
backupRepo.shortName,
backupRepo.website,
backupRepo.signingKeyFingerprint
)
}
}
}
}
1 change: 1 addition & 0 deletions i18n/src/commonMain/moko-resources/base/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,7 @@
<string name="backup_choice">What do you want to backup?</string>
<string name="app_settings">App settings</string>
<string name="source_settings">Source settings</string>
<string name="extensionRepo_settings">Extension Repos</string>
<string name="private_settings">Include sensitive settings (e.g., tracker login tokens)</string>
<string name="creating_backup">Creating backup</string>
<string name="creating_backup_error">Backup failed</string>
Expand Down