[Komga] replace gson with kotlinx.serialization.json (#9107)

* annotate komga data classes

annotate @Serializable to relevant data classes. this is the first step
to replace gson/kotson with kotlinx.serialization

* switch to kotlinx.serialization.json

replaces gson/kotson usage in komga extension
big thanks to gotson for already switching to data classes
made the conversion very simple

Co-authored-by: Gauthier <gotson@users.noreply.github.com>

* linting

* increment komga.extversioncode

also update changelog

* use .string() instead of toString()

since we actually need the object in memory as a string rather than the
content

* apply plugin to generate Serializable

this makes serializers for all data classes that are annotated as
Serializable

Co-authored-by: Gauthier <gotson@users.noreply.github.com>
This commit is contained in:
nicki 2021-09-18 15:09:18 +05:30 committed by GitHub
parent 5b406c58a5
commit 95ad8cb431
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 42 additions and 16 deletions

View File

@ -1,3 +1,11 @@
## 1.2.31
Minimum Komga version required: `0.113.0`
### Refactor
* replace Gson with kotlinx.serialization
## 1.2.30 ## 1.2.30
Minimum Komga version required: `0.113.0` Minimum Komga version required: `0.113.0`

View File

@ -1,11 +1,12 @@
apply plugin: 'com.android.application' apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext { ext {
extName = 'Komga' extName = 'Komga'
pkgNameSuffix = 'all.komga' pkgNameSuffix = 'all.komga'
extClass = '.KomgaFactory' extClass = '.KomgaFactory'
extVersionCode = 30 extVersionCode = 31
} }
dependencies { dependencies {

View File

@ -5,8 +5,6 @@ import android.content.SharedPreferences
import android.text.InputType import android.text.InputType
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import com.github.salomonbrys.kotson.fromJson
import com.google.gson.Gson
import eu.kanade.tachiyomi.extension.BuildConfig import eu.kanade.tachiyomi.extension.BuildConfig
import eu.kanade.tachiyomi.extension.all.komga.dto.AuthorDto import eu.kanade.tachiyomi.extension.all.komga.dto.AuthorDto
import eu.kanade.tachiyomi.extension.all.komga.dto.BookDto import eu.kanade.tachiyomi.extension.all.komga.dto.BookDto
@ -25,6 +23,8 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Credentials import okhttp3.Credentials
import okhttp3.Dns import okhttp3.Dns
import okhttp3.Headers import okhttp3.Headers
@ -37,6 +37,7 @@ import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
@ -177,10 +178,10 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
override fun mangaDetailsParse(response: Response): SManga = override fun mangaDetailsParse(response: Response): SManga =
if (response.fromReadList()) { if (response.fromReadList()) {
val readList = gson.fromJson<ReadListDto>(response.body?.charStream()!!) val readList = json.decodeFromString<ReadListDto>(response.body?.string()!!)
readList.toSManga() readList.toSManga()
} else { } else {
val series = gson.fromJson<SeriesDto>(response.body?.charStream()!!) val series = json.decodeFromString<SeriesDto>(response.body?.string()!!)
series.toSManga() series.toSManga()
} }
@ -188,7 +189,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
GET("${manga.url}/books?unpaged=true&media_status=READY&deleted=false", headers) GET("${manga.url}/books?unpaged=true&media_status=READY&deleted=false", headers)
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val page = gson.fromJson<PageWrapperDto<BookDto>>(response.body?.charStream()!!).content val page = json.decodeFromString<PageWrapperDto<BookDto>>(response.body?.string()!!).content
val r = page.mapIndexed { index, book -> val r = page.mapIndexed { index, book ->
SChapter.create().apply { SChapter.create().apply {
@ -206,7 +207,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
GET("${chapter.url}/pages") GET("${chapter.url}/pages")
override fun pageListParse(response: Response): List<Page> { override fun pageListParse(response: Response): List<Page> {
val pages = gson.fromJson<List<PageDto>>(response.body?.charStream()!!) val pages = json.decodeFromString<List<PageDto>>(response.body?.string()!!)
return pages.map { return pages.map {
val url = "${response.request.url}/${it.number}" + val url = "${response.request.url}/${it.number}" +
if (!supportedImageTypes.contains(it.mediaType)) { if (!supportedImageTypes.contains(it.mediaType)) {
@ -223,11 +224,11 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
private fun processSeriesPage(response: Response): MangasPage { private fun processSeriesPage(response: Response): MangasPage {
if (response.fromReadList()) { if (response.fromReadList()) {
with(gson.fromJson<PageWrapperDto<ReadListDto>>(response.body?.charStream()!!)) { with(json.decodeFromString<PageWrapperDto<ReadListDto>>(response.body?.string()!!)) {
return MangasPage(content.map { it.toSManga() }, !last) return MangasPage(content.map { it.toSManga() }, !last)
} }
} else { } else {
with(gson.fromJson<PageWrapperDto<SeriesDto>>(response.body?.charStream()!!)) { with(json.decodeFromString<PageWrapperDto<SeriesDto>>(response.body?.string()!!)) {
return MangasPage(content.map { it.toSManga() }, !last) return MangasPage(content.map { it.toSManga() }, !last)
} }
} }
@ -356,7 +357,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
override val baseUrl by lazy { getPrefBaseUrl() } override val baseUrl by lazy { getPrefBaseUrl() }
private val username by lazy { getPrefUsername() } private val username by lazy { getPrefUsername() }
private val password by lazy { getPrefPassword() } private val password by lazy { getPrefPassword() }
private val gson by lazy { Gson() } private val json: Json by injectLazy()
override fun headersBuilder(): Headers.Builder = override fun headersBuilder(): Headers.Builder =
Headers.Builder() Headers.Builder()
@ -427,7 +428,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
.subscribe( .subscribe(
{ response -> { response ->
libraries = try { libraries = try {
gson.fromJson(response.body?.charStream()!!) json.decodeFromString(response.body?.string()!!)
} catch (e: Exception) { } catch (e: Exception) {
emptyList() emptyList()
} }
@ -445,7 +446,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
.subscribe( .subscribe(
{ response -> { response ->
collections = try { collections = try {
gson.fromJson<PageWrapperDto<CollectionDto>>(response.body?.charStream()!!).content json.decodeFromString<PageWrapperDto<CollectionDto>>(response.body?.string()!!).content
} catch (e: Exception) { } catch (e: Exception) {
emptyList() emptyList()
} }
@ -463,7 +464,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
.subscribe( .subscribe(
{ response -> { response ->
genres = try { genres = try {
gson.fromJson(response.body?.charStream()!!) json.decodeFromString(response.body?.string()!!)
} catch (e: Exception) { } catch (e: Exception) {
emptySet() emptySet()
} }
@ -481,7 +482,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
.subscribe( .subscribe(
{ response -> { response ->
tags = try { tags = try {
gson.fromJson(response.body?.charStream()!!) json.decodeFromString(response.body?.string()!!)
} catch (e: Exception) { } catch (e: Exception) {
emptySet() emptySet()
} }
@ -499,7 +500,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
.subscribe( .subscribe(
{ response -> { response ->
publishers = try { publishers = try {
gson.fromJson(response.body?.charStream()!!) json.decodeFromString(response.body?.string()!!)
} catch (e: Exception) { } catch (e: Exception) {
emptySet() emptySet()
} }
@ -517,7 +518,7 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
.subscribe( .subscribe(
{ response -> { response ->
authors = try { authors = try {
val list: List<AuthorDto> = gson.fromJson(response.body?.charStream()!!) val list: List<AuthorDto> = json.decodeFromString(response.body?.string()!!)
list.groupBy { it.role } list.groupBy { it.role }
} catch (e: Exception) { } catch (e: Exception) {
emptyMap() emptyMap()

View File

@ -1,10 +1,14 @@
package eu.kanade.tachiyomi.extension.all.komga.dto package eu.kanade.tachiyomi.extension.all.komga.dto
import kotlinx.serialization.Serializable
@Serializable
data class LibraryDto( data class LibraryDto(
val id: String, val id: String,
val name: String val name: String
) )
@Serializable
data class SeriesDto( data class SeriesDto(
val id: String, val id: String,
val libraryId: String, val libraryId: String,
@ -17,6 +21,7 @@ data class SeriesDto(
val booksMetadata: BookMetadataAggregationDto val booksMetadata: BookMetadataAggregationDto
) )
@Serializable
data class SeriesMetadataDto( data class SeriesMetadataDto(
val status: String, val status: String,
val created: String?, val created: String?,
@ -39,6 +44,7 @@ data class SeriesMetadataDto(
val tagsLock: Boolean val tagsLock: Boolean
) )
@Serializable
data class BookMetadataAggregationDto( data class BookMetadataAggregationDto(
val authors: List<AuthorDto> = emptyList(), val authors: List<AuthorDto> = emptyList(),
val tags: Set<String> = emptySet(), val tags: Set<String> = emptySet(),
@ -50,6 +56,7 @@ data class BookMetadataAggregationDto(
val lastModified: String val lastModified: String
) )
@Serializable
data class BookDto( data class BookDto(
val id: String, val id: String,
val seriesId: String, val seriesId: String,
@ -64,18 +71,21 @@ data class BookDto(
val metadata: BookMetadataDto val metadata: BookMetadataDto
) )
@Serializable
data class MediaDto( data class MediaDto(
val status: String, val status: String,
val mediaType: String, val mediaType: String,
val pagesCount: Int val pagesCount: Int
) )
@Serializable
data class PageDto( data class PageDto(
val number: Int, val number: Int,
val fileName: String, val fileName: String,
val mediaType: String val mediaType: String
) )
@Serializable
data class BookMetadataDto( data class BookMetadataDto(
val title: String, val title: String,
val titleLock: Boolean, val titleLock: Boolean,
@ -91,11 +101,13 @@ data class BookMetadataDto(
val authorsLock: Boolean val authorsLock: Boolean
) )
@Serializable
data class AuthorDto( data class AuthorDto(
val name: String, val name: String,
val role: String val role: String
) )
@Serializable
data class CollectionDto( data class CollectionDto(
val id: String, val id: String,
val name: String, val name: String,
@ -106,6 +118,7 @@ data class CollectionDto(
val filtered: Boolean val filtered: Boolean
) )
@Serializable
data class ReadListDto( data class ReadListDto(
val id: String, val id: String,
val name: String, val name: String,

View File

@ -1,5 +1,8 @@
package eu.kanade.tachiyomi.extension.all.komga.dto package eu.kanade.tachiyomi.extension.all.komga.dto
import kotlinx.serialization.Serializable
@Serializable
data class PageWrapperDto<T>( data class PageWrapperDto<T>(
val content: List<T>, val content: List<T>,
val empty: Boolean, val empty: Boolean,