|
|
@@ -8,6 +8,7 @@ import io.legado.app.constant.PreferKey
|
|
|
import io.legado.app.data.appDb
|
|
|
import io.legado.app.help.AppWebDav
|
|
|
import io.legado.app.help.DirectLinkUpload
|
|
|
+import io.legado.app.help.config.AppConfig
|
|
|
import io.legado.app.help.config.LocalConfig
|
|
|
import io.legado.app.help.config.ReadBookConfig
|
|
|
import io.legado.app.help.config.ThemeConfig
|
|
|
@@ -18,7 +19,10 @@ import kotlinx.coroutines.ensureActive
|
|
|
import kotlinx.coroutines.withContext
|
|
|
import splitties.init.appCtx
|
|
|
import java.io.File
|
|
|
+import java.io.FileInputStream
|
|
|
import java.io.FileOutputStream
|
|
|
+import java.text.SimpleDateFormat
|
|
|
+import java.util.*
|
|
|
import java.util.concurrent.TimeUnit
|
|
|
|
|
|
/**
|
|
|
@@ -29,8 +33,9 @@ object Backup {
|
|
|
val backupPath: String by lazy {
|
|
|
appCtx.filesDir.getFile("backup").createFolderIfNotExist().absolutePath
|
|
|
}
|
|
|
+ val zipFilePath = "${appCtx.externalFiles.absolutePath}${File.separator}backup.zip"
|
|
|
|
|
|
- val backupFileNames by lazy {
|
|
|
+ private val backupFileNames by lazy {
|
|
|
arrayOf(
|
|
|
"bookshelf.json",
|
|
|
"bookmark.json",
|
|
|
@@ -55,12 +60,24 @@ object Backup {
|
|
|
)
|
|
|
}
|
|
|
|
|
|
+ private fun getNowZipFileName(): String {
|
|
|
+ val backupDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
|
|
+ .format(Date(System.currentTimeMillis()))
|
|
|
+ val deviceName = AppConfig.webDavDeviceName
|
|
|
+ return if (deviceName?.isNotBlank() == true) {
|
|
|
+ "backup${backupDate}-${deviceName}.zip"
|
|
|
+ } else {
|
|
|
+ "backup${backupDate}.zip"
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
fun autoBack(context: Context) {
|
|
|
val lastBackup = LocalConfig.lastBackup
|
|
|
if (lastBackup + TimeUnit.DAYS.toMillis(1) < System.currentTimeMillis()) {
|
|
|
Coroutine.async {
|
|
|
- if (!AppWebDav.hasBackUp()) {
|
|
|
- backup(context, context.getPrefString(PreferKey.backupPath), true)
|
|
|
+ val backupZipFileName = getNowZipFileName()
|
|
|
+ if (!AppWebDav.hasBackUp(backupZipFileName)) {
|
|
|
+ backup(context, context.getPrefString(PreferKey.backupPath))
|
|
|
} else {
|
|
|
LocalConfig.lastBackup = System.currentTimeMillis()
|
|
|
}
|
|
|
@@ -70,7 +87,7 @@ object Backup {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- suspend fun backup(context: Context, path: String?, isAuto: Boolean = false) {
|
|
|
+ suspend fun backup(context: Context, path: String?) {
|
|
|
LocalConfig.lastBackup = System.currentTimeMillis()
|
|
|
withContext(IO) {
|
|
|
FileUtils.delete(backupPath)
|
|
|
@@ -124,18 +141,26 @@ object Backup {
|
|
|
edit.commit()
|
|
|
}
|
|
|
ensureActive()
|
|
|
- when {
|
|
|
- path.isNullOrBlank() -> {
|
|
|
- copyBackup(context.getExternalFilesDir(null)!!, false)
|
|
|
- }
|
|
|
- path.isContentScheme() -> {
|
|
|
- copyBackup(context, Uri.parse(path), isAuto)
|
|
|
- }
|
|
|
- else -> {
|
|
|
- copyBackup(File(path), isAuto)
|
|
|
+ val zipFileName = getNowZipFileName()
|
|
|
+ val paths = arrayListOf(*backupFileNames)
|
|
|
+ for (i in 0 until paths.size) {
|
|
|
+ paths[i] = backupPath + File.separator + paths[i]
|
|
|
+ }
|
|
|
+ FileUtils.delete(zipFilePath)
|
|
|
+ if (ZipUtils.zipFiles(paths, zipFilePath)) {
|
|
|
+ when {
|
|
|
+ path.isNullOrBlank() -> {
|
|
|
+ copyBackup(context.getExternalFilesDir(null)!!, zipFileName)
|
|
|
+ }
|
|
|
+ path.isContentScheme() -> {
|
|
|
+ copyBackup(context, Uri.parse(path), zipFileName)
|
|
|
+ }
|
|
|
+ else -> {
|
|
|
+ copyBackup(File(path), zipFileName)
|
|
|
+ }
|
|
|
}
|
|
|
+ AppWebDav.backUpWebDav(zipFileName)
|
|
|
}
|
|
|
- AppWebDav.backUpWebDav(backupPath)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@@ -149,40 +174,23 @@ object Backup {
|
|
|
}
|
|
|
|
|
|
@Throws(Exception::class)
|
|
|
- private fun copyBackup(context: Context, uri: Uri, isAuto: Boolean) {
|
|
|
+ private fun copyBackup(context: Context, uri: Uri, fileName: String) {
|
|
|
DocumentFile.fromTreeUri(context, uri)?.let { treeDoc ->
|
|
|
- for (fileName in backupFileNames) {
|
|
|
- val file = File(backupPath + File.separator + fileName)
|
|
|
- if (file.exists()) {
|
|
|
- if (isAuto) {
|
|
|
- treeDoc.findFile("auto")?.findFile(fileName)?.delete()
|
|
|
- DocumentUtils.createFileIfNotExist(
|
|
|
- treeDoc,
|
|
|
- fileName,
|
|
|
- subDirs = arrayOf("auto")
|
|
|
- )?.writeBytes(context, file.readBytes())
|
|
|
- } else {
|
|
|
- treeDoc.findFile(fileName)?.delete()
|
|
|
- treeDoc.createFile("", fileName)
|
|
|
- ?.writeBytes(context, file.readBytes())
|
|
|
- }
|
|
|
+ treeDoc.findFile(fileName)?.delete()
|
|
|
+ treeDoc.createFile("", fileName)?.openOutputStream()?.use { outputS ->
|
|
|
+ FileInputStream(File(zipFilePath)).use { inputS ->
|
|
|
+ inputS.copyTo(outputS)
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@Throws(Exception::class)
|
|
|
- private fun copyBackup(rootFile: File, isAuto: Boolean) {
|
|
|
- for (fileName in backupFileNames) {
|
|
|
- val file = File(backupPath + File.separator + fileName)
|
|
|
- if (file.exists()) {
|
|
|
- file.copyTo(
|
|
|
- if (isAuto) {
|
|
|
- FileUtils.createFileIfNotExist(rootFile, "auto", fileName)
|
|
|
- } else {
|
|
|
- FileUtils.createFileIfNotExist(rootFile, fileName)
|
|
|
- }, true
|
|
|
- )
|
|
|
+ private fun copyBackup(rootFile: File, fileName: String) {
|
|
|
+ FileInputStream(File(zipFilePath)).use { inputS ->
|
|
|
+ val file = FileUtils.createFileIfNotExist(rootFile, fileName)
|
|
|
+ FileOutputStream(file).use { outputS ->
|
|
|
+ inputS.copyTo(outputS)
|
|
|
}
|
|
|
}
|
|
|
}
|