restoring with clean db and not installed extensions work
This commit is contained in:
@@ -46,12 +46,12 @@ object Chapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getSourceChapters(mangaId: Int): List<ChapterDataClass> {
|
private suspend fun getSourceChapters(mangaId: Int): List<ChapterDataClass> {
|
||||||
val mangaDetails = getManga(mangaId)
|
val manga = getManga(mangaId)
|
||||||
val source = getHttpSource(mangaDetails.sourceId.toLong())
|
val source = getHttpSource(manga.sourceId.toLong())
|
||||||
val chapterList = source.fetchChapterList(
|
val chapterList = source.fetchChapterList(
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
title = mangaDetails.title
|
title = manga.title
|
||||||
url = mangaDetails.url
|
url = manga.url
|
||||||
}
|
}
|
||||||
).awaitSingle()
|
).awaitSingle()
|
||||||
|
|
||||||
@@ -69,7 +69,7 @@ object Chapter {
|
|||||||
it[scanlator] = fetchedChapter.scanlator
|
it[scanlator] = fetchedChapter.scanlator
|
||||||
|
|
||||||
it[chapterIndex] = index + 1
|
it[chapterIndex] = index + 1
|
||||||
it[manga] = mangaId
|
it[ChapterTable.manga] = mangaId
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ChapterTable.update({ ChapterTable.url eq fetchedChapter.url }) {
|
ChapterTable.update({ ChapterTable.url eq fetchedChapter.url }) {
|
||||||
@@ -79,7 +79,7 @@ object Chapter {
|
|||||||
it[scanlator] = fetchedChapter.scanlator
|
it[scanlator] = fetchedChapter.scanlator
|
||||||
|
|
||||||
it[chapterIndex] = index + 1
|
it[chapterIndex] = index + 1
|
||||||
it[manga] = mangaId
|
it[ChapterTable.manga] = mangaId
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+124
-27
@@ -11,20 +11,36 @@ import mu.KotlinLogging
|
|||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.gzip
|
import okio.gzip
|
||||||
import okio.source
|
import okio.source
|
||||||
|
import org.jetbrains.exposed.sql.and
|
||||||
|
import org.jetbrains.exposed.sql.insert
|
||||||
|
import org.jetbrains.exposed.sql.insertAndGetId
|
||||||
|
import org.jetbrains.exposed.sql.select
|
||||||
|
import org.jetbrains.exposed.sql.transactions.transaction
|
||||||
|
import suwayomi.tachidesk.manga.impl.Category
|
||||||
|
import suwayomi.tachidesk.manga.impl.CategoryManga
|
||||||
import suwayomi.tachidesk.manga.impl.backup.AbstractBackupValidator.ValidationResult
|
import suwayomi.tachidesk.manga.impl.backup.AbstractBackupValidator.ValidationResult
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.models.Chapter
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.models.Manga
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.models.Track
|
||||||
import suwayomi.tachidesk.manga.impl.backup.proto.ProtoBackupValidator.validate
|
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.BackupCategory
|
||||||
|
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupHistory
|
||||||
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupManga
|
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupManga
|
||||||
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupSerializer
|
import suwayomi.tachidesk.manga.impl.backup.proto.models.BackupSerializer
|
||||||
|
import suwayomi.tachidesk.manga.model.table.CategoryTable
|
||||||
|
import suwayomi.tachidesk.manga.model.table.ChapterTable
|
||||||
|
import suwayomi.tachidesk.manga.model.table.MangaTable
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
|
import java.util.Date
|
||||||
|
|
||||||
private val logger = KotlinLogging.logger {}
|
private val logger = KotlinLogging.logger {}
|
||||||
|
|
||||||
object ProtoBackupImport : ProtoBackupBase() {
|
object ProtoBackupImport : ProtoBackupBase() {
|
||||||
var restoreAmount = 0
|
private var restoreAmount = 0
|
||||||
|
|
||||||
|
private val errors = mutableListOf<Pair<Date, String>>()
|
||||||
|
|
||||||
suspend fun performRestore(sourceStream: InputStream): ValidationResult {
|
suspend fun performRestore(sourceStream: InputStream): ValidationResult {
|
||||||
|
|
||||||
val backupString = sourceStream.source().gzip().buffer().use { it.readByteArray() }
|
val backupString = sourceStream.source().gzip().buffer().use { it.readByteArray() }
|
||||||
val backup = parser.decodeFromByteArray(BackupSerializer, backupString)
|
val backup = parser.decodeFromByteArray(BackupSerializer, backupString)
|
||||||
|
|
||||||
@@ -37,43 +53,124 @@ object ProtoBackupImport : ProtoBackupBase() {
|
|||||||
restoreCategories(backup.backupCategories)
|
restoreCategories(backup.backupCategories)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val categoryMapping = transaction {
|
||||||
|
backup.backupCategories.associate {
|
||||||
|
it.order to CategoryTable.select { CategoryTable.name eq it.name }.first()[CategoryTable.id].value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store source mapping for error messages
|
// Store source mapping for error messages
|
||||||
sourceMapping = backup.backupSources.map { it.sourceId to it.name }.toMap()
|
sourceMapping = backup.backupSources.map { it.sourceId to it.name }.toMap()
|
||||||
|
|
||||||
// Restore individual manga
|
// Restore individual manga
|
||||||
backup.backupManga.forEach {
|
backup.backupManga.forEach {
|
||||||
restoreManga(it, backup.backupCategories)
|
restoreManga(it, backup.backupCategories, categoryMapping)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optionally trigger online library + tracker update
|
logger.info {
|
||||||
|
"""
|
||||||
|
Restore Errors:
|
||||||
|
${ errors.joinToString("\n") { "${it.first} - ${it.second}" } }
|
||||||
|
Restore Summary:
|
||||||
|
- Missing Sources:
|
||||||
|
${validationResult.missingSources.joinToString("\n ")}
|
||||||
|
- Missing Trackers:
|
||||||
|
${validationResult.missingTrackers.joinToString("\n")}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
|
|
||||||
return validationResult
|
return validationResult
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreCategories(backupCategories: List<BackupCategory>) { // TODO
|
private fun restoreCategories(backupCategories: List<BackupCategory>) {
|
||||||
// db.inTransaction {
|
val dbCategories = Category.getCategoryList()
|
||||||
// backupManager.restoreCategories(backupCategories)
|
|
||||||
// }
|
// Iterate over them and create missing categories
|
||||||
//
|
backupCategories.forEach { category ->
|
||||||
// restoreProgress += 1
|
if (dbCategories.none { it.name == category.name }) {
|
||||||
// showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
|
Category.createCategory(category.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreManga(backupManga: BackupManga, backupCategories: List<BackupCategory>) { // TODO
|
private fun restoreManga(
|
||||||
// val manga = backupManga.getMangaImpl()
|
backupManga: BackupManga,
|
||||||
// val chapters = backupManga.getChaptersImpl()
|
backupCategories: List<BackupCategory>,
|
||||||
// val categories = backupManga.categories
|
categoryMapping: Map<Int, Int>
|
||||||
// val history = backupManga.history
|
) { // TODO
|
||||||
// val tracks = backupManga.getTrackingImpl()
|
val manga = backupManga.getMangaImpl()
|
||||||
//
|
val chapters = backupManga.getChaptersImpl()
|
||||||
// try {
|
val categories = backupManga.categories
|
||||||
// restoreMangaData(manga, chapters, categories, history, tracks, backupCategories)
|
val history = backupManga.history
|
||||||
// } catch (e: Exception) {
|
val tracks = backupManga.getTrackingImpl()
|
||||||
// val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
|
|
||||||
// errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
|
try {
|
||||||
// }
|
restoreMangaData(manga, chapters, categories, history, tracks, backupCategories, categoryMapping)
|
||||||
//
|
} catch (e: Exception) {
|
||||||
// restoreProgress += 1
|
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
|
||||||
// showRestoreProgress(restoreProgress, restoreAmount, manga.title)
|
errors.add(Date() to "${manga.title} [$sourceName]: ${e.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restoreMangaData(
|
||||||
|
manga: Manga,
|
||||||
|
chapters: List<Chapter>,
|
||||||
|
categories: List<Int>,
|
||||||
|
history: List<BackupHistory>,
|
||||||
|
tracks: List<Track>,
|
||||||
|
backupCategories: List<BackupCategory>,
|
||||||
|
categoryMapping: Map<Int, Int>
|
||||||
|
) {
|
||||||
|
val dbManga = transaction {
|
||||||
|
MangaTable.select { (MangaTable.url eq manga.url) and (MangaTable.sourceReference eq manga.source) }
|
||||||
|
.firstOrNull()
|
||||||
|
}
|
||||||
|
if (dbManga == null) { // Manga not in database
|
||||||
|
transaction {
|
||||||
|
// insert manga to database
|
||||||
|
val mangaId = MangaTable.insertAndGetId {
|
||||||
|
it[url] = manga.url
|
||||||
|
it[title] = manga.title
|
||||||
|
|
||||||
|
it[artist] = manga.artist
|
||||||
|
it[author] = manga.author
|
||||||
|
it[description] = manga.description
|
||||||
|
it[genre] = manga.genre
|
||||||
|
it[status] = manga.status
|
||||||
|
it[thumbnail_url] = manga.thumbnail_url
|
||||||
|
|
||||||
|
it[sourceReference] = manga.source
|
||||||
|
|
||||||
|
it[initialized] = manga.description != null
|
||||||
|
}.value
|
||||||
|
|
||||||
|
// insert chapter data
|
||||||
|
chapters.forEach { chapter ->
|
||||||
|
ChapterTable.insert {
|
||||||
|
it[url] = chapter.url
|
||||||
|
it[name] = chapter.name
|
||||||
|
it[date_upload] = chapter.date_upload
|
||||||
|
it[chapter_number] = chapter.chapter_number
|
||||||
|
it[scanlator] = chapter.scanlator
|
||||||
|
|
||||||
|
it[chapterIndex] = chapter.source_order
|
||||||
|
it[ChapterTable.manga] = mangaId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert categories
|
||||||
|
categories.forEach { backupCategoryOrder ->
|
||||||
|
CategoryManga.addMangaToCategory(mangaId, categoryMapping[backupCategoryOrder]!!)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // Manga in database
|
||||||
|
// merge chapter data
|
||||||
|
|
||||||
|
// merge categories
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: insert/merge history
|
||||||
|
|
||||||
|
// TODO: insert/merge tracking
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ object GetHttpSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val sourceRecord = transaction {
|
val sourceRecord = transaction {
|
||||||
SourceTable.select { SourceTable.id eq sourceId }.first()
|
SourceTable.select { SourceTable.id eq sourceId }.firstOrNull()!!
|
||||||
}
|
}
|
||||||
|
|
||||||
val extensionId = sourceRecord[SourceTable.extension]
|
val extensionId = sourceRecord[SourceTable.extension]
|
||||||
|
|||||||
Reference in New Issue
Block a user