Singleton instance of Json serializer

This commit is contained in:
arkon 2020-11-01 15:12:16 -05:00
parent 9b10e851d1
commit d21c147203
11 changed files with 57 additions and 26 deletions

View File

@ -13,6 +13,7 @@ import eu.kanade.tachiyomi.network.NetworkHelper
import eu.kanade.tachiyomi.source.SourceManager import eu.kanade.tachiyomi.source.SourceManager
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import uy.kohesive.injekt.api.InjektModule import uy.kohesive.injekt.api.InjektModule
import uy.kohesive.injekt.api.InjektRegistrar import uy.kohesive.injekt.api.InjektRegistrar
import uy.kohesive.injekt.api.addSingleton import uy.kohesive.injekt.api.addSingleton
@ -44,6 +45,8 @@ class AppModule(val app: Application) : InjektModule {
addSingletonFactory { Gson() } addSingletonFactory { Gson() }
addSingletonFactory { Json { ignoreUnknownKeys = true } }
// Asynchronously init expensive components for a faster cold start // Asynchronously init expensive components for a faster cold start
GlobalScope.launch { get<PreferencesHelper>() } GlobalScope.launch { get<PreferencesHelper>() }

View File

@ -8,6 +8,7 @@ import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import uy.kohesive.injekt.injectLazy
/** /**
* Class used to keep a list of chapters for future deletion. * Class used to keep a list of chapters for future deletion.
@ -16,6 +17,8 @@ import kotlinx.serialization.json.Json
*/ */
class DownloadPendingDeleter(context: Context) { class DownloadPendingDeleter(context: Context) {
private val json: Json by injectLazy()
/** /**
* Preferences used to store the list of chapters to delete. * Preferences used to store the list of chapters to delete.
*/ */
@ -49,7 +52,7 @@ class DownloadPendingDeleter(context: Context) {
val existingEntry = preferences.getString(manga.id!!.toString(), null) val existingEntry = preferences.getString(manga.id!!.toString(), null)
if (existingEntry != null) { if (existingEntry != null) {
// Existing entry found on preferences, decode json and add the new chapter // Existing entry found on preferences, decode json and add the new chapter
val savedEntry = Json.decodeFromString<Entry>(existingEntry) val savedEntry = json.decodeFromString<Entry>(existingEntry)
// Append new chapters // Append new chapters
val newChapters = savedEntry.chapters.addUniqueById(chapters) val newChapters = savedEntry.chapters.addUniqueById(chapters)
@ -65,7 +68,7 @@ class DownloadPendingDeleter(context: Context) {
} }
// Save current state // Save current state
val json = Json.encodeToString(newEntry) val json = json.encodeToString(newEntry)
preferences.edit { preferences.edit {
putString(newEntry.manga.id.toString(), json) putString(newEntry.manga.id.toString(), json)
} }
@ -97,7 +100,7 @@ class DownloadPendingDeleter(context: Context) {
private fun decodeAll(): List<Entry> { private fun decodeAll(): List<Entry> {
return preferences.all.values.mapNotNull { rawEntry -> return preferences.all.values.mapNotNull { rawEntry ->
try { try {
(rawEntry as? String)?.let { Json.decodeFromString<Entry>(it) } (rawEntry as? String)?.let { json.decodeFromString<Entry>(it) }
} catch (e: Exception) { } catch (e: Exception) {
null null
} }

View File

@ -28,6 +28,7 @@ class DownloadStore(
*/ */
private val preferences = context.getSharedPreferences("active_downloads", Context.MODE_PRIVATE) private val preferences = context.getSharedPreferences("active_downloads", Context.MODE_PRIVATE)
private val json: Json by injectLazy()
private val db: DatabaseHelper by injectLazy() private val db: DatabaseHelper by injectLazy()
/** /**
@ -109,7 +110,7 @@ class DownloadStore(
*/ */
private fun serialize(download: Download): String { private fun serialize(download: Download): String {
val obj = DownloadObject(download.manga.id!!, download.chapter.id!!, counter++) val obj = DownloadObject(download.manga.id!!, download.chapter.id!!, counter++)
return Json.encodeToString(obj) return json.encodeToString(obj)
} }
/** /**
@ -119,7 +120,7 @@ class DownloadStore(
*/ */
private fun deserialize(string: String): DownloadObject? { private fun deserialize(string: String): DownloadObject? {
return try { return try {
Json.decodeFromString<DownloadObject>(string) json.decodeFromString<DownloadObject>(string)
} catch (e: Exception) { } catch (e: Exception) {
null null
} }

View File

@ -11,6 +11,7 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import rx.Completable import rx.Completable
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
class Anilist(private val context: Context, id: Int) : TrackService(id) { class Anilist(private val context: Context, id: Int) : TrackService(id) {
@ -34,6 +35,8 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
override val name = "AniList" override val name = "AniList"
private val json: Json by injectLazy()
private val interceptor by lazy { AnilistInterceptor(this, getPassword()) } private val interceptor by lazy { AnilistInterceptor(this, getPassword()) }
private val api by lazy { AnilistApi(client, interceptor) } private val api by lazy { AnilistApi(client, interceptor) }
@ -196,12 +199,12 @@ class Anilist(private val context: Context, id: Int) : TrackService(id) {
} }
fun saveOAuth(oAuth: OAuth?) { fun saveOAuth(oAuth: OAuth?) {
preferences.trackToken(this).set(Json.encodeToString(oAuth)) preferences.trackToken(this).set(json.encodeToString(oAuth))
} }
fun loadOAuth(): OAuth? { fun loadOAuth(): OAuth? {
return try { return try {
Json.decodeFromString<OAuth>(preferences.trackToken(this).get()) json.decodeFromString<OAuth>(preferences.trackToken(this).get())
} catch (e: Exception) { } catch (e: Exception) {
null null
} }

View File

@ -23,10 +23,13 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.util.Calendar import java.util.Calendar
class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) { class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
private val json: Json by injectLazy()
private val jsonMime = "application/json; charset=utf-8".toMediaTypeOrNull() private val jsonMime = "application/json; charset=utf-8".toMediaTypeOrNull()
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
@ -61,7 +64,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
val response = Json.decodeFromString<JsonObject>(responseBody) val response = json.decodeFromString<JsonObject>(responseBody)
track.library_id = response["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long track.library_id = response["data"]!!.jsonObject["SaveMediaListEntry"]!!.jsonObject["id"]!!.jsonPrimitive.long
track track
} }
@ -143,7 +146,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
val response = Json.decodeFromString<JsonObject>(responseBody) val response = json.decodeFromString<JsonObject>(responseBody)
val data = response["data"]!!.jsonObject val data = response["data"]!!.jsonObject
val page = data["Page"]!!.jsonObject val page = data["Page"]!!.jsonObject
val media = page["media"]!!.jsonArray val media = page["media"]!!.jsonArray
@ -203,7 +206,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
val response = Json.decodeFromString<JsonObject>(responseBody) val response = json.decodeFromString<JsonObject>(responseBody)
val data = response["data"]!!.jsonObject val data = response["data"]!!.jsonObject
val page = data["Page"]!!.jsonObject val page = data["Page"]!!.jsonObject
val media = page["mediaList"]!!.jsonArray val media = page["mediaList"]!!.jsonArray
@ -248,7 +251,7 @@ class AnilistApi(val client: OkHttpClient, interceptor: AnilistInterceptor) {
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
val response = Json.decodeFromString<JsonObject>(responseBody) val response = json.decodeFromString<JsonObject>(responseBody)
val data = response["data"]!!.jsonObject val data = response["data"]!!.jsonObject
val viewer = data["Viewer"]!!.jsonObject val viewer = data["Viewer"]!!.jsonObject
Pair(viewer["id"]!!.jsonPrimitive.int, viewer["mediaListOptions"]!!.jsonObject["scoreFormat"]!!.jsonPrimitive.content) Pair(viewer["id"]!!.jsonPrimitive.int, viewer["mediaListOptions"]!!.jsonObject["scoreFormat"]!!.jsonPrimitive.content)

View File

@ -11,11 +11,14 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import rx.Completable import rx.Completable
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
class Bangumi(private val context: Context, id: Int) : TrackService(id) { class Bangumi(private val context: Context, id: Int) : TrackService(id) {
override val name = "Bangumi" override val name = "Bangumi"
private val json: Json by injectLazy()
private val interceptor by lazy { BangumiInterceptor(this) } private val interceptor by lazy { BangumiInterceptor(this) }
private val api by lazy { BangumiApi(client, interceptor) } private val api by lazy { BangumiApi(client, interceptor) }
@ -111,12 +114,12 @@ class Bangumi(private val context: Context, id: Int) : TrackService(id) {
} }
fun saveToken(oauth: OAuth?) { fun saveToken(oauth: OAuth?) {
preferences.trackToken(this).set(Json.encodeToString(oauth)) preferences.trackToken(this).set(json.encodeToString(oauth))
} }
fun restoreToken(): OAuth? { fun restoreToken(): OAuth? {
return try { return try {
Json.decodeFromString<OAuth>(preferences.trackToken(this).get()) json.decodeFromString<OAuth>(preferences.trackToken(this).get())
} catch (e: Exception) { } catch (e: Exception) {
null null
} }

View File

@ -20,10 +20,13 @@ import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.net.URLEncoder import java.net.URLEncoder
class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) { class BangumiApi(private val client: OkHttpClient, interceptor: BangumiInterceptor) {
private val json: Json by injectLazy()
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
fun addLibManga(track: Track): Observable<Track> { fun addLibManga(track: Track): Observable<Track> {
@ -93,7 +96,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
if (responseBody.contains("\"code\":404")) { if (responseBody.contains("\"code\":404")) {
responseBody = "{\"results\":0,\"list\":[]}" responseBody = "{\"results\":0,\"list\":[]}"
} }
val response = Json.decodeFromString<JsonObject>(responseBody)["list"]?.jsonArray val response = json.decodeFromString<JsonObject>(responseBody)["list"]?.jsonArray
response?.filter { it.jsonObject["type"]?.jsonPrimitive?.int == 1 }?.map { jsonToSearch(it.jsonObject) } response?.filter { it.jsonObject["type"]?.jsonPrimitive?.int == 1 }?.map { jsonToSearch(it.jsonObject) }
} }
} }
@ -134,7 +137,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
.map { netResponse -> .map { netResponse ->
// get comic info // get comic info
val responseBody = netResponse.body?.string().orEmpty() val responseBody = netResponse.body?.string().orEmpty()
jsonToTrack(Json.decodeFromString(responseBody)) jsonToTrack(json.decodeFromString(responseBody))
} }
} }
@ -151,7 +154,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
.asObservableSuccess() .asObservableSuccess()
.map { netResponse -> .map { netResponse ->
val resp = netResponse.body?.string() val resp = netResponse.body?.string()
val coll = Json { ignoreUnknownKeys = true }.decodeFromString<Collection>(resp!!) val coll = json.decodeFromString<Collection>(resp!!)
track.status = coll.status?.id!! track.status = coll.status?.id!!
track.last_chapter_read = coll.ep_status!! track.last_chapter_read = coll.ep_status!!
track track
@ -164,7 +167,7 @@ class BangumiApi(private val client: OkHttpClient, interceptor: BangumiIntercept
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
Json { ignoreUnknownKeys = true }.decodeFromString<OAuth>(responseBody) json.decodeFromString<OAuth>(responseBody)
} }
} }

View File

@ -5,9 +5,12 @@ import kotlinx.serialization.json.Json
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class BangumiInterceptor(val bangumi: Bangumi) : Interceptor { class BangumiInterceptor(val bangumi: Bangumi) : Interceptor {
private val json: Json by injectLazy()
/** /**
* OAuth object used for authenticated requests. * OAuth object used for authenticated requests.
*/ */
@ -30,7 +33,7 @@ class BangumiInterceptor(val bangumi: Bangumi) : Interceptor {
if (currAuth.isExpired()) { if (currAuth.isExpired()) {
val response = chain.proceed(BangumiApi.refreshTokenRequest(currAuth.refresh_token!!)) val response = chain.proceed(BangumiApi.refreshTokenRequest(currAuth.refresh_token!!))
if (response.isSuccessful) { if (response.isSuccessful) {
newAuth(Json { ignoreUnknownKeys = true }.decodeFromString<OAuth>(response.body!!.string())) newAuth(json.decodeFromString<OAuth>(response.body!!.string()))
} else { } else {
response.close() response.close()
} }

View File

@ -11,6 +11,7 @@ import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import rx.Completable import rx.Completable
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
class Shikimori(private val context: Context, id: Int) : TrackService(id) { class Shikimori(private val context: Context, id: Int) : TrackService(id) {
@ -28,6 +29,8 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
override val name = "Shikimori" override val name = "Shikimori"
private val json: Json by injectLazy()
private val interceptor by lazy { ShikimoriInterceptor(this) } private val interceptor by lazy { ShikimoriInterceptor(this) }
private val api by lazy { ShikimoriApi(client, interceptor) } private val api by lazy { ShikimoriApi(client, interceptor) }
@ -116,12 +119,12 @@ class Shikimori(private val context: Context, id: Int) : TrackService(id) {
} }
fun saveToken(oauth: OAuth?) { fun saveToken(oauth: OAuth?) {
preferences.trackToken(this).set(Json.encodeToString(oauth)) preferences.trackToken(this).set(json.encodeToString(oauth))
} }
fun restoreToken(): OAuth? { fun restoreToken(): OAuth? {
return try { return try {
Json.decodeFromString<OAuth>(preferences.trackToken(this).get()) json.decodeFromString<OAuth>(preferences.trackToken(this).get())
} catch (e: Exception) { } catch (e: Exception) {
null null
} }

View File

@ -24,9 +24,12 @@ import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import rx.Observable import rx.Observable
import uy.kohesive.injekt.injectLazy
class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInterceptor) { class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInterceptor) {
private val json: Json by injectLazy()
private val jsonime = "application/json; charset=utf-8".toMediaTypeOrNull() private val jsonime = "application/json; charset=utf-8".toMediaTypeOrNull()
private val authClient = client.newBuilder().addInterceptor(interceptor).build() private val authClient = client.newBuilder().addInterceptor(interceptor).build()
@ -72,7 +75,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
val response = Json.decodeFromString<JsonArray>(responseBody) val response = json.decodeFromString<JsonArray>(responseBody)
response.map { jsonToSearch(it.jsonObject) } response.map { jsonToSearch(it.jsonObject) }
} }
} }
@ -125,7 +128,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
.asObservableSuccess() .asObservableSuccess()
.map { netResponse -> .map { netResponse ->
val responseBody = netResponse.body?.string().orEmpty() val responseBody = netResponse.body?.string().orEmpty()
Json.decodeFromString<JsonObject>(responseBody) json.decodeFromString<JsonObject>(responseBody)
}.flatMap { mangas -> }.flatMap { mangas ->
authClient.newCall(request) authClient.newCall(request)
.asObservableSuccess() .asObservableSuccess()
@ -134,7 +137,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
val response = Json.decodeFromString<JsonArray>(responseBody) val response = json.decodeFromString<JsonArray>(responseBody)
if (response.size > 1) { if (response.size > 1) {
throw Exception("Too much mangas in response") throw Exception("Too much mangas in response")
} }
@ -148,7 +151,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
fun getCurrentUser(): Int { fun getCurrentUser(): Int {
val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body?.string()!! val user = authClient.newCall(GET("$apiUrl/users/whoami")).execute().body?.string()!!
return Json.decodeFromString<JsonObject>(user)["id"]!!.jsonPrimitive.int return json.decodeFromString<JsonObject>(user)["id"]!!.jsonPrimitive.int
} }
fun accessToken(code: String): Observable<OAuth> { fun accessToken(code: String): Observable<OAuth> {
@ -157,7 +160,7 @@ class ShikimoriApi(private val client: OkHttpClient, interceptor: ShikimoriInter
if (responseBody.isEmpty()) { if (responseBody.isEmpty()) {
throw Exception("Null Response") throw Exception("Null Response")
} }
Json { ignoreUnknownKeys = true }.decodeFromString<OAuth>(responseBody) json.decodeFromString<OAuth>(responseBody)
} }
} }

View File

@ -4,9 +4,12 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.Response import okhttp3.Response
import uy.kohesive.injekt.injectLazy
class ShikimoriInterceptor(val shikimori: Shikimori) : Interceptor { class ShikimoriInterceptor(val shikimori: Shikimori) : Interceptor {
private val json: Json by injectLazy()
/** /**
* OAuth object used for authenticated requests. * OAuth object used for authenticated requests.
*/ */
@ -23,7 +26,7 @@ class ShikimoriInterceptor(val shikimori: Shikimori) : Interceptor {
if (currAuth.isExpired()) { if (currAuth.isExpired()) {
val response = chain.proceed(ShikimoriApi.refreshTokenRequest(refreshToken)) val response = chain.proceed(ShikimoriApi.refreshTokenRequest(refreshToken))
if (response.isSuccessful) { if (response.isSuccessful) {
newAuth(Json.decodeFromString<OAuth>(response.body!!.string())) newAuth(json.decodeFromString<OAuth>(response.body!!.string()))
} else { } else {
response.close() response.close()
} }