备份问题

This commit is contained in:
HapeLee
2026-05-30 01:16:23 +08:00
parent b408ba580a
commit f8f19f7379
4 changed files with 47 additions and 38 deletions
@@ -9,7 +9,9 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.LocalConfig
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.BackupRestoreLock
import io.legado.app.help.storage.Restore
import io.legado.app.lib.webdav.Authorization
import io.legado.app.lib.webdav.WebDav
@@ -122,10 +124,13 @@ object AppWebDav {
suspend fun restoreWebDav(name: String) {
authorization?.let {
val webDav = WebDav(rootWebDavUrl + name, it)
webDav.downloadTo(Backup.zipFilePath, true)
FileUtils.delete(Backup.backupPath)
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
Restore.restoreLocked(Backup.backupPath)
BackupRestoreLock.withLock {
webDav.downloadTo(Backup.zipFilePath, true)
FileUtils.delete(Backup.backupPath)
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
Restore.restoreUnzipped(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis()
}
}
}
@@ -8,7 +8,9 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookProgress
import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig
import io.legado.app.help.config.LocalConfig
import io.legado.app.help.storage.Backup
import io.legado.app.help.storage.BackupRestoreLock
import io.legado.app.help.storage.Restore
import io.legado.app.lib.webdav.Authorization
import io.legado.app.lib.webdav.WebDav
@@ -137,10 +139,13 @@ class WebDavManager(
val auth = requireAuthorization()
val rootUrl = buildRootUrl(configFlow.value)
val webDav = WebDav(rootUrl + name, auth)
webDav.downloadTo(Backup.zipFilePath, true)
FileUtils.delete(Backup.backupPath)
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
Restore.restoreLocked(Backup.backupPath)
BackupRestoreLock.withLock {
webDav.downloadTo(Backup.zipFilePath, true)
FileUtils.delete(Backup.backupPath)
ZipUtils.unZipToPath(File(Backup.zipFilePath), Backup.backupPath)
Restore.restoreUnzipped(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis()
}
}
suspend fun hasBackUp(backUpName: String): Boolean {
@@ -34,8 +34,6 @@ import io.legado.app.utils.writeToOutputStream
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.coroutines.ensureActive
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import splitties.init.appCtx
import java.io.File
@@ -58,8 +56,6 @@ object Backup {
private const val TAG = "Backup"
private val mutex = Mutex()
private val backupFileNames by lazy {
arrayOf(
"bookshelf.json",
@@ -107,7 +103,7 @@ object Backup {
fun autoBack(context: Context) {
if (shouldBackup()) {
Coroutine.async {
mutex.withLock {
BackupRestoreLock.withLock {
if (shouldBackup()) {
val backupZipFileName = getNowZipFileName()
if (!AppWebDav.hasBackUp(backupZipFileName)) {
@@ -124,7 +120,7 @@ object Backup {
}
suspend fun backupLocked(context: Context, path: String?, mode: String = "both") {
mutex.withLock {
BackupRestoreLock.withLock {
withContext(IO) {
backup(context, path, mode)
}
@@ -55,8 +55,6 @@ import io.legado.app.utils.openInputStream
import io.legado.app.utils.toastOnUi
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.delay
import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock
import kotlinx.coroutines.withContext
import org.koin.core.component.KoinComponent
import org.koin.core.component.inject
@@ -70,40 +68,45 @@ import java.io.FileInputStream
object Restore : KoinComponent {
private val settingsRepository: SettingsRepository by inject()
private val mutex = Mutex()
private const val TAG = "Restore"
suspend fun restore(context: Context, uri: Uri) {
LogUtils.d(TAG, "开始恢复备份 uri:$uri")
kotlin.runCatching {
FileUtils.delete(Backup.backupPath)
if (uri.isContentScheme()) {
DocumentFile.fromSingleUri(context, uri)!!.openInputStream()!!.use {
ZipUtils.unZipToPath(it, Backup.backupPath)
BackupRestoreLock.withLock {
LogUtils.d(TAG, "开始恢复备份 uri:$uri")
val unzipResult = kotlin.runCatching {
FileUtils.delete(Backup.backupPath)
if (uri.isContentScheme()) {
DocumentFile.fromSingleUri(context, uri)!!.openInputStream()!!.use {
ZipUtils.unZipToPath(it, Backup.backupPath)
}
} else {
ZipUtils.unZipToPath(File(uri.path!!), Backup.backupPath)
}
}.onFailure {
AppLog.put("复制解压文件出错\n${it.localizedMessage}", it)
}
if (unzipResult.isSuccess) {
kotlin.runCatching {
restoreUnzipped(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis()
}.onFailure {
appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}")
AppLog.put("恢复备份出错\n${it.localizedMessage}", it)
}
} else {
ZipUtils.unZipToPath(File(uri.path!!), Backup.backupPath)
}
}.onFailure {
AppLog.put("复制解压文件出错\n${it.localizedMessage}", it)
return
}
kotlin.runCatching {
restoreLocked(Backup.backupPath)
LocalConfig.lastBackup = System.currentTimeMillis()
}.onFailure {
appCtx.toastOnUi("恢复备份出错\n${it.localizedMessage}")
AppLog.put("恢复备份出错\n${it.localizedMessage}", it)
}
}
suspend fun restoreLocked(path: String) {
mutex.withLock {
restore(path)
BackupRestoreLock.withLock {
restoreUnzipped(path)
}
}
internal suspend fun restoreUnzipped(path: String) {
restore(path)
}
private suspend fun restore(path: String) {
val aes = BackupAES()
fileToListT<Book>(path, "bookshelf.json")?.let {