Legacy backup conversion to Kotlin Serialization (#5282)
* Legacy backup conversion to Kotlin Serialization * Fix BackupTest compiling
This commit is contained in:
parent
b03ebc1fa4
commit
597cec3064
@ -2,44 +2,52 @@ package eu.kanade.tachiyomi.data.backup.legacy
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.github.salomonbrys.kotson.fromJson
|
|
||||||
import com.github.salomonbrys.kotson.registerTypeAdapter
|
|
||||||
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
|
import eu.kanade.tachiyomi.data.backup.AbstractBackupManager
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.CURRENT_VERSION
|
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.Companion.CURRENT_VERSION
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryTypeAdapter
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryImplTypeSerializer
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterTypeAdapter
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.CategoryTypeSerializer
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.HistoryTypeAdapter
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterImplTypeSerializer
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaTypeAdapter
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.ChapterTypeSerializer
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackTypeAdapter
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.HistoryTypeSerializer
|
||||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaImplTypeSerializer
|
||||||
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.MangaTypeSerializer
|
||||||
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackImplTypeSerializer
|
||||||
|
import eu.kanade.tachiyomi.data.backup.legacy.serializer.TrackTypeSerializer
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.History
|
import eu.kanade.tachiyomi.data.database.models.History
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
import eu.kanade.tachiyomi.data.database.models.MangaCategory
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
import eu.kanade.tachiyomi.data.database.models.toMangaInfo
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.model.toSManga
|
import eu.kanade.tachiyomi.source.model.toSManga
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
|
import kotlinx.serialization.modules.contextual
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : AbstractBackupManager(context) {
|
class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : AbstractBackupManager(context) {
|
||||||
|
|
||||||
val parser: Gson = when (version) {
|
val parser: Json = when (version) {
|
||||||
2 -> GsonBuilder()
|
2 -> Json {
|
||||||
.registerTypeAdapter<MangaImpl>(MangaTypeAdapter.build())
|
// Forks may have added items to backup
|
||||||
.registerTypeHierarchyAdapter<ChapterImpl>(ChapterTypeAdapter.build())
|
ignoreUnknownKeys = true
|
||||||
.registerTypeAdapter<CategoryImpl>(CategoryTypeAdapter.build())
|
|
||||||
.registerTypeAdapter<DHistory>(HistoryTypeAdapter.build())
|
// Register custom serializers
|
||||||
.registerTypeHierarchyAdapter<TrackImpl>(TrackTypeAdapter.build())
|
serializersModule = SerializersModule {
|
||||||
.create()
|
contextual(MangaTypeSerializer)
|
||||||
|
contextual(MangaImplTypeSerializer)
|
||||||
|
contextual(ChapterTypeSerializer)
|
||||||
|
contextual(ChapterImplTypeSerializer)
|
||||||
|
contextual(CategoryTypeSerializer)
|
||||||
|
contextual(CategoryImplTypeSerializer)
|
||||||
|
contextual(TrackTypeSerializer)
|
||||||
|
contextual(TrackImplTypeSerializer)
|
||||||
|
contextual(HistoryTypeSerializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
else -> throw Exception("Unknown backup version")
|
else -> throw Exception("Unknown backup version")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,12 +87,11 @@ class LegacyBackupManager(context: Context, version: Int = CURRENT_VERSION) : Ab
|
|||||||
/**
|
/**
|
||||||
* Restore the categories from Json
|
* Restore the categories from Json
|
||||||
*
|
*
|
||||||
* @param jsonCategories array containing categories
|
* @param backupCategories array containing categories
|
||||||
*/
|
*/
|
||||||
internal fun restoreCategories(jsonCategories: JsonArray) {
|
internal fun restoreCategories(backupCategories: List<Category>) {
|
||||||
// Get categories from file and from db
|
// Get categories from file and from db
|
||||||
val dbCategories = databaseHelper.getCategories().executeAsBlocking()
|
val dbCategories = databaseHelper.getCategories().executeAsBlocking()
|
||||||
val backupCategories = parser.fromJson<List<CategoryImpl>>(jsonCategories)
|
|
||||||
|
|
||||||
// Iterate over them
|
// Iterate over them
|
||||||
backupCategories.forEach { category ->
|
backupCategories.forEach { category ->
|
||||||
|
@ -2,88 +2,80 @@ package eu.kanade.tachiyomi.data.backup.legacy
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.github.salomonbrys.kotson.fromJson
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonElement
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import com.google.gson.stream.JsonReader
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
|
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestore
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
import eu.kanade.tachiyomi.data.backup.BackupNotifier
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup.MANGAS
|
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||||
|
import eu.kanade.tachiyomi.data.backup.legacy.models.MangaObject
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Track
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.decodeFromJsonElement
|
||||||
|
import kotlinx.serialization.json.intOrNull
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import okio.buffer
|
||||||
|
import okio.source
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
|
class LegacyBackupRestore(context: Context, notifier: BackupNotifier) : AbstractBackupRestore<LegacyBackupManager>(context, notifier) {
|
||||||
|
|
||||||
override suspend fun performRestore(uri: Uri): Boolean {
|
override suspend fun performRestore(uri: Uri): Boolean {
|
||||||
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
|
// Read the json and create a Json Object,
|
||||||
val json = JsonParser.parseReader(reader).asJsonObject
|
// cannot use the backupManager json deserializer one because its not initialized yet
|
||||||
|
val backupObject = Json.decodeFromString<JsonObject>(
|
||||||
|
context.contentResolver.openInputStream(uri)!!.source().buffer().use { it.readUtf8() }
|
||||||
|
)
|
||||||
|
|
||||||
val version = json.get(Backup.VERSION)?.asInt ?: 1
|
// Get parser version
|
||||||
|
val version = backupObject["version"]?.jsonPrimitive?.intOrNull ?: 1
|
||||||
|
|
||||||
|
// Initialize manager
|
||||||
backupManager = LegacyBackupManager(context, version)
|
backupManager = LegacyBackupManager(context, version)
|
||||||
|
|
||||||
val mangasJson = json.get(MANGAS).asJsonArray
|
// Decode the json object to a Backup object
|
||||||
restoreAmount = mangasJson.size() + 1 // +1 for categories
|
val backup = backupManager.parser.decodeFromJsonElement<Backup>(backupObject)
|
||||||
|
|
||||||
|
restoreAmount = backup.mangas.size + 1 // +1 for categories
|
||||||
|
|
||||||
// Restore categories
|
// Restore categories
|
||||||
json.get(Backup.CATEGORIES)?.let { restoreCategories(it) }
|
backup.categories?.let { restoreCategories(it) }
|
||||||
|
|
||||||
// Store source mapping for error messages
|
// Store source mapping for error messages
|
||||||
sourceMapping = LegacyBackupRestoreValidator.getSourceMapping(json)
|
sourceMapping = LegacyBackupRestoreValidator.getSourceMapping(backup.extensions ?: emptyList())
|
||||||
|
|
||||||
// Restore individual manga
|
// Restore individual manga
|
||||||
mangasJson.forEach {
|
backup.mangas.forEach {
|
||||||
if (job?.isActive != true) {
|
if (job?.isActive != true) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreManga(it.asJsonObject)
|
restoreManga(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun restoreCategories(categoriesJson: JsonElement) {
|
private fun restoreCategories(categoriesJson: List<Category>) {
|
||||||
db.inTransaction {
|
db.inTransaction {
|
||||||
backupManager.restoreCategories(categoriesJson.asJsonArray)
|
backupManager.restoreCategories(categoriesJson)
|
||||||
}
|
}
|
||||||
|
|
||||||
restoreProgress += 1
|
restoreProgress += 1
|
||||||
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
|
showRestoreProgress(restoreProgress, restoreAmount, context.getString(R.string.categories))
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun restoreManga(mangaJson: JsonObject) {
|
private suspend fun restoreManga(mangaJson: MangaObject) {
|
||||||
val manga = backupManager.parser.fromJson<MangaImpl>(
|
val manga = mangaJson.manga
|
||||||
mangaJson.get(
|
val chapters = mangaJson.chapters ?: emptyList()
|
||||||
Backup.MANGA
|
val categories = mangaJson.categories ?: emptyList()
|
||||||
)
|
val history = mangaJson.history ?: emptyList()
|
||||||
)
|
val tracks = mangaJson.track ?: emptyList()
|
||||||
val chapters = backupManager.parser.fromJson<List<ChapterImpl>>(
|
|
||||||
mangaJson.get(Backup.CHAPTERS)
|
|
||||||
?: JsonArray()
|
|
||||||
)
|
|
||||||
val categories = backupManager.parser.fromJson<List<String>>(
|
|
||||||
mangaJson.get(Backup.CATEGORIES)
|
|
||||||
?: JsonArray()
|
|
||||||
)
|
|
||||||
val history = backupManager.parser.fromJson<List<DHistory>>(
|
|
||||||
mangaJson.get(Backup.HISTORY)
|
|
||||||
?: JsonArray()
|
|
||||||
)
|
|
||||||
val tracks = backupManager.parser.fromJson<List<TrackImpl>>(
|
|
||||||
mangaJson.get(Backup.TRACK)
|
|
||||||
?: JsonArray()
|
|
||||||
)
|
|
||||||
|
|
||||||
val source = backupManager.sourceManager.get(manga.source)
|
val source = backupManager.sourceManager.get(manga.source)
|
||||||
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
|
val sourceName = sourceMapping[manga.source] ?: manga.source.toString()
|
||||||
|
@ -2,12 +2,12 @@ package eu.kanade.tachiyomi.data.backup.legacy
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import com.google.gson.stream.JsonReader
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
|
import eu.kanade.tachiyomi.data.backup.AbstractBackupRestoreValidator
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
import eu.kanade.tachiyomi.data.backup.legacy.models.Backup
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import okio.buffer
|
||||||
|
import okio.source
|
||||||
|
|
||||||
class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
||||||
/**
|
/**
|
||||||
@ -17,30 +17,30 @@ class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
|||||||
* @return List of missing sources or missing trackers.
|
* @return List of missing sources or missing trackers.
|
||||||
*/
|
*/
|
||||||
override fun validate(context: Context, uri: Uri): Results {
|
override fun validate(context: Context, uri: Uri): Results {
|
||||||
val reader = JsonReader(context.contentResolver.openInputStream(uri)!!.bufferedReader())
|
val backupManager = LegacyBackupManager(context)
|
||||||
val json = JsonParser.parseReader(reader).asJsonObject
|
|
||||||
|
|
||||||
val version = json.get(Backup.VERSION)
|
val backup = backupManager.parser.decodeFromString<Backup>(
|
||||||
val mangasJson = json.get(Backup.MANGAS)
|
context.contentResolver.openInputStream(uri)!!.source().buffer().use { it.readUtf8() }
|
||||||
if (version == null || mangasJson == null) {
|
)
|
||||||
|
|
||||||
|
if (backup.version == null) {
|
||||||
throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
|
throw Exception(context.getString(R.string.invalid_backup_file_missing_data))
|
||||||
}
|
}
|
||||||
|
|
||||||
val mangas = mangasJson.asJsonArray
|
if (backup.mangas.isEmpty()) {
|
||||||
if (mangas.size() == 0) {
|
|
||||||
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
|
throw Exception(context.getString(R.string.invalid_backup_file_missing_manga))
|
||||||
}
|
}
|
||||||
|
|
||||||
val sources = getSourceMapping(json)
|
val sources = getSourceMapping(backup.extensions ?: emptyList())
|
||||||
val missingSources = sources
|
val missingSources = sources
|
||||||
.filter { sourceManager.get(it.key) == null }
|
.filter { sourceManager.get(it.key) == null }
|
||||||
.values
|
.values
|
||||||
.sorted()
|
.sorted()
|
||||||
|
|
||||||
val trackers = mangas
|
val trackers = backup.mangas
|
||||||
.filter { it.asJsonObject.has("track") }
|
.filterNot { it.track.isNullOrEmpty() }
|
||||||
.flatMap { it.asJsonObject["track"].asJsonArray }
|
.flatMap { it.track ?: emptyList() }
|
||||||
.map { it.asJsonObject["s"].asInt }
|
.map { it.sync_id }
|
||||||
.distinct()
|
.distinct()
|
||||||
val missingTrackers = trackers
|
val missingTrackers = trackers
|
||||||
.mapNotNull { trackManager.getService(it) }
|
.mapNotNull { trackManager.getService(it) }
|
||||||
@ -52,12 +52,10 @@ class LegacyBackupRestoreValidator : AbstractBackupRestoreValidator() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getSourceMapping(json: JsonObject): Map<Long, String> {
|
fun getSourceMapping(extensionsMapping: List<String>): Map<Long, String> {
|
||||||
val extensionsMapping = json.get(Backup.EXTENSIONS) ?: return emptyMap()
|
return extensionsMapping
|
||||||
|
|
||||||
return extensionsMapping.asJsonArray
|
|
||||||
.map {
|
.map {
|
||||||
val items = it.asString.split(":")
|
val items = it.split(":")
|
||||||
items[0].toLong() to items[1]
|
items[0].toLong() to items[1]
|
||||||
}
|
}
|
||||||
.toMap()
|
.toMap()
|
||||||
|
@ -1,25 +1,37 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.legacy.models
|
package eu.kanade.tachiyomi.data.backup.legacy.models
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
@Serializable
|
||||||
* Json values
|
data class Backup(
|
||||||
*/
|
val version: Int? = null,
|
||||||
object Backup {
|
var mangas: MutableList<MangaObject> = mutableListOf(),
|
||||||
const val CURRENT_VERSION = 2
|
var categories: List<@Contextual Category>? = null,
|
||||||
const val MANGA = "manga"
|
var extensions: List<String>? = null
|
||||||
const val MANGAS = "mangas"
|
) {
|
||||||
const val TRACK = "track"
|
companion object {
|
||||||
const val CHAPTERS = "chapters"
|
const val CURRENT_VERSION = 2
|
||||||
const val CATEGORIES = "categories"
|
|
||||||
const val EXTENSIONS = "extensions"
|
|
||||||
const val HISTORY = "history"
|
|
||||||
const val VERSION = "version"
|
|
||||||
|
|
||||||
fun getDefaultFilename(): String {
|
fun getDefaultFilename(): String {
|
||||||
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
|
val date = SimpleDateFormat("yyyy-MM-dd_HH-mm", Locale.getDefault()).format(Date())
|
||||||
return "tachiyomi_$date.json"
|
return "tachiyomi_$date.json"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class MangaObject(
|
||||||
|
var manga: @Contextual Manga,
|
||||||
|
var chapters: List<@Contextual Chapter>? = null,
|
||||||
|
var categories: List<String>? = null,
|
||||||
|
var track: List<@Contextual Track>? = null,
|
||||||
|
var history: List<@Contextual DHistory>? = null
|
||||||
|
)
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.typeAdapter
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Serializer used to write / read [CategoryImpl] to / from json
|
|
||||||
*/
|
|
||||||
object CategoryTypeAdapter {
|
|
||||||
|
|
||||||
fun build(): TypeAdapter<CategoryImpl> {
|
|
||||||
return typeAdapter {
|
|
||||||
write {
|
|
||||||
beginArray()
|
|
||||||
value(it.name)
|
|
||||||
value(it.order)
|
|
||||||
endArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
read {
|
|
||||||
beginArray()
|
|
||||||
val category = CategoryImpl()
|
|
||||||
category.name = nextString()
|
|
||||||
category.order = nextInt()
|
|
||||||
endArray()
|
|
||||||
category
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,49 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Category
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.CategoryImpl
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.JsonDecoder
|
||||||
|
import kotlinx.serialization.json.JsonEncoder
|
||||||
|
import kotlinx.serialization.json.add
|
||||||
|
import kotlinx.serialization.json.buildJsonArray
|
||||||
|
import kotlinx.serialization.json.int
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Serializer used to write / read [CategoryImpl] to / from json
|
||||||
|
*/
|
||||||
|
open class CategoryBaseSerializer<T : Category> : KSerializer<T> {
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Category")
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: T) {
|
||||||
|
encoder as JsonEncoder
|
||||||
|
encoder.encodeJsonElement(
|
||||||
|
buildJsonArray {
|
||||||
|
add(value.name)
|
||||||
|
add(value.order)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun deserialize(decoder: Decoder): T {
|
||||||
|
// make a category impl and cast as T so that the serializer accepts it
|
||||||
|
return CategoryImpl().apply {
|
||||||
|
decoder as JsonDecoder
|
||||||
|
val array = decoder.decodeJsonElement().jsonArray
|
||||||
|
name = array[0].jsonPrimitive.content
|
||||||
|
order = array[1].jsonPrimitive.int
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow for serialization of a category and category impl
|
||||||
|
object CategoryTypeSerializer : CategoryBaseSerializer<Category>()
|
||||||
|
|
||||||
|
object CategoryImplTypeSerializer : CategoryBaseSerializer<CategoryImpl>()
|
@ -1,59 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.typeAdapter
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import com.google.gson.stream.JsonToken
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Serializer used to write / read [ChapterImpl] to / from json
|
|
||||||
*/
|
|
||||||
object ChapterTypeAdapter {
|
|
||||||
|
|
||||||
private const val URL = "u"
|
|
||||||
private const val READ = "r"
|
|
||||||
private const val BOOKMARK = "b"
|
|
||||||
private const val LAST_READ = "l"
|
|
||||||
|
|
||||||
fun build(): TypeAdapter<ChapterImpl> {
|
|
||||||
return typeAdapter {
|
|
||||||
write {
|
|
||||||
if (it.read || it.bookmark || it.last_page_read != 0) {
|
|
||||||
beginObject()
|
|
||||||
name(URL)
|
|
||||||
value(it.url)
|
|
||||||
if (it.read) {
|
|
||||||
name(READ)
|
|
||||||
value(1)
|
|
||||||
}
|
|
||||||
if (it.bookmark) {
|
|
||||||
name(BOOKMARK)
|
|
||||||
value(1)
|
|
||||||
}
|
|
||||||
if (it.last_page_read != 0) {
|
|
||||||
name(LAST_READ)
|
|
||||||
value(it.last_page_read)
|
|
||||||
}
|
|
||||||
endObject()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
read {
|
|
||||||
val chapter = ChapterImpl()
|
|
||||||
beginObject()
|
|
||||||
while (hasNext()) {
|
|
||||||
if (peek() == JsonToken.NAME) {
|
|
||||||
when (nextName()) {
|
|
||||||
URL -> chapter.url = nextString()
|
|
||||||
READ -> chapter.read = nextInt() == 1
|
|
||||||
BOOKMARK -> chapter.bookmark = nextInt() == 1
|
|
||||||
LAST_READ -> chapter.last_page_read = nextInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endObject()
|
|
||||||
chapter
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,66 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.JsonDecoder
|
||||||
|
import kotlinx.serialization.json.JsonEncoder
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.intOrNull
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Serializer used to write / read [ChapterImpl] to / from json
|
||||||
|
*/
|
||||||
|
open class ChapterBaseSerializer<T : Chapter> : KSerializer<T> {
|
||||||
|
|
||||||
|
override val descriptor = buildClassSerialDescriptor("Chapter")
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: T) {
|
||||||
|
encoder as JsonEncoder
|
||||||
|
encoder.encodeJsonElement(
|
||||||
|
buildJsonObject {
|
||||||
|
put(URL, value.url)
|
||||||
|
if (value.read) {
|
||||||
|
put(READ, 1)
|
||||||
|
}
|
||||||
|
if (value.bookmark) {
|
||||||
|
put(BOOKMARK, 1)
|
||||||
|
}
|
||||||
|
if (value.last_page_read != 0) {
|
||||||
|
put(LAST_READ, value.last_page_read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun deserialize(decoder: Decoder): T {
|
||||||
|
// make a chapter impl and cast as T so that the serializer accepts it
|
||||||
|
return ChapterImpl().apply {
|
||||||
|
decoder as JsonDecoder
|
||||||
|
val jsonObject = decoder.decodeJsonElement().jsonObject
|
||||||
|
url = jsonObject[URL]!!.jsonPrimitive.content
|
||||||
|
read = jsonObject[READ]?.jsonPrimitive?.intOrNull == 1
|
||||||
|
bookmark = jsonObject[BOOKMARK]?.jsonPrimitive?.intOrNull == 1
|
||||||
|
last_page_read = jsonObject[LAST_READ]?.jsonPrimitive?.intOrNull ?: last_page_read
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val URL = "u"
|
||||||
|
private const val READ = "r"
|
||||||
|
private const val BOOKMARK = "b"
|
||||||
|
private const val LAST_READ = "l"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow for serialization of a chapter and chapter impl
|
||||||
|
object ChapterTypeSerializer : ChapterBaseSerializer<Chapter>()
|
||||||
|
|
||||||
|
object ChapterImplTypeSerializer : ChapterBaseSerializer<ChapterImpl>()
|
@ -1,32 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.typeAdapter
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Serializer used to write / read [DHistory] to / from json
|
|
||||||
*/
|
|
||||||
object HistoryTypeAdapter {
|
|
||||||
|
|
||||||
fun build(): TypeAdapter<DHistory> {
|
|
||||||
return typeAdapter {
|
|
||||||
write {
|
|
||||||
if (it.lastRead != 0L) {
|
|
||||||
beginArray()
|
|
||||||
value(it.url)
|
|
||||||
value(it.lastRead)
|
|
||||||
endArray()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
read {
|
|
||||||
beginArray()
|
|
||||||
val url = nextString()
|
|
||||||
val lastRead = nextLong()
|
|
||||||
endArray()
|
|
||||||
DHistory(url, lastRead)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,41 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.backup.legacy.models.DHistory
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.JsonDecoder
|
||||||
|
import kotlinx.serialization.json.JsonEncoder
|
||||||
|
import kotlinx.serialization.json.add
|
||||||
|
import kotlinx.serialization.json.buildJsonArray
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Serializer used to write / read [DHistory] to / from json
|
||||||
|
*/
|
||||||
|
object HistoryTypeSerializer : KSerializer<DHistory> {
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("History")
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: DHistory) {
|
||||||
|
encoder as JsonEncoder
|
||||||
|
encoder.encodeJsonElement(
|
||||||
|
buildJsonArray {
|
||||||
|
add(value.url)
|
||||||
|
add(value.lastRead)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun deserialize(decoder: Decoder): DHistory {
|
||||||
|
decoder as JsonDecoder
|
||||||
|
val array = decoder.decodeJsonElement().jsonArray
|
||||||
|
return DHistory(
|
||||||
|
url = array[0].jsonPrimitive.content,
|
||||||
|
lastRead = array[1].jsonPrimitive.long
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -1,37 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.typeAdapter
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Serializer used to write / read [MangaImpl] to / from json
|
|
||||||
*/
|
|
||||||
object MangaTypeAdapter {
|
|
||||||
|
|
||||||
fun build(): TypeAdapter<MangaImpl> {
|
|
||||||
return typeAdapter {
|
|
||||||
write {
|
|
||||||
beginArray()
|
|
||||||
value(it.url)
|
|
||||||
value(it.title)
|
|
||||||
value(it.source)
|
|
||||||
value(it.viewer_flags)
|
|
||||||
value(it.chapter_flags)
|
|
||||||
endArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
read {
|
|
||||||
beginArray()
|
|
||||||
val manga = MangaImpl()
|
|
||||||
manga.url = nextString()
|
|
||||||
manga.title = nextString()
|
|
||||||
manga.source = nextLong()
|
|
||||||
manga.viewer_flags = nextInt()
|
|
||||||
manga.chapter_flags = nextInt()
|
|
||||||
endArray()
|
|
||||||
manga
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,56 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.JsonDecoder
|
||||||
|
import kotlinx.serialization.json.JsonEncoder
|
||||||
|
import kotlinx.serialization.json.add
|
||||||
|
import kotlinx.serialization.json.buildJsonArray
|
||||||
|
import kotlinx.serialization.json.int
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.long
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Serializer used to write / read [MangaImpl] to / from json
|
||||||
|
*/
|
||||||
|
open class MangaBaseSerializer<T : Manga> : KSerializer<T> {
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Manga")
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: T) {
|
||||||
|
encoder as JsonEncoder
|
||||||
|
encoder.encodeJsonElement(
|
||||||
|
buildJsonArray {
|
||||||
|
add(value.url)
|
||||||
|
add(value.title)
|
||||||
|
add(value.source)
|
||||||
|
add(value.viewer_flags)
|
||||||
|
add(value.chapter_flags)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun deserialize(decoder: Decoder): T {
|
||||||
|
// make a manga impl and cast as T so that the serializer accepts it
|
||||||
|
return MangaImpl().apply {
|
||||||
|
decoder as JsonDecoder
|
||||||
|
val array = decoder.decodeJsonElement().jsonArray
|
||||||
|
url = array[0].jsonPrimitive.content
|
||||||
|
title = array[1].jsonPrimitive.content
|
||||||
|
source = array[2].jsonPrimitive.long
|
||||||
|
viewer_flags = array[3].jsonPrimitive.int
|
||||||
|
chapter_flags = array[4].jsonPrimitive.int
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow for serialization of a manga and manga impl
|
||||||
|
object MangaTypeSerializer : MangaBaseSerializer<Manga>()
|
||||||
|
|
||||||
|
object MangaImplTypeSerializer : MangaBaseSerializer<MangaImpl>()
|
@ -1,59 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.typeAdapter
|
|
||||||
import com.google.gson.TypeAdapter
|
|
||||||
import com.google.gson.stream.JsonToken
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JSON Serializer used to write / read [TrackImpl] to / from json
|
|
||||||
*/
|
|
||||||
object TrackTypeAdapter {
|
|
||||||
|
|
||||||
private const val SYNC = "s"
|
|
||||||
private const val MEDIA = "r"
|
|
||||||
private const val LIBRARY = "ml"
|
|
||||||
private const val TITLE = "t"
|
|
||||||
private const val LAST_READ = "l"
|
|
||||||
private const val TRACKING_URL = "u"
|
|
||||||
|
|
||||||
fun build(): TypeAdapter<TrackImpl> {
|
|
||||||
return typeAdapter {
|
|
||||||
write {
|
|
||||||
beginObject()
|
|
||||||
name(TITLE)
|
|
||||||
value(it.title)
|
|
||||||
name(SYNC)
|
|
||||||
value(it.sync_id)
|
|
||||||
name(MEDIA)
|
|
||||||
value(it.media_id)
|
|
||||||
name(LIBRARY)
|
|
||||||
value(it.library_id)
|
|
||||||
name(LAST_READ)
|
|
||||||
value(it.last_chapter_read)
|
|
||||||
name(TRACKING_URL)
|
|
||||||
value(it.tracking_url)
|
|
||||||
endObject()
|
|
||||||
}
|
|
||||||
|
|
||||||
read {
|
|
||||||
val track = TrackImpl()
|
|
||||||
beginObject()
|
|
||||||
while (hasNext()) {
|
|
||||||
if (peek() == JsonToken.NAME) {
|
|
||||||
when (nextName()) {
|
|
||||||
TITLE -> track.title = nextString()
|
|
||||||
SYNC -> track.sync_id = nextInt()
|
|
||||||
MEDIA -> track.media_id = nextInt()
|
|
||||||
LIBRARY -> track.library_id = nextLong()
|
|
||||||
LAST_READ -> track.last_chapter_read = nextInt()
|
|
||||||
TRACKING_URL -> track.tracking_url = nextString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
endObject()
|
|
||||||
track
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,67 @@
|
|||||||
|
package eu.kanade.tachiyomi.data.backup.legacy.serializer
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||||
|
import kotlinx.serialization.KSerializer
|
||||||
|
import kotlinx.serialization.descriptors.SerialDescriptor
|
||||||
|
import kotlinx.serialization.descriptors.buildClassSerialDescriptor
|
||||||
|
import kotlinx.serialization.encoding.Decoder
|
||||||
|
import kotlinx.serialization.encoding.Encoder
|
||||||
|
import kotlinx.serialization.json.JsonDecoder
|
||||||
|
import kotlinx.serialization.json.JsonEncoder
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.int
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.long
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON Serializer used to write / read [TrackImpl] to / from json
|
||||||
|
*/
|
||||||
|
open class TrackBaseSerializer<T : Track> : KSerializer<T> {
|
||||||
|
override val descriptor: SerialDescriptor = buildClassSerialDescriptor("Track")
|
||||||
|
|
||||||
|
override fun serialize(encoder: Encoder, value: T) {
|
||||||
|
encoder as JsonEncoder
|
||||||
|
encoder.encodeJsonElement(
|
||||||
|
buildJsonObject {
|
||||||
|
put(TITLE, value.title)
|
||||||
|
put(SYNC, value.sync_id)
|
||||||
|
put(MEDIA, value.media_id)
|
||||||
|
put(LIBRARY, value.library_id)
|
||||||
|
put(LAST_READ, value.last_chapter_read)
|
||||||
|
put(TRACKING_URL, value.tracking_url)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
override fun deserialize(decoder: Decoder): T {
|
||||||
|
// make a track impl and cast as T so that the serializer accepts it
|
||||||
|
return TrackImpl().apply {
|
||||||
|
decoder as JsonDecoder
|
||||||
|
val jsonObject = decoder.decodeJsonElement().jsonObject
|
||||||
|
title = jsonObject[TITLE]!!.jsonPrimitive.content
|
||||||
|
sync_id = jsonObject[SYNC]!!.jsonPrimitive.int
|
||||||
|
media_id = jsonObject[MEDIA]!!.jsonPrimitive.int
|
||||||
|
library_id = jsonObject[LIBRARY]!!.jsonPrimitive.long
|
||||||
|
last_chapter_read = jsonObject[LAST_READ]!!.jsonPrimitive.int
|
||||||
|
tracking_url = jsonObject[TRACKING_URL]!!.jsonPrimitive.content
|
||||||
|
} as T
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val SYNC = "s"
|
||||||
|
private const val MEDIA = "r"
|
||||||
|
private const val LIBRARY = "ml"
|
||||||
|
private const val TITLE = "t"
|
||||||
|
private const val LAST_READ = "l"
|
||||||
|
private const val TRACKING_URL = "u"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow for serialization of a track and track impl
|
||||||
|
object TrackTypeSerializer : TrackBaseSerializer<Track>()
|
||||||
|
|
||||||
|
object TrackImplTypeSerializer : TrackBaseSerializer<TrackImpl>()
|
@ -3,9 +3,6 @@ package eu.kanade.tachiyomi.data.backup
|
|||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import com.github.salomonbrys.kotson.fromJson
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner
|
import eu.kanade.tachiyomi.CustomRobolectricGradleTestRunner
|
||||||
import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager
|
import eu.kanade.tachiyomi.data.backup.legacy.LegacyBackupManager
|
||||||
@ -17,12 +14,16 @@ import eu.kanade.tachiyomi.data.database.models.Chapter
|
|||||||
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
import eu.kanade.tachiyomi.data.database.models.ChapterImpl
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
import eu.kanade.tachiyomi.data.database.models.MangaImpl
|
||||||
|
import eu.kanade.tachiyomi.data.database.models.Track
|
||||||
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
import eu.kanade.tachiyomi.data.database.models.TrackImpl
|
||||||
import eu.kanade.tachiyomi.source.SourceManager
|
import eu.kanade.tachiyomi.source.SourceManager
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
import eu.kanade.tachiyomi.ui.reader.setting.OrientationType
|
||||||
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
import eu.kanade.tachiyomi.ui.reader.setting.ReadingModeType
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import org.assertj.core.api.Assertions.assertThat
|
import org.assertj.core.api.Assertions.assertThat
|
||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
@ -47,16 +48,10 @@ import uy.kohesive.injekt.api.addSingleton
|
|||||||
@RunWith(CustomRobolectricGradleTestRunner::class)
|
@RunWith(CustomRobolectricGradleTestRunner::class)
|
||||||
class BackupTest {
|
class BackupTest {
|
||||||
// Create root object
|
// Create root object
|
||||||
var root = JsonObject()
|
var root = Backup()
|
||||||
|
|
||||||
// Create information object
|
// Create information object
|
||||||
var information = JsonObject()
|
var information = buildJsonObject {}
|
||||||
|
|
||||||
// Create manga array
|
|
||||||
var mangaEntries = JsonArray()
|
|
||||||
|
|
||||||
// Create category array
|
|
||||||
var categoryEntries = JsonArray()
|
|
||||||
|
|
||||||
lateinit var app: Application
|
lateinit var app: Application
|
||||||
lateinit var context: Context
|
lateinit var context: Context
|
||||||
@ -83,11 +78,6 @@ class BackupTest {
|
|||||||
|
|
||||||
source = mock(HttpSource::class.java)
|
source = mock(HttpSource::class.java)
|
||||||
`when`(legacyBackupManager.sourceManager.get(anyLong())).thenReturn(source)
|
`when`(legacyBackupManager.sourceManager.get(anyLong())).thenReturn(source)
|
||||||
|
|
||||||
root.add(Backup.MANGAS, mangaEntries)
|
|
||||||
root.add(Backup.CATEGORIES, categoryEntries)
|
|
||||||
|
|
||||||
clearJson()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -95,11 +85,8 @@ class BackupTest {
|
|||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
fun testRestoreEmptyCategory() {
|
fun testRestoreEmptyCategory() {
|
||||||
// Create backup of empty database
|
|
||||||
legacyBackupManager.backupCategories(categoryEntries)
|
|
||||||
|
|
||||||
// Restore Json
|
// Restore Json
|
||||||
legacyBackupManager.restoreCategories(categoryEntries)
|
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
||||||
|
|
||||||
// Check if empty
|
// Check if empty
|
||||||
val dbCats = db.getCategories().executeAsBlocking()
|
val dbCats = db.getCategories().executeAsBlocking()
|
||||||
@ -115,7 +102,7 @@ class BackupTest {
|
|||||||
val category = addSingleCategory("category")
|
val category = addSingleCategory("category")
|
||||||
|
|
||||||
// Restore Json
|
// Restore Json
|
||||||
legacyBackupManager.restoreCategories(categoryEntries)
|
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
||||||
|
|
||||||
// Check if successful
|
// Check if successful
|
||||||
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
||||||
@ -139,7 +126,7 @@ class BackupTest {
|
|||||||
db.insertCategory(category).executeAsBlocking()
|
db.insertCategory(category).executeAsBlocking()
|
||||||
|
|
||||||
// Restore Json
|
// Restore Json
|
||||||
legacyBackupManager.restoreCategories(categoryEntries)
|
legacyBackupManager.restoreCategories(root.categories ?: emptyList())
|
||||||
|
|
||||||
// Check if successful
|
// Check if successful
|
||||||
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
val dbCats = legacyBackupManager.databaseHelper.getCategories().executeAsBlocking()
|
||||||
@ -167,9 +154,6 @@ class BackupTest {
|
|||||||
assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
|
assertThat(favoriteManga[0].readingModeType).isEqualTo(ReadingModeType.VERTICAL.flagValue)
|
||||||
assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
|
assertThat(favoriteManga[0].orientationType).isEqualTo(OrientationType.PORTRAIT.flagValue)
|
||||||
|
|
||||||
// Update json with all options enabled
|
|
||||||
mangaEntries.add(legacyBackupManager.backupMangaObject(manga, 1))
|
|
||||||
|
|
||||||
// Change manga in database to default values
|
// Change manga in database to default values
|
||||||
val dbManga = getSingleManga("One Piece")
|
val dbManga = getSingleManga("One Piece")
|
||||||
dbManga.id = manga.id
|
dbManga.id = manga.id
|
||||||
@ -198,9 +182,9 @@ class BackupTest {
|
|||||||
|
|
||||||
// Restore Json
|
// Restore Json
|
||||||
// Create JSON from manga to test parser
|
// Create JSON from manga to test parser
|
||||||
val json = legacyBackupManager.parser.toJsonTree(manga)
|
val json = legacyBackupManager.parser.encodeToString(manga)
|
||||||
// Restore JSON from manga to test parser
|
// Restore JSON from manga to test parser
|
||||||
val jsonManga = legacyBackupManager.parser.fromJson<MangaImpl>(json)
|
val jsonManga = legacyBackupManager.parser.decodeFromString<Manga>(json)
|
||||||
|
|
||||||
// Restore manga with fetch observable
|
// Restore manga with fetch observable
|
||||||
val networkManga = getSingleManga("One Piece")
|
val networkManga = getSingleManga("One Piece")
|
||||||
@ -237,8 +221,8 @@ class BackupTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check parser
|
// Check parser
|
||||||
val chaptersJson = legacyBackupManager.parser.toJsonTree(chapters)
|
val chaptersJson = legacyBackupManager.parser.encodeToString(chapters)
|
||||||
val restoredChapters = legacyBackupManager.parser.fromJson<List<ChapterImpl>>(chaptersJson)
|
val restoredChapters = legacyBackupManager.parser.decodeFromString<List<Chapter>>(chaptersJson)
|
||||||
|
|
||||||
// Fetch chapters from upstream
|
// Fetch chapters from upstream
|
||||||
// Create list
|
// Create list
|
||||||
@ -275,8 +259,8 @@ class BackupTest {
|
|||||||
historyList.add(historyJson)
|
historyList.add(historyJson)
|
||||||
|
|
||||||
// Check parser
|
// Check parser
|
||||||
val historyListJson = legacyBackupManager.parser.toJsonTree(historyList)
|
val historyListJson = legacyBackupManager.parser.encodeToString(historyList)
|
||||||
val history = legacyBackupManager.parser.fromJson<List<DHistory>>(historyListJson)
|
val history = legacyBackupManager.parser.decodeFromString<List<DHistory>>(historyListJson)
|
||||||
|
|
||||||
// Restore categories
|
// Restore categories
|
||||||
legacyBackupManager.restoreHistoryForManga(history)
|
legacyBackupManager.restoreHistoryForManga(history)
|
||||||
@ -314,8 +298,8 @@ class BackupTest {
|
|||||||
// Check parser and restore already in database
|
// Check parser and restore already in database
|
||||||
var trackList = listOf(track)
|
var trackList = listOf(track)
|
||||||
// Check parser
|
// Check parser
|
||||||
var trackListJson = legacyBackupManager.parser.toJsonTree(trackList)
|
var trackListJson = legacyBackupManager.parser.encodeToString(trackList)
|
||||||
var trackListRestore = legacyBackupManager.parser.fromJson<List<TrackImpl>>(trackListJson)
|
var trackListRestore = legacyBackupManager.parser.decodeFromString<List<Track>>(trackListJson)
|
||||||
legacyBackupManager.restoreTrackForManga(manga, trackListRestore)
|
legacyBackupManager.restoreTrackForManga(manga, trackListRestore)
|
||||||
|
|
||||||
// Assert if restore works.
|
// Assert if restore works.
|
||||||
@ -337,8 +321,8 @@ class BackupTest {
|
|||||||
trackList = listOf(track2)
|
trackList = listOf(track2)
|
||||||
|
|
||||||
// Check parser
|
// Check parser
|
||||||
trackListJson = legacyBackupManager.parser.toJsonTree(trackList)
|
trackListJson = legacyBackupManager.parser.encodeToString(trackList)
|
||||||
trackListRestore = legacyBackupManager.parser.fromJson<List<TrackImpl>>(trackListJson)
|
trackListRestore = legacyBackupManager.parser.decodeFromString<List<Track>>(trackListJson)
|
||||||
legacyBackupManager.restoreTrackForManga(manga2, trackListRestore)
|
legacyBackupManager.restoreTrackForManga(manga2, trackListRestore)
|
||||||
|
|
||||||
// Assert if restore works.
|
// Assert if restore works.
|
||||||
@ -348,16 +332,13 @@ class BackupTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun clearJson() {
|
private fun clearJson() {
|
||||||
root = JsonObject()
|
root = Backup()
|
||||||
information = JsonObject()
|
information = buildJsonObject {}
|
||||||
mangaEntries = JsonArray()
|
|
||||||
categoryEntries = JsonArray()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addSingleCategory(name: String): Category {
|
private fun addSingleCategory(name: String): Category {
|
||||||
val category = Category.create(name)
|
val category = Category.create(name)
|
||||||
val catJson = legacyBackupManager.parser.toJsonTree(category)
|
root.categories = listOf(category)
|
||||||
categoryEntries.add(catJson)
|
|
||||||
return category
|
return category
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user