From fa4d61eaf0b06ecba803a54d2ee70ac05966c4a6 Mon Sep 17 00:00:00 2001 From: inorichi Date: Sun, 18 Feb 2018 20:14:12 +0100 Subject: [PATCH] Run periodic backups without launching services --- .../data/backup/BackupCreateService.kt | 105 +----------------- .../tachiyomi/data/backup/BackupCreatorJob.kt | 5 +- .../tachiyomi/data/backup/BackupManager.kt | 92 +++++++++++++++ .../ui/setting/SettingsBackupController.kt | 13 +-- 4 files changed, 100 insertions(+), 115 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt index cf3d2535c..0d993a701 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreateService.kt @@ -4,17 +4,8 @@ import android.app.IntentService import android.content.Context import android.content.Intent import android.net.Uri -import com.github.salomonbrys.kotson.set import com.google.gson.JsonArray -import com.google.gson.JsonObject -import com.hippo.unifile.UniFile -import eu.kanade.tachiyomi.data.backup.models.Backup -import eu.kanade.tachiyomi.data.backup.models.Backup.CATEGORIES -import eu.kanade.tachiyomi.data.backup.models.Backup.MANGAS -import eu.kanade.tachiyomi.data.backup.models.Backup.VERSION import eu.kanade.tachiyomi.data.database.models.Manga -import eu.kanade.tachiyomi.util.sendLocalBroadcast -import timber.log.Timber import eu.kanade.tachiyomi.BuildConfig.APPLICATION_ID as ID /** @@ -26,8 +17,6 @@ class BackupCreateService : IntentService(NAME) { // Name of class private const val NAME = "BackupCreateService" - // Backup called from job - private const val EXTRA_IS_JOB = "$ID.$NAME.EXTRA_IS_JOB" // Options for backup private const val EXTRA_FLAGS = "$ID.$NAME.EXTRA_FLAGS" @@ -48,12 +37,10 @@ class BackupCreateService : IntentService(NAME) { * @param context context of application * @param uri path of Uri * @param flags determines what to backup - * @param isJob backup called from job */ - fun makeBackup(context: Context, uri: Uri, flags: Int, isJob: Boolean = false) { + fun makeBackup(context: Context, uri: Uri, flags: Int) { val intent = Intent(context, BackupCreateService::class.java).apply { putExtra(BackupConst.EXTRA_URI, uri) - putExtra(EXTRA_IS_JOB, isJob) putExtra(EXTRA_FLAGS, flags) } context.startService(intent) @@ -68,95 +55,9 @@ class BackupCreateService : IntentService(NAME) { // Get values val uri = intent.getParcelableExtra(BackupConst.EXTRA_URI) - val isJob = intent.getBooleanExtra(EXTRA_IS_JOB, false) val flags = intent.getIntExtra(EXTRA_FLAGS, 0) // Create backup - createBackupFromApp(uri, flags, isJob) + backupManager.createBackup(uri, flags, false) } - /** - * Create backup Json file from database - * - * @param uri path of Uri - * @param isJob backup called from job - */ - private fun createBackupFromApp(uri: Uri, flags: Int, isJob: Boolean) { - // Create root object - val root = JsonObject() - - // Create manga array - val mangaEntries = JsonArray() - - // Create category array - val categoryEntries = JsonArray() - - // Add value's to root - root[VERSION] = Backup.CURRENT_VERSION - root[MANGAS] = mangaEntries - root[CATEGORIES] = categoryEntries - - backupManager.databaseHelper.inTransaction { - // Get manga from database - val mangas = backupManager.getFavoriteManga() - - // Backup library manga and its dependencies - mangas.forEach { manga -> - mangaEntries.add(backupManager.backupMangaObject(manga, flags)) - } - - // Backup categories - if ((flags and BACKUP_CATEGORY_MASK) == BACKUP_CATEGORY) { - backupManager.backupCategories(categoryEntries) - } - } - - try { - // When BackupCreatorJob - if (isJob) { - // Get dir of file and create - var dir = UniFile.fromUri(this, uri) - dir = dir.createDirectory("automatic") - - // Delete older backups - val numberOfBackups = backupManager.numberOfBackups() - val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.json""") - dir.listFiles { _, filename -> backupRegex.matches(filename) } - .orEmpty() - .sortedByDescending { it.name } - .drop(numberOfBackups - 1) - .forEach { it.delete() } - - // Create new file to place backup - val newFile = dir.createFile(Backup.getDefaultFilename()) - ?: throw Exception("Couldn't create backup file") - - newFile.openOutputStream().bufferedWriter().use { - backupManager.parser.toJson(root, it) - } - } else { - val file = UniFile.fromUri(this, uri) - ?: throw Exception("Couldn't create backup file") - file.openOutputStream().bufferedWriter().use { - backupManager.parser.toJson(root, it) - } - - // Show completed dialog - val intent = Intent(BackupConst.INTENT_FILTER).apply { - putExtra(BackupConst.ACTION, BackupConst.ACTION_BACKUP_COMPLETED_DIALOG) - putExtra(BackupConst.EXTRA_URI, file.uri.toString()) - } - sendLocalBroadcast(intent) - } - } catch (e: Exception) { - Timber.e(e) - if (!isJob) { - // Show error dialog - val intent = Intent(BackupConst.INTENT_FILTER).apply { - putExtra(BackupConst.ACTION, BackupConst.ACTION_ERROR_BACKUP_DIALOG) - putExtra(BackupConst.EXTRA_ERROR_MESSAGE, e.message) - } - sendLocalBroadcast(intent) - } - } - } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt index 49c9aaecf..8717f8a89 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupCreatorJob.kt @@ -13,9 +13,10 @@ class BackupCreatorJob : Job() { override fun onRunJob(params: Params): Result { val preferences = Injekt.get() + val backupManager = Injekt.get() val uri = Uri.parse(preferences.backupsDirectory().getOrDefault()) val flags = BackupCreateService.BACKUP_ALL - BackupCreateService.makeBackup(context, uri, flags, true) + backupManager.createBackup(uri, flags, true) return Result.SUCCESS } @@ -38,4 +39,4 @@ class BackupCreatorJob : Job() { JobManager.instance().cancelAllForTag(TAG) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt index 33b37b429..4fcbafc2f 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/backup/BackupManager.kt @@ -1,8 +1,11 @@ package eu.kanade.tachiyomi.data.backup import android.content.Context +import android.content.Intent +import android.net.Uri import com.github.salomonbrys.kotson.* import com.google.gson.* +import com.hippo.unifile.UniFile import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY_MASK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CHAPTER @@ -11,6 +14,7 @@ import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HIST import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_HISTORY_MASK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_TRACK_MASK +import eu.kanade.tachiyomi.data.backup.models.Backup import eu.kanade.tachiyomi.data.backup.models.Backup.CATEGORIES import eu.kanade.tachiyomi.data.backup.models.Backup.CHAPTERS import eu.kanade.tachiyomi.data.backup.models.Backup.CURRENT_VERSION @@ -26,8 +30,10 @@ import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.data.track.TrackManager import eu.kanade.tachiyomi.source.Source import eu.kanade.tachiyomi.source.SourceManager +import eu.kanade.tachiyomi.util.sendLocalBroadcast import eu.kanade.tachiyomi.util.syncChaptersWithSource import rx.Observable +import timber.log.Timber import uy.kohesive.injekt.injectLazy class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { @@ -85,6 +91,92 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) { else -> throw Exception("Json version unknown") } + /** + * Create backup Json file from database + * + * @param uri path of Uri + * @param isJob backup called from job + */ + fun createBackup(uri: Uri, flags: Int, isJob: Boolean) { + // Create root object + val root = JsonObject() + + // Create manga array + val mangaEntries = JsonArray() + + // Create category array + val categoryEntries = JsonArray() + + // Add value's to root + root[Backup.VERSION] = Backup.CURRENT_VERSION + root[Backup.MANGAS] = mangaEntries + root[CATEGORIES] = categoryEntries + + databaseHelper.inTransaction { + // Get manga from database + val mangas = getFavoriteManga() + + // Backup library manga and its dependencies + mangas.forEach { manga -> + mangaEntries.add(backupMangaObject(manga, flags)) + } + + // Backup categories + if ((flags and BACKUP_CATEGORY_MASK) == BACKUP_CATEGORY) { + backupCategories(categoryEntries) + } + } + + try { + // When BackupCreatorJob + if (isJob) { + // Get dir of file and create + var dir = UniFile.fromUri(context, uri) + dir = dir.createDirectory("automatic") + + // Delete older backups + val numberOfBackups = numberOfBackups() + val backupRegex = Regex("""tachiyomi_\d+-\d+-\d+_\d+-\d+.json""") + dir.listFiles { _, filename -> backupRegex.matches(filename) } + .orEmpty() + .sortedByDescending { it.name } + .drop(numberOfBackups - 1) + .forEach { it.delete() } + + // Create new file to place backup + val newFile = dir.createFile(Backup.getDefaultFilename()) + ?: throw Exception("Couldn't create backup file") + + newFile.openOutputStream().bufferedWriter().use { + parser.toJson(root, it) + } + } else { + val file = UniFile.fromUri(context, uri) + ?: throw Exception("Couldn't create backup file") + file.openOutputStream().bufferedWriter().use { + parser.toJson(root, it) + } + + // Show completed dialog + val intent = Intent(BackupConst.INTENT_FILTER).apply { + putExtra(BackupConst.ACTION, BackupConst.ACTION_BACKUP_COMPLETED_DIALOG) + putExtra(BackupConst.EXTRA_URI, file.uri.toString()) + } + context.sendLocalBroadcast(intent) + } + } catch (e: Exception) { + Timber.e(e) + if (!isJob) { + // Show error dialog + val intent = Intent(BackupConst.INTENT_FILTER).apply { + putExtra(BackupConst.ACTION, BackupConst.ACTION_ERROR_BACKUP_DIALOG) + putExtra(BackupConst.EXTRA_ERROR_MESSAGE, e.message) + } + context.sendLocalBroadcast(intent) + } + } + } + /** * Backup the categories of library * diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt index 840aa50cf..597cc4eef 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsBackupController.kt @@ -3,11 +3,7 @@ package eu.kanade.tachiyomi.ui.setting import android.Manifest.permission.WRITE_EXTERNAL_STORAGE import android.app.Activity import android.app.Dialog -import android.content.ActivityNotFoundException -import android.content.BroadcastReceiver -import android.content.Context -import android.content.Intent -import android.content.IntentFilter +import android.content.* import android.net.Uri import android.os.Build import android.os.Bundle @@ -15,22 +11,17 @@ import android.support.v7.preference.PreferenceScreen import android.view.View import com.afollestad.materialdialogs.MaterialDialog import com.hippo.unifile.UniFile -import com.nononsenseapps.filepicker.FilePickerActivity import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.backup.BackupConst import eu.kanade.tachiyomi.data.backup.BackupCreateService import eu.kanade.tachiyomi.data.backup.BackupCreatorJob import eu.kanade.tachiyomi.data.backup.BackupRestoreService import eu.kanade.tachiyomi.data.backup.models.Backup -import eu.kanade.tachiyomi.data.preference.PreferencesHelper import eu.kanade.tachiyomi.data.preference.getOrDefault import eu.kanade.tachiyomi.ui.base.controller.DialogController import eu.kanade.tachiyomi.ui.base.controller.popControllerWithTag import eu.kanade.tachiyomi.ui.base.controller.requestPermissionsSafe import eu.kanade.tachiyomi.util.* -import eu.kanade.tachiyomi.widget.CustomLayoutPickerActivity -import uy.kohesive.injekt.Injekt -import uy.kohesive.injekt.api.get import java.io.File import java.util.concurrent.TimeUnit import eu.kanade.tachiyomi.data.preference.PreferenceKeys as Keys @@ -464,4 +455,4 @@ class SettingsBackupController : SettingsController() { const val TAG_RESTORING_BACKUP_DIALOG = "RestoringBackupDialog" } -} \ No newline at end of file +}