From 5910a51eb4c9fda5e0f69a3367e2efc332567081 Mon Sep 17 00:00:00 2001 From: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Date: Wed, 7 Oct 2026 09:04:41 +0600 Subject: [PATCH] Keep the names of uninstalled sources across backup restores --- .../tachiyomi/data/backup/BackupFileValidator.kt | 10 +++++----- .../data/backup/restore/BackupRestorer.kt | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt index 5bae34de6..2a2bd6739 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupFileValidator.kt @@ -27,12 +27,12 @@ class BackupFileValidator( val sources = backup.backupSources.associate { it.sourceId to it.name } val missingSources = sources .filterKeys { sourceManager.get(it) == null } - .values.map { - val id = it.toLongOrNull() - if (id == null) { - it - } else { + .map { (id, name) -> + // Some backups store the id as the name, and sources without a stub were backed up with no name + if (name.isBlank() || name.toLongOrNull() != null) { sourceManager.getOrStub(id).toString() + } else { + name } } .distinct() diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt index 5de4c5eb9..d4e36afff 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/restore/BackupRestorer.kt @@ -11,6 +11,7 @@ import eu.kanade.tachiyomi.data.backup.models.BackupCategory 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 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.ExtensionStoreRestorer @@ -26,6 +27,8 @@ import kotlinx.coroutines.launch import logcat.LogPriority import tachiyomi.core.common.i18n.stringResource import tachiyomi.core.common.util.system.logcat +import tachiyomi.domain.source.repository.StubSourceRepository +import tachiyomi.domain.source.service.SourceManager import tachiyomi.i18n.MR import java.io.File import java.text.SimpleDateFormat @@ -48,6 +51,8 @@ class BackupRestorer( private val extensionStoreRestorer: ExtensionStoreRestorer, private val mangaRestorer: MangaRestorer, private val backupDecoder: BackupDecoder, + private val sourceManager: SourceManager, + private val stubSourceRepository: StubSourceRepository, ) { @AssistedFactory @@ -99,6 +104,7 @@ class BackupRestorer( sourceMapping = backupMaps.associate { it.sourceId to it.name } if (options.libraryEntries) { + restoreSourceNames(backupMaps) restoreAmount += backup.backupManga.size } if (options.categories) { @@ -145,6 +151,16 @@ class BackupRestorer( } } + // Without a stub, a source that isn't installed has no name for the next backup to write + private suspend fun restoreSourceNames(backupSources: List) { + backupSources + .filter { it.name.isNotBlank() } + .filter { + sourceManager.get(it.sourceId) == null && stubSourceRepository.getStubSource(it.sourceId) == null + } + .forEach { stubSourceRepository.upsertStubSource(it.sourceId, lang = "", name = it.name) } + } + private fun CoroutineScope.restoreCategories(backupCategories: List) = launch { ensureActive() categoriesRestorer(backupCategories)