initial support for portobuf backup

This commit is contained in:
Aria Moradi
2021-08-19 00:46:45 +04:30
parent e2db191f70
commit d3d53d1a4e
7 changed files with 166 additions and 18 deletions

View File

@@ -61,3 +61,31 @@ interface SManga : Serializable {
}
}
}
//fun SManga.toMangaInfo(): MangaInfo {
// return MangaInfo(
// key = this.url,
// title = this.title,
// artist = this.artist ?: "",
// author = this.author ?: "",
// description = this.description ?: "",
// genres = this.genre?.split(", ") ?: emptyList(),
// status = this.status,
// cover = this.thumbnail_url ?: ""
// )
//}
//
//fun MangaInfo.toSManga(): SManga {
// val mangaInfo = this
// return SManga.create().apply {
// url = mangaInfo.key
// title = mangaInfo.title
// artist = mangaInfo.artist
// author = mangaInfo.author
// description = mangaInfo.description
// genre = mangaInfo.genres.joinToString(", ")
// status = mangaInfo.status
// thumbnail_url = mangaInfo.cover
// }
//}

View File

@@ -16,7 +16,7 @@ object MangaTypeAdapter {
value(it.url)
value(it.title)
value(it.source)
value(it.viewer)
value(it.viewer_flags)
value(it.chapter_flags)
endArray()
}
@@ -27,7 +27,7 @@ object MangaTypeAdapter {
manga.url = nextString()
manga.title = nextString()
manga.source = nextLong()
manga.viewer = nextInt()
manga.viewer_flags = nextInt()
manga.chapter_flags = nextInt()
endArray()
manga

View File

@@ -5,7 +5,7 @@ import suwayomi.tachidesk.manga.model.table.MangaTable
open class MangaImpl : Manga {
override var id: Long? = 0
override var id: Long? = null
override var source: Long = -1
@@ -29,6 +29,8 @@ open class MangaImpl : Manga {
override var last_update: Long = 0
override var next_update: Long = 0
override var date_added: Long = 0
override var initialized: Boolean = false
@@ -42,7 +44,7 @@ open class MangaImpl : Manga {
* 4 -> Webtoon
* 5 -> Continues Vertical
*/
override var viewer: Int = 0
override var viewer_flags: Int = 0
/** Contains some useful info about
*/
@@ -70,7 +72,7 @@ open class MangaImpl : Manga {
url = mangaRecord[MangaTable.url]
title = mangaRecord[MangaTable.title]
source = mangaRecord[MangaTable.sourceReference]
viewer = 0 // TODO: implement
viewer_flags = 0 // TODO: implement
chapter_flags = 0 // TODO: implement
}
}

View File

@@ -0,0 +1,16 @@
package suwayomi.tachidesk.manga.impl.backup.proto
import kotlinx.serialization.protobuf.ProtoBuf
/*
* Copyright (C) Contributors to the Suwayomi project
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
open class ProtoBackupBase {
var sourceMapping: Map<Long, String> = emptyMap()
val parser = ProtoBuf
}

View File

@@ -1,7 +1,5 @@
package suwayomi.tachidesk.manga.impl.backup.proto
import suwayomi.tachidesk.manga.impl.backup.BackupFlags
/*
* Copyright (C) Contributors to the Suwayomi project
*
@@ -9,8 +7,35 @@ import suwayomi.tachidesk.manga.impl.backup.BackupFlags
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
object ProtoBackupExport {
suspend fun createBackup(flags: BackupFlags): String? {
TODO()
import okio.buffer
import okio.gzip
import okio.sink
import suwayomi.tachidesk.manga.impl.backup.BackupFlags
import suwayomi.tachidesk.manga.impl.backup.proto.models.Backup
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupSerializer
import java.io.ByteArrayOutputStream
object ProtoBackupExport: ProtoBackupBase() {
suspend fun createBackup(flags: BackupFlags): ByteArray {
// Create root object
var backup: Backup? = null
// databaseHelper.inTransaction {
// val databaseManga = getFavoriteManga()
//
// backup = Backup(
// backupManga(databaseManga, flags),
// backupCategories(),
// backupExtensionInfo(databaseManga)
// )
// }
val byteArray = parser.encodeToByteArray(BackupSerializer, backup!!)
byteArray.inputStream()
val byteStream = ByteArrayOutputStream()
byteStream.sink().gzip().buffer().use { it.write(byteArray) }
return byteStream.toByteArray()
}
}

View File

@@ -7,25 +7,74 @@ package suwayomi.tachidesk.manga.impl.backup.proto
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import kotlinx.serialization.protobuf.ProtoBuf
import mu.KotlinLogging
import okio.buffer
import okio.gzip
import okio.source
import suwayomi.tachidesk.manga.impl.backup.AbstractBackupValidator.ValidationResult
import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupValidator.validate
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupCategory
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupManga
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupSerializer
import java.io.InputStream
private val logger = KotlinLogging.logger {}
object ProtoBackupImport {
object ProtoBackupImport: ProtoBackupBase() {
var restoreAmount = 0
suspend fun performRestore(sourceStream: InputStream): ValidationResult {
val backupString = sourceStream.source().gzip().buffer().use { it.readByteArray() }
val backup = ProtoBuf.decodeFromByteArray(BackupSerializer, backupString)
val backup = parser.decodeFromByteArray(BackupSerializer, backupString)
val validationResult = validate(backup)
restoreAmount = backup.backupManga.size + 1 // +1 for categories
// Restore categories
if (backup.backupCategories.isNotEmpty()) {
restoreCategories(backup.backupCategories)
}
// Store source mapping for error messages
sourceMapping = backup.backupSources.map { it.sourceId to it.name }.toMap()
// Restore individual manga
backup.backupManga.forEach {
restoreManga(it, backup.backupCategories)
}
// TODO: optionally trigger online library + tracker update
return validationResult
}
private fun restoreCategories(backupCategories: List<BackupCategory>) { // TODO
// db.inTransaction {
// backupManager.restoreCategories(backupCategories)
// }
//
// restoreProgress += 1
// showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
}
TODO()
private fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>) { // TODO
// val manga = backupManga.getMangaImpl()
// val chapters = backupManga.getChaptersImpl()
// val categories = backupManga.categories
// val history = backupManga.history
// val tracks = backupManga.getTrackingImpl()
//
// try {
// restoreMangaData(manga, chapters, categories, history, tracks, backupCategories)
// } catch (e: Exception) {
// val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
// errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
// }
//
// restoreProgress += 1
// showRestoreProgress(restoreProgress, restoreAmount, manga.title)
}
}

View File

@@ -7,11 +7,39 @@ package suwayomi.tachidesk.manga.impl.backup.proto
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
import com.google.gson.JsonObject
import org.jetbrains.exposed.sql.select
import org.jetbrains.exposed.sql.transactions.transaction
import suwayomi.tachidesk.manga.impl.backup.AbstractBackupValidator
import suwayomi.tachidesk.manga.impl.backup.proto.models.Backup
import suwayomi.tachidesk.manga.model.table.SourceTable
object ProtoBackupValidator: AbstractBackupValidator() {
fun validate(json: JsonObject): ValidationResult {
TODO()
fun validate(backup: Backup): ValidationResult {
if (backup.backupManga.isEmpty()) {
throw Exception("Backup does not contain any manga.")
}
val sources = backup.backupSources.map { it.sourceId to it.name }.toMap()
val missingSources = transaction {
sources
.filter { SourceTable.select { SourceTable.id eq it.key }.firstOrNull() == null }
.map { "${it.value} (${it.key})" }
.sorted()
}
// val trackers = backup.backupManga
// .flatMap { it.tracking }
// .map { it.syncId }
// .distinct()
val missingTrackers = listOf("")
// val missingTrackers = trackers
// .mapNotNull { trackManager.getService(it) }
// .filter { !it.isLogged }
// .map { context.getString(it.nameRes()) }
// .sorted()
return ValidationResult(missingSources, missingTrackers)
}
}