Convert SY specific usages of Gson to Kotlin Serialization
Cleanup saved searches a bit Cleanup json parsing
This commit is contained in:
parent
bbfce97125
commit
f3365cef67
@ -2,20 +2,16 @@ package eu.kanade.tachiyomi.data.backup
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.fromJson
|
import com.github.salomonbrys.kotson.fromJson
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
import com.github.salomonbrys.kotson.jsonObject
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.registerTypeAdapter
|
import com.github.salomonbrys.kotson.registerTypeAdapter
|
||||||
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
|
import com.github.salomonbrys.kotson.registerTypeHierarchyAdapter
|
||||||
import com.github.salomonbrys.kotson.set
|
import com.github.salomonbrys.kotson.set
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
import com.google.gson.GsonBuilder
|
import com.google.gson.GsonBuilder
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonElement
|
import com.google.gson.JsonElement
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import com.hippo.unifile.UniFile
|
import com.hippo.unifile.UniFile
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY
|
import eu.kanade.tachiyomi.data.backup.BackupCreateService.Companion.BACKUP_CATEGORY
|
||||||
@ -62,13 +58,16 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.source.online.all.EHentai
|
import eu.kanade.tachiyomi.source.online.all.EHentai
|
||||||
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
import eu.kanade.tachiyomi.source.online.all.MergedSource
|
||||||
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
import eu.kanade.tachiyomi.util.chapter.syncChaptersWithSource
|
||||||
import exh.EXHSavedSearch
|
|
||||||
import exh.MERGED_SOURCE_ID
|
import exh.MERGED_SOURCE_ID
|
||||||
import exh.eh.EHentaiThrottleManager
|
import exh.eh.EHentaiThrottleManager
|
||||||
import exh.merged.sql.models.MergedMangaReference
|
import exh.merged.sql.models.MergedMangaReference
|
||||||
|
import exh.savedsearches.EXHSavedSearch
|
||||||
|
import exh.savedsearches.JsonSavedSearch
|
||||||
import exh.util.asObservable
|
import exh.util.asObservable
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@ -553,17 +552,17 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
|||||||
val newSavedSearches = backupSavedSearches.mapNotNull {
|
val newSavedSearches = backupSavedSearches.mapNotNull {
|
||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
val source = sourceManager.getOrStub(id)
|
val source = sourceManager.getOrStub(id)
|
||||||
if (source !is CatalogueSource) return@mapNotNull null
|
if (source !is CatalogueSource) return@mapNotNull null
|
||||||
|
|
||||||
val originalFilters = source.getFilterList()
|
val originalFilters = source.getFilterList()
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
filterSerializer.deserialize(originalFilters, content.filters)
|
||||||
Pair(
|
Pair(
|
||||||
id,
|
id,
|
||||||
EXHSavedSearch(
|
EXHSavedSearch(
|
||||||
content["name"].string,
|
content.name,
|
||||||
content["query"].string,
|
content.query,
|
||||||
originalFilters
|
originalFilters
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@ -580,18 +579,18 @@ class BackupManager(val context: Context, version: Int = CURRENT_VERSION) {
|
|||||||
newSavedSearches += preferences.eh_savedSearches().get().mapNotNull {
|
newSavedSearches += preferences.eh_savedSearches().get().mapNotNull {
|
||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
if (id !in currentSources) return@mapNotNull null
|
if (id !in currentSources) return@mapNotNull null
|
||||||
val source = sourceManager.getOrStub(id)
|
val source = sourceManager.getOrStub(id)
|
||||||
if (source !is CatalogueSource) return@mapNotNull null
|
if (source !is CatalogueSource) return@mapNotNull null
|
||||||
|
|
||||||
val originalFilters = source.getFilterList()
|
val originalFilters = source.getFilterList()
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
filterSerializer.deserialize(originalFilters, content.filters)
|
||||||
Pair(
|
Pair(
|
||||||
id,
|
id,
|
||||||
EXHSavedSearch(
|
EXHSavedSearch(
|
||||||
content["name"].string,
|
content.name,
|
||||||
content["query"].string,
|
content.query,
|
||||||
originalFilters
|
originalFilters
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -1,14 +1,19 @@
|
|||||||
package eu.kanade.tachiyomi.data.library
|
package eu.kanade.tachiyomi.data.library
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.github.salomonbrys.kotson.nullLong
|
|
||||||
import com.github.salomonbrys.kotson.nullString
|
|
||||||
import com.github.salomonbrys.kotson.set
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
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 kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonArray
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.contentOrNull
|
||||||
|
import kotlinx.serialization.json.encodeToJsonElement
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.longOrNull
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.util.Scanner
|
import java.util.Scanner
|
||||||
|
|
||||||
@ -28,25 +33,24 @@ class CustomMangaManager(val context: Context) {
|
|||||||
if (!editJson.exists() || !editJson.isFile) return
|
if (!editJson.exists() || !editJson.isFile) return
|
||||||
|
|
||||||
val json = try {
|
val json = try {
|
||||||
Gson().fromJson(
|
Json.decodeFromString<JsonObject>(
|
||||||
Scanner(editJson).useDelimiter("\\Z").next(),
|
Scanner(editJson).useDelimiter("\\Z").next()
|
||||||
JsonObject::class.java
|
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
} ?: return
|
} ?: return
|
||||||
|
|
||||||
val mangasJson = json.get("mangas").asJsonArray ?: return
|
val mangasJson = json["mangas"] as? JsonArray ?: return
|
||||||
customMangaMap = mangasJson.mapNotNull { element ->
|
customMangaMap = mangasJson.mapNotNull { element ->
|
||||||
val mangaObject = element.asJsonObject ?: return@mapNotNull null
|
val mangaObject = element as? JsonObject ?: return@mapNotNull null
|
||||||
val id = mangaObject["id"]?.nullLong ?: return@mapNotNull null
|
val id = mangaObject["id"]?.jsonPrimitive?.longOrNull ?: return@mapNotNull null
|
||||||
val manga = MangaImpl().apply {
|
val manga = MangaImpl().apply {
|
||||||
this.id = id
|
this.id = id
|
||||||
title = mangaObject["title"]?.nullString ?: ""
|
title = mangaObject["title"]?.jsonPrimitive?.contentOrNull ?: ""
|
||||||
author = mangaObject["author"]?.nullString
|
author = mangaObject["author"]?.jsonPrimitive?.contentOrNull
|
||||||
artist = mangaObject["artist"]?.nullString
|
artist = mangaObject["artist"]?.jsonPrimitive?.contentOrNull
|
||||||
description = mangaObject["description"]?.nullString
|
description = mangaObject["description"]?.jsonPrimitive?.contentOrNull
|
||||||
genre = mangaObject["genre"]?.asJsonArray?.mapNotNull { it.nullString }
|
genre = (mangaObject["genre"] as? JsonArray)?.mapNotNull { it.jsonPrimitive.contentOrNull }
|
||||||
?.joinToString(", ")
|
?.joinToString(", ")
|
||||||
}
|
}
|
||||||
id to manga
|
id to manga
|
||||||
@ -72,17 +76,16 @@ class CustomMangaManager(val context: Context) {
|
|||||||
private fun saveCustomInfo() {
|
private fun saveCustomInfo() {
|
||||||
val jsonElements = customMangaMap.values.map { it.toJson() }
|
val jsonElements = customMangaMap.values.map { it.toJson() }
|
||||||
if (jsonElements.isNotEmpty()) {
|
if (jsonElements.isNotEmpty()) {
|
||||||
val gson = GsonBuilder().create()
|
val mangaEntries = Json.encodeToJsonElement(jsonElements)
|
||||||
val root = JsonObject()
|
val root = buildJsonObject {
|
||||||
val mangaEntries = gson.toJsonTree(jsonElements)
|
put("mangas", mangaEntries)
|
||||||
|
}
|
||||||
root["mangas"] = mangaEntries
|
|
||||||
editJson.delete()
|
editJson.delete()
|
||||||
editJson.writeText(gson.toJson(root))
|
editJson.writeText(Json.encodeToString(root))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Manga.toJson(): MangaJson {
|
private fun Manga.toJson(): MangaJson {
|
||||||
return MangaJson(
|
return MangaJson(
|
||||||
id!!,
|
id!!,
|
||||||
title,
|
title,
|
||||||
@ -93,6 +96,7 @@ class CustomMangaManager(val context: Context) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class MangaJson(
|
data class MangaJson(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val title: String? = null,
|
val title: String? = null,
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.extension.api
|
package eu.kanade.tachiyomi.extension.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.int
|
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.extension.model.Extension
|
import eu.kanade.tachiyomi.extension.model.Extension
|
||||||
import eu.kanade.tachiyomi.extension.model.LoadResult
|
import eu.kanade.tachiyomi.extension.model.LoadResult
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.source
|
package eu.kanade.tachiyomi.source
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
@ -18,6 +17,9 @@ import eu.kanade.tachiyomi.util.storage.EpubFile
|
|||||||
import eu.kanade.tachiyomi.util.system.ImageUtil
|
import eu.kanade.tachiyomi.util.system.ImageUtil
|
||||||
import junrar.Archive
|
import junrar.Archive
|
||||||
import junrar.rarfile.FileHeader
|
import junrar.rarfile.FileHeader
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
@ -154,16 +156,19 @@ class LocalSource(private val context: Context) : CatalogueSource {
|
|||||||
val directory = getBaseDirectories(context).mapNotNull { File(it, manga.url) }.find {
|
val directory = getBaseDirectories(context).mapNotNull { File(it, manga.url) }.find {
|
||||||
it.exists()
|
it.exists()
|
||||||
} ?: return
|
} ?: return
|
||||||
val gson = GsonBuilder().setPrettyPrinting().create()
|
val json = Json {
|
||||||
|
prettyPrint = true
|
||||||
|
}
|
||||||
val existingFileName = directory.listFiles()?.find { it.extension == "json" }?.name
|
val existingFileName = directory.listFiles()?.find { it.extension == "json" }?.name
|
||||||
val file = File(directory, existingFileName ?: "info.json")
|
val file = File(directory, existingFileName ?: "info.json")
|
||||||
file.writeText(gson.toJson(manga.toJson()))
|
file.writeText(json.encodeToString(manga.toJson()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun SManga.toJson(): MangaJson {
|
private fun SManga.toJson(): MangaJson {
|
||||||
return MangaJson(title, author, artist, description, genre?.split(", ")?.toTypedArray())
|
return MangaJson(title, author, artist, description, genre?.split(", ")?.toTypedArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class MangaJson(
|
data class MangaJson(
|
||||||
val title: String,
|
val title: String,
|
||||||
val author: String?,
|
val author: String?,
|
||||||
|
@ -3,15 +3,6 @@ package eu.kanade.tachiyomi.source.online.all
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.int
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.set
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.annoations.Nsfw
|
import eu.kanade.tachiyomi.annoations.Nsfw
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
@ -57,6 +48,17 @@ import exh.util.trimAll
|
|||||||
import exh.util.trimOrNull
|
import exh.util.trimOrNull
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.add
|
||||||
|
import kotlinx.serialization.json.buildJsonArray
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.int
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
import okhttp3.CookieJar
|
import okhttp3.CookieJar
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
@ -938,29 +940,33 @@ class EHentai(
|
|||||||
val gallery = lastSplit.first()
|
val gallery = lastSplit.first()
|
||||||
val pageToken = uri.pathSegments.elementAt(1)
|
val pageToken = uri.pathSegments.elementAt(1)
|
||||||
|
|
||||||
val json = JsonObject()
|
val json = buildJsonObject {
|
||||||
json["method"] = "gtoken"
|
put("method", "gtoken")
|
||||||
json["pagelist"] = JsonArray().apply {
|
put(
|
||||||
add(
|
"pagelist",
|
||||||
JsonArray().apply {
|
buildJsonArray {
|
||||||
add(gallery.toInt())
|
add(
|
||||||
add(pageToken)
|
buildJsonArray {
|
||||||
add(pageNum.toInt())
|
add(gallery.toInt())
|
||||||
|
add(pageToken)
|
||||||
|
add(pageNum.toInt())
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val outJson = JsonParser.parseString(
|
val outJson = Json.decodeFromString<JsonObject>(
|
||||||
client.newCall(
|
client.newCall(
|
||||||
Request.Builder()
|
Request.Builder()
|
||||||
.url(EH_API_BASE)
|
.url(EH_API_BASE)
|
||||||
.post(json.toString().toRequestBody(JSON))
|
.post(json.toString().toRequestBody(JSON))
|
||||||
.build()
|
.build()
|
||||||
).execute().body!!.string()
|
).execute().body!!.string()
|
||||||
).obj
|
)
|
||||||
|
|
||||||
val obj = outJson["tokenlist"].array.first()
|
val obj = outJson["tokenlist"]!!.jsonArray.first().jsonObject
|
||||||
return "${uri.scheme}://${uri.host}/g/${obj["gid"].int}/${obj["token"].string}/"
|
return "${uri.scheme}://${uri.host}/g/${obj["gid"]!!.jsonPrimitive.int}/${obj["token"]!!.jsonPrimitive.content}/"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getDescriptionAdapter(controller: MangaController): EHentaiDescriptionAdapter {
|
override fun getDescriptionAdapter(controller: MangaController): EHentaiDescriptionAdapter {
|
||||||
|
@ -68,8 +68,8 @@ class Hitomi(delegate: HttpSource, val context: Context) :
|
|||||||
tags += RaisedTag("group", group!!, RaisedSearchMetadata.TAG_TYPE_VIRTUAL)
|
tags += RaisedTag("group", group!!, RaisedSearchMetadata.TAG_TYPE_VIRTUAL)
|
||||||
}
|
}
|
||||||
"type" -> {
|
"type" -> {
|
||||||
type = content.text()
|
genre = content.text()
|
||||||
tags += RaisedTag("type", type!!, RaisedSearchMetadata.TAG_TYPE_VIRTUAL)
|
tags += RaisedTag("type", genre!!, RaisedSearchMetadata.TAG_TYPE_VIRTUAL)
|
||||||
}
|
}
|
||||||
"series" -> {
|
"series" -> {
|
||||||
series = content.select("a").map { it.text() }
|
series = content.select("a").map { it.text() }
|
||||||
|
@ -2,12 +2,7 @@ package eu.kanade.tachiyomi.source.online.all
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import com.github.salomonbrys.kotson.get
|
import com.elvishew.xlog.XLog
|
||||||
import com.github.salomonbrys.kotson.nullArray
|
|
||||||
import com.github.salomonbrys.kotson.nullLong
|
|
||||||
import com.github.salomonbrys.kotson.nullObj
|
|
||||||
import com.github.salomonbrys.kotson.nullString
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
@ -23,6 +18,10 @@ import exh.metadata.metadata.base.RaisedTag
|
|||||||
import exh.source.DelegatedHttpSource
|
import exh.source.DelegatedHttpSource
|
||||||
import exh.ui.metadata.adapters.NHentaiDescriptionAdapter
|
import exh.ui.metadata.adapters.NHentaiDescriptionAdapter
|
||||||
import exh.util.urlImportFetchSearchManga
|
import exh.util.urlImportFetchSearchManga
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
|
||||||
@ -58,41 +57,40 @@ class NHentai(delegate: HttpSource, val context: Context) :
|
|||||||
val json = GALLERY_JSON_REGEX.find(input.body!!.string())!!.groupValues[1].replace(
|
val json = GALLERY_JSON_REGEX.find(input.body!!.string())!!.groupValues[1].replace(
|
||||||
UNICODE_ESCAPE_REGEX
|
UNICODE_ESCAPE_REGEX
|
||||||
) { it.groupValues[1].toInt(radix = 16).toChar().toString() }
|
) { it.groupValues[1].toInt(radix = 16).toChar().toString() }
|
||||||
val obj = JsonParser.parseString(json).asJsonObject
|
val jsonResponse = jsonParser.decodeFromString<JsonResponse>(json)
|
||||||
|
|
||||||
with(metadata) {
|
with(metadata) {
|
||||||
nhId = obj["id"].asLong
|
nhId = jsonResponse.id
|
||||||
|
|
||||||
uploadDate = obj["upload_date"].nullLong
|
uploadDate = jsonResponse.uploadDate
|
||||||
|
|
||||||
favoritesCount = obj["num_favorites"].nullLong
|
favoritesCount = jsonResponse.numFavorites
|
||||||
|
|
||||||
mediaId = obj["media_id"].nullString
|
mediaId = jsonResponse.mediaId
|
||||||
|
|
||||||
obj["title"].nullObj?.let { title ->
|
jsonResponse.title?.let { title ->
|
||||||
japaneseTitle = title["japanese"].nullString
|
japaneseTitle = title.japanese
|
||||||
shortTitle = title["pretty"].nullString
|
shortTitle = title.pretty
|
||||||
englishTitle = title["english"].nullString
|
englishTitle = title.english
|
||||||
}
|
}
|
||||||
|
|
||||||
obj["images"].nullObj?.let { images ->
|
jsonResponse.images?.let { images ->
|
||||||
coverImageType = images["cover"]?.get("t").nullString
|
coverImageType = images.cover?.type
|
||||||
images["pages"].nullArray?.mapNotNull {
|
images.pages.mapNotNull {
|
||||||
it?.asJsonObject?.get("t").nullString
|
it.type
|
||||||
}?.let {
|
}.let {
|
||||||
pageImageTypes = it
|
pageImageTypes = it
|
||||||
}
|
}
|
||||||
thumbnailImageType = images["thumbnail"]?.get("t").nullString
|
thumbnailImageType = images.thumbnail?.type
|
||||||
}
|
}
|
||||||
|
|
||||||
scanlator = obj["scanlator"].nullString
|
scanlator = jsonResponse.scanlator
|
||||||
|
|
||||||
obj["tags"]?.asJsonArray?.map {
|
jsonResponse.tags.map {
|
||||||
val asObj = it.asJsonObject
|
it.type to it.name
|
||||||
Pair(asObj["type"].nullString, asObj["name"].nullString)
|
}.apply {
|
||||||
}?.apply {
|
|
||||||
tags.clear()
|
tags.clear()
|
||||||
}?.forEach {
|
}.forEach {
|
||||||
if (it.first != null && it.second != null) {
|
if (it.first != null && it.second != null) {
|
||||||
tags.add(RaisedTag(it.first!!, it.second!!, if (it.first == "category") RaisedSearchMetadata.TAG_TYPE_VIRTUAL else NHentaiSearchMetadata.TAG_TYPE_DEFAULT))
|
tags.add(RaisedTag(it.first!!, it.second!!, if (it.first == "category") RaisedSearchMetadata.TAG_TYPE_VIRTUAL else NHentaiSearchMetadata.TAG_TYPE_DEFAULT))
|
||||||
}
|
}
|
||||||
@ -100,6 +98,49 @@ class NHentai(delegate: HttpSource, val context: Context) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class JsonResponse(
|
||||||
|
val id: Long,
|
||||||
|
@SerialName("media_id") val mediaId: String? = null,
|
||||||
|
val title: JsonTitle? = null,
|
||||||
|
val images: JsonImages? = null,
|
||||||
|
val scanlator: String? = null,
|
||||||
|
@SerialName("upload_date") val uploadDate: Long? = null,
|
||||||
|
val tags: List<JsonTag> = emptyList(),
|
||||||
|
@SerialName("num_pages") val numPages: Int? = null,
|
||||||
|
@SerialName("num_favorites") val numFavorites: Long? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class JsonTitle(
|
||||||
|
val english: String? = null,
|
||||||
|
val japanese: String? = null,
|
||||||
|
val pretty: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class JsonImages(
|
||||||
|
val pages: List<JsonPage> = emptyList(),
|
||||||
|
val cover: JsonPage? = null,
|
||||||
|
val thumbnail: JsonPage? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class JsonPage(
|
||||||
|
@SerialName("t") val type: String? = null,
|
||||||
|
@SerialName("w") val width: String? = null,
|
||||||
|
@SerialName("h") val height: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class JsonTag(
|
||||||
|
val id: Long? = null,
|
||||||
|
val type: String? = null,
|
||||||
|
val name: String? = null,
|
||||||
|
val url: String? = null,
|
||||||
|
val count: Long? = null
|
||||||
|
)
|
||||||
|
|
||||||
override fun toString() = "$name (${lang.toUpperCase()})"
|
override fun toString() = "$name (${lang.toUpperCase()})"
|
||||||
|
|
||||||
override fun ensureDelegateCompatible() {
|
override fun ensureDelegateCompatible() {
|
||||||
@ -127,6 +168,10 @@ class NHentai(delegate: HttpSource, val context: Context) :
|
|||||||
companion object {
|
companion object {
|
||||||
const val otherId = 7309872737163460316L
|
const val otherId = 7309872737163460316L
|
||||||
|
|
||||||
|
private val jsonParser = Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
}
|
||||||
|
|
||||||
private val GALLERY_JSON_REGEX = Regex(".parse\\(\"(.*)\"\\);")
|
private val GALLERY_JSON_REGEX = Regex(".parse\\(\"(.*)\"\\);")
|
||||||
private val UNICODE_ESCAPE_REGEX = Regex("\\\\u([0-9a-fA-F]{4})")
|
private val UNICODE_ESCAPE_REGEX = Regex("\\\\u([0-9a-fA-F]{4})")
|
||||||
}
|
}
|
||||||
|
@ -96,7 +96,7 @@ class PervEden(delegate: HttpSource, val context: Context) :
|
|||||||
if (it is TextNode) {
|
if (it is TextNode) {
|
||||||
val text = it.text().trim()
|
val text = it.text().trim()
|
||||||
if (!text.isBlank()) {
|
if (!text.isBlank()) {
|
||||||
type = text
|
genre = text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ import eu.kanade.tachiyomi.util.view.shrinkOnScroll
|
|||||||
import eu.kanade.tachiyomi.util.view.snack
|
import eu.kanade.tachiyomi.util.view.snack
|
||||||
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
import eu.kanade.tachiyomi.widget.AutofitRecyclerView
|
||||||
import eu.kanade.tachiyomi.widget.EmptyView
|
import eu.kanade.tachiyomi.widget.EmptyView
|
||||||
import exh.EXHSavedSearch
|
|
||||||
import exh.isEhBasedSource
|
import exh.isEhBasedSource
|
||||||
|
import exh.savedsearches.EXHSavedSearch
|
||||||
import exh.source.EnhancedHttpSource.Companion.getMainSource
|
import exh.source.EnhancedHttpSource.Companion.getMainSource
|
||||||
import kotlinx.android.parcel.Parcelize
|
import kotlinx.android.parcel.Parcelize
|
||||||
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
import kotlinx.android.synthetic.main.main_activity.root_coordinator
|
||||||
|
@ -1,11 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.davidea.flexibleadapter.items.ISectionable
|
import eu.davidea.flexibleadapter.items.ISectionable
|
||||||
import eu.kanade.tachiyomi.data.cache.CoverCache
|
import eu.kanade.tachiyomi.data.cache.CoverCache
|
||||||
@ -38,7 +33,14 @@ import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateItem
|
|||||||
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
import eu.kanade.tachiyomi.ui.browse.source.filter.TriStateSectionItem
|
||||||
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
import eu.kanade.tachiyomi.util.chapter.ChapterSettingsHelper
|
||||||
import eu.kanade.tachiyomi.util.removeCovers
|
import eu.kanade.tachiyomi.util.removeCovers
|
||||||
import exh.EXHSavedSearch
|
import exh.savedsearches.EXHSavedSearch
|
||||||
|
import exh.savedsearches.JsonSavedSearch
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -134,8 +136,8 @@ open class BrowseSourcePresenter(
|
|||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
if (filters != null) {
|
if (filters != null) {
|
||||||
val filters = JsonParser.parseString(filters).obj
|
val filters = Json.decodeFromString<JsonObject>(filters)
|
||||||
filterSerializer.deserialize(sourceFilters, filters["filters"].array)
|
filterSerializer.deserialize(sourceFilters, filters["filters"]!!.jsonArray)
|
||||||
}
|
}
|
||||||
val allDefault = sourceFilters == source.getFilterList()
|
val allDefault = sourceFilters == source.getFilterList()
|
||||||
// SY <--
|
// SY <--
|
||||||
@ -446,11 +448,11 @@ open class BrowseSourcePresenter(
|
|||||||
!it.startsWith("${source.id}:")
|
!it.startsWith("${source.id}:")
|
||||||
}
|
}
|
||||||
val newSerialized = searches.map {
|
val newSerialized = searches.map {
|
||||||
"${source.id}:" + jsonObject(
|
"${source.id}:" + buildJsonObject {
|
||||||
"name" to it.name,
|
put("name", it.name)
|
||||||
"query" to it.query,
|
put("query", it.query)
|
||||||
"filters" to filterSerializer.serialize(it.filterList)
|
put("filters", filterSerializer.serialize(it.filterList))
|
||||||
).toString()
|
}.toString()
|
||||||
}
|
}
|
||||||
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
||||||
}
|
}
|
||||||
@ -461,12 +463,12 @@ open class BrowseSourcePresenter(
|
|||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
if (id != source.id) return@map null
|
if (id != source.id) return@map null
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
val originalFilters = source.getFilterList()
|
val originalFilters = source.getFilterList()
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
filterSerializer.deserialize(originalFilters, content.filters)
|
||||||
EXHSavedSearch(
|
EXHSavedSearch(
|
||||||
content["name"].string,
|
content.name,
|
||||||
content["query"].string,
|
content.query,
|
||||||
originalFilters
|
originalFilters
|
||||||
)
|
)
|
||||||
} catch (t: RuntimeException) {
|
} catch (t: RuntimeException) {
|
||||||
|
@ -1,16 +1,5 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.browse
|
package eu.kanade.tachiyomi.ui.browse.source.browse
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
|
||||||
import com.github.salomonbrys.kotson.nullArray
|
|
||||||
import com.github.salomonbrys.kotson.nullObj
|
|
||||||
import com.github.salomonbrys.kotson.nullString
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.network.await
|
import eu.kanade.tachiyomi.network.await
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
@ -22,6 +11,15 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.Job
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonArray
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
@ -73,17 +71,18 @@ class MyAnimeList() : API("https://api.jikan.moe/v3/") {
|
|||||||
if (body.isEmpty()) {
|
if (body.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
val data = JsonParser.parseString(body).obj
|
val data = Json.decodeFromString<JsonObject>(body)
|
||||||
val recommendations = data["recommendations"].nullArray
|
val recommendations = data["recommendations"] as? JsonArray
|
||||||
?: throw Exception("Unexpected response")
|
?: throw Exception("Unexpected response")
|
||||||
val recs = recommendations.map { rec ->
|
val recs = recommendations.map { rec ->
|
||||||
|
rec as? JsonObject ?: throw Exception("Invalid json")
|
||||||
Timber.tag("RECOMMENDATIONS")
|
Timber.tag("RECOMMENDATIONS")
|
||||||
.d("MYANIMELIST > FOUND RECOMMENDATION > %s", rec["title"].string)
|
.d("MYANIMELIST > FOUND RECOMMENDATION > %s", rec["title"]!!.jsonPrimitive.content)
|
||||||
SMangaImpl().apply {
|
SMangaImpl().apply {
|
||||||
this.title = rec["title"].string
|
this.title = rec["title"]!!.jsonPrimitive.content
|
||||||
this.thumbnail_url = rec["image_url"].string
|
this.thumbnail_url = rec["image_url"]!!.jsonPrimitive.content
|
||||||
this.initialized = true
|
this.initialized = true
|
||||||
this.url = rec["url"].string
|
this.url = rec["url"]!!.jsonPrimitive.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback.invoke(recs, null)
|
callback.invoke(recs, null)
|
||||||
@ -121,15 +120,15 @@ class MyAnimeList() : API("https://api.jikan.moe/v3/") {
|
|||||||
if (body.isEmpty()) {
|
if (body.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
val data = JsonParser.parseString(body).obj
|
val data = Json.decodeFromString<JsonObject>(body)
|
||||||
val results = data["results"].nullArray ?: throw Exception("Unexpected response")
|
val results = data["results"] as? JsonArray ?: throw Exception("Unexpected response")
|
||||||
if (results.size() <= 0) {
|
if (results.size <= 0) {
|
||||||
throw Exception("'$search' not found")
|
throw Exception("'$search' not found")
|
||||||
}
|
}
|
||||||
val result = results.first().obj
|
val result = results.first().jsonObject
|
||||||
Timber.tag("RECOMMENDATIONS")
|
Timber.tag("RECOMMENDATIONS")
|
||||||
.d("MYANIMELIST > FOUND TITLE > %s", result["title"].string)
|
.d("MYANIMELIST > FOUND TITLE > %s", result["title"]!!.jsonPrimitive.content)
|
||||||
val id = result["mal_id"].string
|
val id = result["mal_id"]!!.jsonPrimitive.content
|
||||||
getRecsById(id, callback)
|
getRecsById(id, callback)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -138,19 +137,21 @@ class MyAnimeList() : API("https://api.jikan.moe/v3/") {
|
|||||||
class Anilist() : API("https://graphql.anilist.co/") {
|
class Anilist() : API("https://graphql.anilist.co/") {
|
||||||
private fun countOccurrence(arr: JsonArray, search: String): Int {
|
private fun countOccurrence(arr: JsonArray, search: String): Int {
|
||||||
return arr.count {
|
return arr.count {
|
||||||
val synonym = it.string
|
val synonym = it.jsonPrimitive.content
|
||||||
synonym.contains(search, true)
|
synonym.contains(search, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun languageContains(obj: JsonObject, language: String, search: String): Boolean {
|
private fun languageContains(obj: JsonObject, language: String, search: String): Boolean {
|
||||||
return obj["title"].obj[language].nullString?.contains(search, true) == true
|
return obj["title"]?.jsonObject?.get(language)?.jsonPrimitive?.content?.contains(search, true) == true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTitle(obj: JsonObject): String {
|
private fun getTitle(obj: JsonObject): String {
|
||||||
return obj["title"].obj["romaji"].nullString
|
return obj["title"]!!.jsonObject.let {
|
||||||
?: obj["title"].obj["english"].nullString
|
it["romaji"]?.jsonPrimitive?.content
|
||||||
?: obj["title"].obj["native"].string
|
?: it["english"]?.jsonPrimitive?.content
|
||||||
|
?: it["native"]!!.jsonPrimitive.content
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getRecsBySearch(
|
override fun getRecsBySearch(
|
||||||
@ -189,11 +190,13 @@ class Anilist() : API("https://graphql.anilist.co/") {
|
|||||||
|}
|
|}
|
||||||
|}
|
|}
|
||||||
|""".trimMargin()
|
|""".trimMargin()
|
||||||
val variables = jsonObject("search" to search)
|
val variables = buildJsonObject {
|
||||||
val payload = jsonObject(
|
put("search", search)
|
||||||
"query" to query,
|
}
|
||||||
"variables" to variables
|
val payload = buildJsonObject {
|
||||||
)
|
put("query", query)
|
||||||
|
put("variables", variables)
|
||||||
|
}
|
||||||
val payloadBody =
|
val payloadBody =
|
||||||
payload.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
payload.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull())
|
||||||
val request = Request.Builder()
|
val request = Request.Builder()
|
||||||
@ -211,33 +214,33 @@ class Anilist() : API("https://graphql.anilist.co/") {
|
|||||||
if (body.isEmpty()) {
|
if (body.isEmpty()) {
|
||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
val data = JsonParser.parseString(body).obj["data"].nullObj
|
val data = Json.decodeFromString<JsonObject>(body)["data"] as? JsonObject
|
||||||
?: throw Exception("Unexpected response")
|
?: throw Exception("Unexpected response")
|
||||||
val page = data["Page"].obj
|
val page = data["Page"]!!.jsonObject
|
||||||
val media = page["media"].array
|
val media = page["media"]!!.jsonArray
|
||||||
if (media.size() <= 0) {
|
if (media.size <= 0) {
|
||||||
throw Exception("'$search' not found")
|
throw Exception("'$search' not found")
|
||||||
}
|
}
|
||||||
val result = media.sortedWith(
|
val result = media.sortedWith(
|
||||||
compareBy(
|
compareBy(
|
||||||
{ languageContains(it.obj, "romaji", search) },
|
{ languageContains(it.jsonObject, "romaji", search) },
|
||||||
{ languageContains(it.obj, "english", search) },
|
{ languageContains(it.jsonObject, "english", search) },
|
||||||
{ languageContains(it.obj, "native", search) },
|
{ languageContains(it.jsonObject, "native", search) },
|
||||||
{ countOccurrence(it.obj["synonyms"].array, search) > 0 }
|
{ countOccurrence(it.jsonObject["synonyms"]!!.jsonArray, search) > 0 }
|
||||||
)
|
)
|
||||||
).last().obj
|
).last().jsonObject
|
||||||
Timber.tag("RECOMMENDATIONS")
|
Timber.tag("RECOMMENDATIONS")
|
||||||
.d("ANILIST > FOUND TITLE > %s", getTitle(result))
|
.d("ANILIST > FOUND TITLE > %s", getTitle(result))
|
||||||
val recommendations = result["recommendations"].obj["edges"].array
|
val recommendations = result["recommendations"]!!.jsonObject["edges"]!!.jsonArray
|
||||||
val recs = recommendations.map {
|
val recs = recommendations.map {
|
||||||
val rec = it["node"]["mediaRecommendation"].obj
|
val rec = it.jsonObject["node"]!!.jsonObject["mediaRecommendation"]!!.jsonObject
|
||||||
Timber.tag("RECOMMENDATIONS")
|
Timber.tag("RECOMMENDATIONS")
|
||||||
.d("ANILIST: FOUND RECOMMENDATION: %s", getTitle(rec))
|
.d("ANILIST: FOUND RECOMMENDATION: %s", getTitle(rec))
|
||||||
SMangaImpl().apply {
|
SMangaImpl().apply {
|
||||||
this.title = getTitle(rec)
|
this.title = getTitle(rec)
|
||||||
this.thumbnail_url = rec["coverImage"].obj["large"].string
|
this.thumbnail_url = rec["coverImage"]!!.jsonObject["large"]!!.jsonPrimitive.content
|
||||||
this.initialized = true
|
this.initialized = true
|
||||||
this.url = rec["siteUrl"].string
|
this.url = rec["siteUrl"]!!.jsonPrimitive.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
callback.invoke(recs, null)
|
callback.invoke(recs, null)
|
||||||
|
@ -18,7 +18,7 @@ import eu.kanade.tachiyomi.databinding.SourceFilterSheetBinding
|
|||||||
import eu.kanade.tachiyomi.source.CatalogueSource
|
import eu.kanade.tachiyomi.source.CatalogueSource
|
||||||
import eu.kanade.tachiyomi.source.online.BrowseSourceFilterHeader
|
import eu.kanade.tachiyomi.source.online.BrowseSourceFilterHeader
|
||||||
import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
import eu.kanade.tachiyomi.widget.SimpleNavigationView
|
||||||
import exh.EXHSavedSearch
|
import exh.savedsearches.EXHSavedSearch
|
||||||
import exh.source.EnhancedHttpSource.Companion.getMainSource
|
import exh.source.EnhancedHttpSource.Companion.getMainSource
|
||||||
|
|
||||||
class SourceFilterSheet(
|
class SourceFilterSheet(
|
||||||
|
@ -11,7 +11,6 @@ import androidx.core.view.isVisible
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
|
||||||
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
@ -30,6 +29,7 @@ import exh.util.nullIfBlank
|
|||||||
import kotlinx.coroutines.flow.filter
|
import kotlinx.coroutines.flow.filter
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import reactivecircus.flowbinding.android.view.clicks
|
import reactivecircus.flowbinding.android.view.clicks
|
||||||
import reactivecircus.flowbinding.appcompat.QueryTextEvent
|
import reactivecircus.flowbinding.appcompat.QueryTextEvent
|
||||||
import reactivecircus.flowbinding.appcompat.queryTextEvents
|
import reactivecircus.flowbinding.appcompat.queryTextEvents
|
||||||
@ -203,7 +203,7 @@ open class IndexController :
|
|||||||
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
val allDefault = presenter.sourceFilters == presenter.source.getFilterList()
|
||||||
filterSheet?.dismiss()
|
filterSheet?.dismiss()
|
||||||
if (!allDefault) {
|
if (!allDefault) {
|
||||||
val json = jsonObject("filters" to filterSerializer.serialize(presenter.sourceFilters))
|
val json = buildJsonObject { put("filters", filterSerializer.serialize(presenter.sourceFilters)) }
|
||||||
onBrowseClick(presenter.query.nullIfBlank(), json.toString())
|
onBrowseClick(presenter.query.nullIfBlank(), json.toString())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -232,7 +232,7 @@ open class IndexController :
|
|||||||
filterSheet?.dismiss()
|
filterSheet?.dismiss()
|
||||||
|
|
||||||
if (!allDefault) {
|
if (!allDefault) {
|
||||||
val json = jsonObject("filters" to filterSerializer.serialize(presenter.sourceFilters))
|
val json = buildJsonObject { put("filters", filterSerializer.serialize(presenter.sourceFilters)) }
|
||||||
onBrowseClick(presenter.query.nullIfBlank(), json.toString())
|
onBrowseClick(presenter.query.nullIfBlank(), json.toString())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
package eu.kanade.tachiyomi.ui.browse.source.index
|
package eu.kanade.tachiyomi.ui.browse.source.index
|
||||||
|
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.davidea.flexibleadapter.items.IFlexible
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
@ -15,7 +11,8 @@ import eu.kanade.tachiyomi.source.model.FilterList
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
import eu.kanade.tachiyomi.ui.base.presenter.BasePresenter
|
||||||
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter.Companion.toItems
|
import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourcePresenter.Companion.toItems
|
||||||
import exh.EXHSavedSearch
|
import exh.savedsearches.EXHSavedSearch
|
||||||
|
import exh.savedsearches.JsonSavedSearch
|
||||||
import exh.util.asFlow
|
import exh.util.asFlow
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -23,6 +20,8 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.coroutines.flow.singleOrNull
|
import kotlinx.coroutines.flow.singleOrNull
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.Subscription
|
import rx.Subscription
|
||||||
import rx.android.schedulers.AndroidSchedulers
|
import rx.android.schedulers.AndroidSchedulers
|
||||||
@ -232,12 +231,12 @@ open class IndexPresenter(
|
|||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
if (id != source.id) return@map null
|
if (id != source.id) return@map null
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
val content = Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
val originalFilters = source.getFilterList()
|
val originalFilters = source.getFilterList()
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
filterSerializer.deserialize(originalFilters, content.filters)
|
||||||
EXHSavedSearch(
|
EXHSavedSearch(
|
||||||
content["name"].string,
|
content.name,
|
||||||
content["query"].string,
|
content.query,
|
||||||
originalFilters
|
originalFilters
|
||||||
)
|
)
|
||||||
} catch (t: RuntimeException) {
|
} catch (t: RuntimeException) {
|
||||||
|
@ -12,8 +12,6 @@ import com.afollestad.materialdialogs.input.getInputField
|
|||||||
import com.afollestad.materialdialogs.input.input
|
import com.afollestad.materialdialogs.input.input
|
||||||
import com.bluelinelabs.conductor.RouterTransaction
|
import com.bluelinelabs.conductor.RouterTransaction
|
||||||
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
import com.bluelinelabs.conductor.changehandler.FadeChangeHandler
|
||||||
import com.github.salomonbrys.kotson.fromJson
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.tfcporciuncula.flow.Preference
|
import com.tfcporciuncula.flow.Preference
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
@ -116,6 +114,8 @@ import kotlinx.coroutines.flow.onEach
|
|||||||
import kotlinx.coroutines.flow.take
|
import kotlinx.coroutines.flow.take
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import kotlin.time.Duration
|
import kotlin.time.Duration
|
||||||
@ -128,7 +128,6 @@ import kotlin.time.hours
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
class SettingsEhController : SettingsController() {
|
class SettingsEhController : SettingsController() {
|
||||||
private val gson: Gson by injectLazy()
|
|
||||||
private val db: DatabaseHelper by injectLazy()
|
private val db: DatabaseHelper by injectLazy()
|
||||||
|
|
||||||
private fun Preference<*>.reconfigure(): Boolean {
|
private fun Preference<*>.reconfigure(): Boolean {
|
||||||
@ -687,7 +686,7 @@ class SettingsEhController : SettingsController() {
|
|||||||
val updateInfo = try {
|
val updateInfo = try {
|
||||||
val stats =
|
val stats =
|
||||||
preferences.eh_autoUpdateStats().get().nullIfBlank()?.let {
|
preferences.eh_autoUpdateStats().get().nullIfBlank()?.let {
|
||||||
gson.fromJson<EHentaiUpdaterStats>(it)
|
Json.decodeFromString<EHentaiUpdaterStats>(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
val statsText = if (stats != null) {
|
val statsText = if (stats != null) {
|
||||||
|
@ -2,9 +2,6 @@ package exh
|
|||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.github.salomonbrys.kotson.fromJson
|
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.annotations.SerializedName
|
|
||||||
import com.pushtorefresh.storio.sqlite.queries.Query
|
import com.pushtorefresh.storio.sqlite.queries.Query
|
||||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
||||||
import eu.kanade.tachiyomi.BuildConfig
|
import eu.kanade.tachiyomi.BuildConfig
|
||||||
@ -28,6 +25,10 @@ import eu.kanade.tachiyomi.source.online.all.Hitomi
|
|||||||
import eu.kanade.tachiyomi.source.online.all.NHentai
|
import eu.kanade.tachiyomi.source.online.all.NHentai
|
||||||
import exh.merged.sql.models.MergedMangaReference
|
import exh.merged.sql.models.MergedMangaReference
|
||||||
import exh.source.BlacklistedSources
|
import exh.source.BlacklistedSources
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
@ -36,7 +37,6 @@ import java.net.URISyntaxException
|
|||||||
object EXHMigrations {
|
object EXHMigrations {
|
||||||
private val db: DatabaseHelper by injectLazy()
|
private val db: DatabaseHelper by injectLazy()
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
private val sourceManager: SourceManager by injectLazy()
|
||||||
private val gson: Gson by injectLazy()
|
|
||||||
|
|
||||||
private val logger = XLog.tag("EXHMigrations")
|
private val logger = XLog.tag("EXHMigrations")
|
||||||
|
|
||||||
@ -167,7 +167,7 @@ object EXHMigrations {
|
|||||||
.executeAsBlocking()
|
.executeAsBlocking()
|
||||||
|
|
||||||
if (mergedMangas.isNotEmpty()) {
|
if (mergedMangas.isNotEmpty()) {
|
||||||
val mangaConfigs = mergedMangas.mapNotNull { mergedManga -> readMangaConfig(mergedManga, gson)?.let { mergedManga to it } }
|
val mangaConfigs = mergedMangas.mapNotNull { mergedManga -> readMangaConfig(mergedManga)?.let { mergedManga to it } }
|
||||||
if (mangaConfigs.isNotEmpty()) {
|
if (mangaConfigs.isNotEmpty()) {
|
||||||
val mangaToUpdate = mutableListOf<Manga>()
|
val mangaToUpdate = mutableListOf<Manga>()
|
||||||
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
|
val mergedMangaReferences = mutableListOf<MergedMangaReference>()
|
||||||
@ -237,7 +237,7 @@ object EXHMigrations {
|
|||||||
.prepare()
|
.prepare()
|
||||||
.executeAsBlocking()
|
.executeAsBlocking()
|
||||||
val mergedMangaChaptersMatched = mergedMangaChapters.mapNotNull { chapter -> loadedMangaList.firstOrNull { it.manga.id == chapter.id }?.let { it to chapter } }
|
val mergedMangaChaptersMatched = mergedMangaChapters.mapNotNull { chapter -> loadedMangaList.firstOrNull { it.manga.id == chapter.id }?.let { it to chapter } }
|
||||||
val parsedChapters = chapters.filter { it.read || it.last_page_read != 0 }.mapNotNull { chapter -> readUrlConfig(chapter.url, gson)?.let { chapter to it } }
|
val parsedChapters = chapters.filter { it.read || it.last_page_read != 0 }.mapNotNull { chapter -> readUrlConfig(chapter.url)?.let { chapter to it } }
|
||||||
val chaptersToUpdate = mutableListOf<Chapter>()
|
val chaptersToUpdate = mutableListOf<Chapter>()
|
||||||
parsedChapters.forEach { parsedChapter ->
|
parsedChapters.forEach { parsedChapter ->
|
||||||
mergedMangaChaptersMatched.firstOrNull { it.second.url == parsedChapter.second.url && it.first.source.id == parsedChapter.second.source && it.first.manga.url == parsedChapter.second.mangaUrl }?.let {
|
mergedMangaChaptersMatched.firstOrNull { it.second.url == parsedChapter.second.url && it.first.source.id == parsedChapter.second.source && it.first.manga.url == parsedChapter.second.mangaUrl }?.let {
|
||||||
@ -339,23 +339,25 @@ object EXHMigrations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
private data class UrlConfig(
|
private data class UrlConfig(
|
||||||
@SerializedName("s")
|
@SerialName("s")
|
||||||
val source: Long,
|
val source: Long,
|
||||||
@SerializedName("u")
|
@SerialName("u")
|
||||||
val url: String,
|
val url: String,
|
||||||
@SerializedName("m")
|
@SerialName("m")
|
||||||
val mangaUrl: String
|
val mangaUrl: String
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
private data class MangaConfig(
|
private data class MangaConfig(
|
||||||
@SerializedName("c")
|
@SerialName("c")
|
||||||
val children: List<MangaSource>
|
val children: List<MangaSource>
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun readFromUrl(gson: Gson, url: String): MangaConfig? {
|
fun readFromUrl(url: String): MangaConfig? {
|
||||||
return try {
|
return try {
|
||||||
gson.fromJson(url)
|
Json.decodeFromString(url)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@ -363,14 +365,15 @@ object EXHMigrations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readMangaConfig(manga: SManga, gson: Gson): MangaConfig? {
|
private fun readMangaConfig(manga: SManga): MangaConfig? {
|
||||||
return MangaConfig.readFromUrl(gson, manga.url)
|
return MangaConfig.readFromUrl(manga.url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
private data class MangaSource(
|
private data class MangaSource(
|
||||||
@SerializedName("s")
|
@SerialName("s")
|
||||||
val source: Long,
|
val source: Long,
|
||||||
@SerializedName("u")
|
@SerialName("u")
|
||||||
val url: String
|
val url: String
|
||||||
) {
|
) {
|
||||||
fun load(db: DatabaseHelper, sourceManager: SourceManager): LoadedMangaSource? {
|
fun load(db: DatabaseHelper, sourceManager: SourceManager): LoadedMangaSource? {
|
||||||
@ -380,9 +383,9 @@ object EXHMigrations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun readUrlConfig(url: String, gson: Gson): UrlConfig? {
|
private fun readUrlConfig(url: String): UrlConfig? {
|
||||||
return try {
|
return try {
|
||||||
gson.fromJson(url)
|
Json.decodeFromString(url)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
@ -2,11 +2,6 @@ package exh.debug
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.github.salomonbrys.kotson.array
|
|
||||||
import com.github.salomonbrys.kotson.jsonObject
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
import com.pushtorefresh.storio.sqlite.queries.RawQuery
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
import eu.kanade.tachiyomi.data.database.tables.MangaTable
|
||||||
@ -16,13 +11,13 @@ import eu.kanade.tachiyomi.source.SourceManager
|
|||||||
import eu.kanade.tachiyomi.source.SourceManager.Companion.currentDelegatedSources
|
import eu.kanade.tachiyomi.source.SourceManager.Companion.currentDelegatedSources
|
||||||
import exh.EH_SOURCE_ID
|
import exh.EH_SOURCE_ID
|
||||||
import exh.EXHMigrations
|
import exh.EXHMigrations
|
||||||
import exh.EXHSavedSearch
|
|
||||||
import exh.EXH_SOURCE_ID
|
import exh.EXH_SOURCE_ID
|
||||||
import exh.eh.EHentaiThrottleManager
|
import exh.eh.EHentaiThrottleManager
|
||||||
import exh.eh.EHentaiUpdateWorker
|
import exh.eh.EHentaiUpdateWorker
|
||||||
import exh.metadata.metadata.EHentaiSearchMetadata
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadata
|
||||||
|
import exh.savedsearches.JsonSavedSearch
|
||||||
import exh.util.await
|
import exh.util.await
|
||||||
import exh.util.cancellable
|
import exh.util.cancellable
|
||||||
import exh.util.jobScheduler
|
import exh.util.jobScheduler
|
||||||
@ -31,8 +26,10 @@ import kotlinx.coroutines.flow.asFlow
|
|||||||
import kotlinx.coroutines.flow.mapNotNull
|
import kotlinx.coroutines.flow.mapNotNull
|
||||||
import kotlinx.coroutines.flow.toList
|
import kotlinx.coroutines.flow.toList
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
import xyz.nulldev.ts.api.http.serializer.FilterSerializer
|
|
||||||
import java.lang.RuntimeException
|
import java.lang.RuntimeException
|
||||||
|
|
||||||
@OptIn(FlowPreview::class)
|
@OptIn(FlowPreview::class)
|
||||||
@ -236,22 +233,13 @@ object DebugFunctions {
|
|||||||
|
|
||||||
fun copyEHentaiSavedSearchesToExhentai() {
|
fun copyEHentaiSavedSearchesToExhentai() {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val filterSerializer = FilterSerializer()
|
|
||||||
val source = sourceManager.get(EH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
val source = sourceManager.get(EH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
||||||
val newSource = sourceManager.get(EXH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
val newSource = sourceManager.get(EXH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
||||||
val savedSearches = prefs.eh_savedSearches().get().mapNotNull {
|
val savedSearches = prefs.eh_savedSearches().get().mapNotNull {
|
||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
if (id != source.id) return@mapNotNull null
|
if (id != source.id) return@mapNotNull null
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
|
|
||||||
val originalFilters = source.getFilterList()
|
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
|
||||||
EXHSavedSearch(
|
|
||||||
content["name"].string,
|
|
||||||
content["query"].string,
|
|
||||||
originalFilters
|
|
||||||
)
|
|
||||||
} catch (t: RuntimeException) {
|
} catch (t: RuntimeException) {
|
||||||
// Load failed
|
// Load failed
|
||||||
XLog.e("Failed to load saved search!", t)
|
XLog.e("Failed to load saved search!", t)
|
||||||
@ -263,15 +251,7 @@ object DebugFunctions {
|
|||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
if (id != newSource.id) return@mapNotNull null
|
if (id != newSource.id) return@mapNotNull null
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
|
|
||||||
val originalFilters = source.getFilterList()
|
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
|
||||||
EXHSavedSearch(
|
|
||||||
content["name"].string,
|
|
||||||
content["query"].string,
|
|
||||||
originalFilters
|
|
||||||
)
|
|
||||||
} catch (t: RuntimeException) {
|
} catch (t: RuntimeException) {
|
||||||
// Load failed
|
// Load failed
|
||||||
XLog.e("Failed to load saved search!", t)
|
XLog.e("Failed to load saved search!", t)
|
||||||
@ -284,11 +264,7 @@ object DebugFunctions {
|
|||||||
!it.startsWith("${newSource.id}:")
|
!it.startsWith("${newSource.id}:")
|
||||||
}
|
}
|
||||||
val newSerialized = savedSearches.map {
|
val newSerialized = savedSearches.map {
|
||||||
"${newSource.id}:" + jsonObject(
|
"${newSource.id}:" + Json.encodeToString(it)
|
||||||
"name" to it.name,
|
|
||||||
"query" to it.query,
|
|
||||||
"filters" to filterSerializer.serialize(it.filterList)
|
|
||||||
).toString()
|
|
||||||
}
|
}
|
||||||
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
||||||
}
|
}
|
||||||
@ -296,22 +272,13 @@ object DebugFunctions {
|
|||||||
|
|
||||||
fun copyExhentaiSavedSearchesToEHentai() {
|
fun copyExhentaiSavedSearchesToEHentai() {
|
||||||
runBlocking {
|
runBlocking {
|
||||||
val filterSerializer = FilterSerializer()
|
|
||||||
val source = sourceManager.get(EXH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
val source = sourceManager.get(EXH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
||||||
val newSource = sourceManager.get(EH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
val newSource = sourceManager.get(EH_SOURCE_ID) as? CatalogueSource ?: return@runBlocking
|
||||||
val savedSearches = prefs.eh_savedSearches().get().mapNotNull {
|
val savedSearches = prefs.eh_savedSearches().get().mapNotNull {
|
||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
if (id != source.id) return@mapNotNull null
|
if (id != source.id) return@mapNotNull null
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
|
|
||||||
val originalFilters = source.getFilterList()
|
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
|
||||||
EXHSavedSearch(
|
|
||||||
content["name"].string,
|
|
||||||
content["query"].string,
|
|
||||||
originalFilters
|
|
||||||
)
|
|
||||||
} catch (t: RuntimeException) {
|
} catch (t: RuntimeException) {
|
||||||
// Load failed
|
// Load failed
|
||||||
XLog.e("Failed to load saved search!", t)
|
XLog.e("Failed to load saved search!", t)
|
||||||
@ -323,15 +290,7 @@ object DebugFunctions {
|
|||||||
try {
|
try {
|
||||||
val id = it.substringBefore(':').toLong()
|
val id = it.substringBefore(':').toLong()
|
||||||
if (id != newSource.id) return@mapNotNull null
|
if (id != newSource.id) return@mapNotNull null
|
||||||
val content = JsonParser.parseString(it.substringAfter(':')).obj
|
Json.decodeFromString<JsonSavedSearch>(it.substringAfter(':'))
|
||||||
|
|
||||||
val originalFilters = source.getFilterList()
|
|
||||||
filterSerializer.deserialize(originalFilters, content["filters"].array)
|
|
||||||
EXHSavedSearch(
|
|
||||||
content["name"].string,
|
|
||||||
content["query"].string,
|
|
||||||
originalFilters
|
|
||||||
)
|
|
||||||
} catch (t: RuntimeException) {
|
} catch (t: RuntimeException) {
|
||||||
// Load failed
|
// Load failed
|
||||||
XLog.e("Failed to load saved search!", t)
|
XLog.e("Failed to load saved search!", t)
|
||||||
@ -344,11 +303,7 @@ object DebugFunctions {
|
|||||||
!it.startsWith("${newSource.id}:")
|
!it.startsWith("${newSource.id}:")
|
||||||
}
|
}
|
||||||
val newSerialized = savedSearches.map {
|
val newSerialized = savedSearches.map {
|
||||||
"${newSource.id}:" + jsonObject(
|
"${newSource.id}:" + Json.encodeToString(it)
|
||||||
"name" to it.name,
|
|
||||||
"query" to it.query,
|
|
||||||
"filters" to filterSerializer.serialize(it.filterList)
|
|
||||||
).toString()
|
|
||||||
}
|
}
|
||||||
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
prefs.eh_savedSearches().set((otherSerialized + newSerialized).toSet())
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ import android.content.ComponentName
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.google.gson.Gson
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Chapter
|
import eu.kanade.tachiyomi.data.database.models.Chapter
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
@ -38,6 +37,8 @@ import kotlinx.coroutines.flow.mapNotNull
|
|||||||
import kotlinx.coroutines.flow.toList
|
import kotlinx.coroutines.flow.toList
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
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
|
||||||
@ -54,7 +55,6 @@ class EHentaiUpdateWorker : JobService(), CoroutineScope {
|
|||||||
|
|
||||||
private val db: DatabaseHelper by injectLazy()
|
private val db: DatabaseHelper by injectLazy()
|
||||||
private val prefs: PreferencesHelper by injectLazy()
|
private val prefs: PreferencesHelper by injectLazy()
|
||||||
private val gson: Gson by injectLazy()
|
|
||||||
private val sourceManager: SourceManager by injectLazy()
|
private val sourceManager: SourceManager by injectLazy()
|
||||||
private val updateHelper: EHentaiUpdateHelper by injectLazy()
|
private val updateHelper: EHentaiUpdateHelper by injectLazy()
|
||||||
private val logger = XLog.tag("EHUpdater")
|
private val logger = XLog.tag("EHUpdater")
|
||||||
@ -242,7 +242,7 @@ class EHentaiUpdateWorker : JobService(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
prefs.eh_autoUpdateStats().set(
|
prefs.eh_autoUpdateStats().set(
|
||||||
gson.toJson(
|
Json.encodeToString(
|
||||||
EHentaiUpdaterStats(
|
EHentaiUpdaterStats(
|
||||||
startTime,
|
startTime,
|
||||||
allMeta.size,
|
allMeta.size,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package exh.eh
|
package exh.eh
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class EHentaiUpdaterStats(
|
data class EHentaiUpdaterStats(
|
||||||
val startTime: Long,
|
val startTime: Long,
|
||||||
val possibleUpdates: Int,
|
val possibleUpdates: Int,
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
package exh.log
|
package exh.log
|
||||||
|
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.google.gson.Gson
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.logging.HttpLoggingInterceptor
|
import okhttp3.logging.HttpLoggingInterceptor
|
||||||
|
|
||||||
fun OkHttpClient.Builder.maybeInjectEHLogger(): OkHttpClient.Builder {
|
fun OkHttpClient.Builder.maybeInjectEHLogger(): OkHttpClient.Builder {
|
||||||
if (EHLogLevel.shouldLog(EHLogLevel.EXTREME)) {
|
if (EHLogLevel.shouldLog(EHLogLevel.EXTREME)) {
|
||||||
val logger: HttpLoggingInterceptor.Logger = object : HttpLoggingInterceptor.Logger {
|
val logger: HttpLoggingInterceptor.Logger = HttpLoggingInterceptor.Logger { message ->
|
||||||
override fun log(message: String) {
|
try {
|
||||||
try {
|
Json.decodeFromString<Any>(message)
|
||||||
Gson().fromJson(message, Any::class.java)
|
XLog.tag("||EH-NETWORK-JSON").nst().json(message)
|
||||||
XLog.tag("||EH-NETWORK-JSON").nst().json(message)
|
} catch (ex: Exception) {
|
||||||
} catch (ex: Exception) {
|
XLog.tag("||EH-NETWORK").nb().nst().d(message)
|
||||||
XLog.tag("||EH-NETWORK").nb().nst().d(message)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return addInterceptor(HttpLoggingInterceptor(logger).apply { level = HttpLoggingInterceptor.Level.BODY })
|
return addInterceptor(HttpLoggingInterceptor(logger).apply { level = HttpLoggingInterceptor.Level.BODY })
|
||||||
|
@ -1,24 +1,27 @@
|
|||||||
package exh.md.handlers
|
package exh.md.handlers
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
class ApiChapterParser {
|
class ApiChapterParser {
|
||||||
fun pageListParse(response: Response): List<Page> {
|
fun pageListParse(response: Response): List<Page> {
|
||||||
val jsonData = response.body!!.string()
|
val jsonData = response.body!!.string()
|
||||||
val json = JsonParser.parseString(jsonData).asJsonObject
|
val json = Json.decodeFromString<JsonObject>(jsonData)
|
||||||
|
|
||||||
val pages = mutableListOf<Page>()
|
val pages = mutableListOf<Page>()
|
||||||
|
|
||||||
val hash = json.get("hash").string
|
val hash = json["hash"]!!.jsonPrimitive.content
|
||||||
val pageArray = json.getAsJsonArray("page_array")
|
val pageArray = json["page_array"]!!.jsonArray
|
||||||
val server = json.get("server").string
|
val server = json["server"]!!.jsonPrimitive.content
|
||||||
|
|
||||||
pageArray.forEach {
|
pageArray.forEach {
|
||||||
val url = "$hash/${it.asString}"
|
val url = "$hash/${it.jsonPrimitive.content}"
|
||||||
pages.add(Page(pages.size, "$server,${response.request.url},${Date().time}", url))
|
pages.add(Page(pages.size, "$server,${response.request.url},${Date().time}", url))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -27,8 +30,8 @@ class ApiChapterParser {
|
|||||||
|
|
||||||
fun externalParse(response: Response): String {
|
fun externalParse(response: Response): String {
|
||||||
val jsonData = response.body!!.string()
|
val jsonData = response.body!!.string()
|
||||||
val json = JsonParser.parseString(jsonData).asJsonObject
|
val json = Json.decodeFromString<JsonObject>(jsonData)
|
||||||
val external = json.get("external").string
|
val external = json["external"]!!.jsonPrimitive.content
|
||||||
return external.substringAfterLast("/")
|
return external.substringAfterLast("/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
package exh.md.handlers
|
package exh.md.handlers
|
||||||
|
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.github.salomonbrys.kotson.nullInt
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
@ -18,6 +15,11 @@ import exh.metadata.metadata.base.RaisedTag
|
|||||||
import exh.metadata.metadata.base.getFlatMetadataForManga
|
import exh.metadata.metadata.base.getFlatMetadataForManga
|
||||||
import exh.metadata.metadata.base.insertFlatMetadata
|
import exh.metadata.metadata.base.insertFlatMetadata
|
||||||
import exh.util.floor
|
import exh.util.floor
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.intOrNull
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Single
|
import rx.Single
|
||||||
@ -232,8 +234,8 @@ class ApiMangaParser(private val langs: List<String>) {
|
|||||||
throw Exception("Null Response")
|
throw Exception("Null Response")
|
||||||
}
|
}
|
||||||
|
|
||||||
val jsonObject = JsonParser.parseString(body).obj
|
val jsonObject = Json.decodeFromString<JsonObject>(body)
|
||||||
return jsonObject["manga_id"]?.nullInt ?: throw Exception("No manga associated with chapter")
|
return jsonObject["manga_id"]?.jsonPrimitive?.intOrNull ?: throw Exception("No manga associated with chapter")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
XLog.e(e)
|
XLog.e(e)
|
||||||
throw e
|
throw e
|
||||||
|
@ -9,10 +9,12 @@ import exh.metadata.EX_DATE_FORMAT
|
|||||||
import exh.metadata.ONGOING_SUFFIX
|
import exh.metadata.ONGOING_SUFFIX
|
||||||
import exh.metadata.humanReadableByteCount
|
import exh.metadata.humanReadableByteCount
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
class EHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||||
var gId: String?
|
var gId: String?
|
||||||
get() = indexedExtra
|
get() = indexedExtra
|
||||||
|
@ -4,7 +4,9 @@ import android.content.Context
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class EightMusesSearchMetadata : RaisedSearchMetadata() {
|
class EightMusesSearchMetadata : RaisedSearchMetadata() {
|
||||||
var path: List<String> = emptyList()
|
var path: List<String> = emptyList()
|
||||||
|
|
||||||
|
@ -5,7 +5,9 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.EightMusesSearchMetadata.Companion.ARTIST_NAMESPACE
|
import exh.metadata.metadata.EightMusesSearchMetadata.Companion.ARTIST_NAMESPACE
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class HBrowseSearchMetadata : RaisedSearchMetadata() {
|
class HBrowseSearchMetadata : RaisedSearchMetadata() {
|
||||||
var hbId: Long? = null
|
var hbId: Long? = null
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ import android.content.Context
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class HentaiCafeSearchMetadata : RaisedSearchMetadata() {
|
class HentaiCafeSearchMetadata : RaisedSearchMetadata() {
|
||||||
var hcId: String? = null
|
var hcId: String? = null
|
||||||
var readerId: String? = null
|
var readerId: String? = null
|
||||||
|
@ -5,9 +5,10 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.EX_DATE_FORMAT
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.plusAssign
|
import kotlinx.serialization.Serializable
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class HitomiSearchMetadata : RaisedSearchMetadata() {
|
class HitomiSearchMetadata : RaisedSearchMetadata() {
|
||||||
var url get() = hlId?.let { urlFromHlId(it) }
|
var url get() = hlId?.let { urlFromHlId(it) }
|
||||||
set(a) {
|
set(a) {
|
||||||
@ -26,7 +27,7 @@ class HitomiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
var group: String? = null
|
var group: String? = null
|
||||||
|
|
||||||
var type: String? = null
|
var genre: String? = null
|
||||||
|
|
||||||
var language: String? = null
|
var language: String? = null
|
||||||
|
|
||||||
@ -101,7 +102,7 @@ class HitomiSearchMetadata : RaisedSearchMetadata() {
|
|||||||
pairs += Pair(context.getString(R.string.artist), artists)
|
pairs += Pair(context.getString(R.string.artist), artists)
|
||||||
}
|
}
|
||||||
group?.let { pairs += Pair(context.getString(R.string.group), it) }
|
group?.let { pairs += Pair(context.getString(R.string.group), it) }
|
||||||
type?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
genre?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
||||||
language?.let { pairs += Pair(context.getString(R.string.language), it) }
|
language?.let { pairs += Pair(context.getString(R.string.language), it) }
|
||||||
val series = series.joinToString()
|
val series = series.joinToString()
|
||||||
if (series.isNotBlank()) {
|
if (series.isNotBlank()) {
|
||||||
|
@ -5,7 +5,9 @@ import androidx.core.net.toUri
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
class MangaDexSearchMetadata : RaisedSearchMetadata() {
|
||||||
var mdId: String? = null
|
var mdId: String? = null
|
||||||
|
|
||||||
|
@ -6,9 +6,11 @@ import eu.kanade.tachiyomi.source.model.SManga
|
|||||||
import exh.metadata.EX_DATE_FORMAT
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
import exh.metadata.ONGOING_SUFFIX
|
import exh.metadata.ONGOING_SUFFIX
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
class NHentaiSearchMetadata : RaisedSearchMetadata() {
|
||||||
var url get() = nhId?.let { BASE_URL + nhIdToPath(it) }
|
var url get() = nhId?.let { BASE_URL + nhIdToPath(it) }
|
||||||
set(a) {
|
set(a) {
|
||||||
|
@ -6,7 +6,9 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
import exh.metadata.metadata.base.RaisedTitle
|
import exh.metadata.metadata.base.RaisedTitle
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
||||||
var pvId: String? = null
|
var pvId: String? = null
|
||||||
|
|
||||||
@ -23,7 +25,7 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
|
|
||||||
var artist: String? = null
|
var artist: String? = null
|
||||||
|
|
||||||
var type: String? = null
|
var genre: String? = null
|
||||||
|
|
||||||
var rating: Float? = null
|
var rating: Float? = null
|
||||||
|
|
||||||
@ -102,7 +104,7 @@ class PervEdenSearchMetadata : RaisedSearchMetadata() {
|
|||||||
pairs += Pair(context.getString(R.string.alt_titles), altTitles)
|
pairs += Pair(context.getString(R.string.alt_titles), altTitles)
|
||||||
}
|
}
|
||||||
artist?.let { pairs += Pair(context.getString(R.string.artist), it) }
|
artist?.let { pairs += Pair(context.getString(R.string.artist), it) }
|
||||||
type?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
genre?.let { pairs += Pair(context.getString(R.string.genre), it) }
|
||||||
rating?.let { pairs += Pair(context.getString(R.string.average_rating), it.toString()) }
|
rating?.let { pairs += Pair(context.getString(R.string.average_rating), it.toString()) }
|
||||||
status?.let { pairs += Pair(context.getString(R.string.status), it) }
|
status?.let { pairs += Pair(context.getString(R.string.status), it) }
|
||||||
lang?.let { pairs += Pair(context.getString(R.string.language), it) }
|
lang?.let { pairs += Pair(context.getString(R.string.language), it) }
|
||||||
|
@ -4,7 +4,9 @@ import android.content.Context
|
|||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
class PururinSearchMetadata : RaisedSearchMetadata() {
|
class PururinSearchMetadata : RaisedSearchMetadata() {
|
||||||
var prId: Int? = null
|
var prId: Int? = null
|
||||||
|
|
||||||
|
@ -6,10 +6,12 @@ import eu.kanade.tachiyomi.R
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.EX_DATE_FORMAT
|
import exh.metadata.EX_DATE_FORMAT
|
||||||
import exh.metadata.metadata.base.RaisedSearchMetadata
|
import exh.metadata.metadata.base.RaisedSearchMetadata
|
||||||
|
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
|
||||||
class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
class TsuminoSearchMetadata : RaisedSearchMetadata() {
|
||||||
var tmId: Int? = null
|
var tmId: Int? = null
|
||||||
|
|
||||||
|
@ -5,10 +5,15 @@ import eu.kanade.tachiyomi.data.database.DatabaseHelper
|
|||||||
import exh.metadata.sql.models.SearchMetadata
|
import exh.metadata.sql.models.SearchMetadata
|
||||||
import exh.metadata.sql.models.SearchTag
|
import exh.metadata.sql.models.SearchTag
|
||||||
import exh.metadata.sql.models.SearchTitle
|
import exh.metadata.sql.models.SearchTitle
|
||||||
|
import kotlinx.serialization.InternalSerializationApi
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.serializer
|
||||||
import rx.Completable
|
import rx.Completable
|
||||||
import rx.Single
|
import rx.Single
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class FlatMetadata(
|
data class FlatMetadata(
|
||||||
val metadata: SearchMetadata,
|
val metadata: SearchMetadata,
|
||||||
val tags: List<SearchTag>,
|
val tags: List<SearchTag>,
|
||||||
@ -16,9 +21,10 @@ data class FlatMetadata(
|
|||||||
) {
|
) {
|
||||||
inline fun <reified T : RaisedSearchMetadata> raise(): T = raise(T::class)
|
inline fun <reified T : RaisedSearchMetadata> raise(): T = raise(T::class)
|
||||||
|
|
||||||
|
@OptIn(InternalSerializationApi::class)
|
||||||
fun <T : RaisedSearchMetadata> raise(clazz: KClass<T>): T =
|
fun <T : RaisedSearchMetadata> raise(clazz: KClass<T>): T =
|
||||||
RaisedSearchMetadata.raiseFlattenGson
|
RaisedSearchMetadata.raiseFlattenJson
|
||||||
.fromJson(metadata.extra, clazz.java).apply {
|
.decodeFromString(clazz.serializer(), metadata.extra).apply {
|
||||||
fillBaseFields(this@FlatMetadata)
|
fillBaseFields(this@FlatMetadata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +1,35 @@
|
|||||||
package exh.metadata.metadata.base
|
package exh.metadata.metadata.base
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import com.google.gson.Gson
|
|
||||||
import com.google.gson.GsonBuilder
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import exh.metadata.forEach
|
import exh.metadata.forEach
|
||||||
|
import exh.metadata.metadata.EHentaiSearchMetadata
|
||||||
|
import exh.metadata.metadata.EightMusesSearchMetadata
|
||||||
|
import exh.metadata.metadata.HBrowseSearchMetadata
|
||||||
|
import exh.metadata.metadata.HentaiCafeSearchMetadata
|
||||||
|
import exh.metadata.metadata.HitomiSearchMetadata
|
||||||
|
import exh.metadata.metadata.MangaDexSearchMetadata
|
||||||
|
import exh.metadata.metadata.NHentaiSearchMetadata
|
||||||
|
import exh.metadata.metadata.PervEdenSearchMetadata
|
||||||
|
import exh.metadata.metadata.PururinSearchMetadata
|
||||||
|
import exh.metadata.metadata.TsuminoSearchMetadata
|
||||||
import exh.metadata.sql.models.SearchMetadata
|
import exh.metadata.sql.models.SearchMetadata
|
||||||
import exh.metadata.sql.models.SearchTag
|
import exh.metadata.sql.models.SearchTag
|
||||||
import exh.metadata.sql.models.SearchTitle
|
import exh.metadata.sql.models.SearchTitle
|
||||||
import exh.plusAssign
|
import exh.plusAssign
|
||||||
|
import kotlinx.serialization.Polymorphic
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.Transient
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.modules.SerializersModule
|
||||||
|
import kotlinx.serialization.modules.polymorphic
|
||||||
|
import kotlinx.serialization.modules.subclass
|
||||||
import kotlin.properties.ReadWriteProperty
|
import kotlin.properties.ReadWriteProperty
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
|
@Polymorphic
|
||||||
|
@Serializable
|
||||||
abstract class RaisedSearchMetadata {
|
abstract class RaisedSearchMetadata {
|
||||||
@Transient
|
@Transient
|
||||||
var mangaId: Long = -1
|
var mangaId: Long = -1
|
||||||
@ -67,7 +85,7 @@ abstract class RaisedSearchMetadata {
|
|||||||
fun flatten(): FlatMetadata {
|
fun flatten(): FlatMetadata {
|
||||||
require(mangaId != -1L)
|
require(mangaId != -1L)
|
||||||
|
|
||||||
val extra = raiseFlattenGson.toJson(this)
|
val extra = raiseFlattenJson.encodeToString(this)
|
||||||
return FlatMetadata(
|
return FlatMetadata(
|
||||||
SearchMetadata(
|
SearchMetadata(
|
||||||
mangaId,
|
mangaId,
|
||||||
@ -122,7 +140,25 @@ abstract class RaisedSearchMetadata {
|
|||||||
(this).filter { it.type != TAG_TYPE_VIRTUAL }
|
(this).filter { it.type != TAG_TYPE_VIRTUAL }
|
||||||
.joinToString { (if (it.namespace != null) "${it.namespace}: " else "") + it.name }
|
.joinToString { (if (it.namespace != null) "${it.namespace}: " else "") + it.name }
|
||||||
|
|
||||||
val raiseFlattenGson: Gson = GsonBuilder().create()
|
private val module = SerializersModule {
|
||||||
|
polymorphic(RaisedSearchMetadata::class) {
|
||||||
|
subclass(EHentaiSearchMetadata::class)
|
||||||
|
subclass(EightMusesSearchMetadata::class)
|
||||||
|
subclass(HBrowseSearchMetadata::class)
|
||||||
|
subclass(HentaiCafeSearchMetadata::class)
|
||||||
|
subclass(HitomiSearchMetadata::class)
|
||||||
|
subclass(MangaDexSearchMetadata::class)
|
||||||
|
subclass(NHentaiSearchMetadata::class)
|
||||||
|
subclass(PervEdenSearchMetadata::class)
|
||||||
|
subclass(PururinSearchMetadata::class)
|
||||||
|
subclass(TsuminoSearchMetadata::class)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val raiseFlattenJson = Json {
|
||||||
|
ignoreUnknownKeys = true
|
||||||
|
serializersModule = module
|
||||||
|
}
|
||||||
|
|
||||||
fun titleDelegate(type: Int) = object : ReadWriteProperty<RaisedSearchMetadata, String?> {
|
fun titleDelegate(type: Int) = object : ReadWriteProperty<RaisedSearchMetadata, String?> {
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package exh.metadata.metadata.base
|
package exh.metadata.metadata.base
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class RaisedTag(
|
data class RaisedTag(
|
||||||
val namespace: String?,
|
val namespace: String?,
|
||||||
val name: String,
|
val name: String,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package exh.metadata.metadata.base
|
package exh.metadata.metadata.base
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class RaisedTitle(
|
data class RaisedTitle(
|
||||||
val title: String,
|
val title: String,
|
||||||
val type: Int = 0
|
val type: Int = 0
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
package exh.metadata.sql.models
|
package exh.metadata.sql.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.Contextual
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class SearchMetadata(
|
data class SearchMetadata(
|
||||||
// Manga ID this gallery is linked to
|
// Manga ID this gallery is linked to
|
||||||
val mangaId: Long,
|
val mangaId: Long,
|
||||||
@ -17,5 +21,6 @@ data class SearchMetadata(
|
|||||||
val extraVersion: Int
|
val extraVersion: Int
|
||||||
) {
|
) {
|
||||||
// Transient information attached to this piece of metadata, useful for caching
|
// Transient information attached to this piece of metadata, useful for caching
|
||||||
var transientCache: Map<String, Any>? = null
|
|
||||||
|
var transientCache: Map<String, @Contextual Any>? = null
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package exh.metadata.sql.models
|
package exh.metadata.sql.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class SearchTag(
|
data class SearchTag(
|
||||||
// Tag identifier, unique
|
// Tag identifier, unique
|
||||||
val id: Long?,
|
val id: Long?,
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package exh.metadata.sql.models
|
package exh.metadata.sql.models
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
data class SearchTitle(
|
data class SearchTitle(
|
||||||
// Title identifier, unique
|
// Title identifier, unique
|
||||||
val id: Long?,
|
val id: Long?,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
package exh
|
package exh.savedsearches
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
|
11
app/src/main/java/exh/savedsearches/JsonSavedSearch.kt
Normal file
11
app/src/main/java/exh/savedsearches/JsonSavedSearch.kt
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package exh.savedsearches
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.json.JsonArray
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class JsonSavedSearch(
|
||||||
|
val name: String,
|
||||||
|
val query: String,
|
||||||
|
val filters: JsonArray
|
||||||
|
)
|
@ -13,9 +13,6 @@ import android.webkit.WebView
|
|||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import com.afollestad.materialdialogs.MaterialDialog
|
import com.afollestad.materialdialogs.MaterialDialog
|
||||||
import com.elvishew.xlog.XLog
|
import com.elvishew.xlog.XLog
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||||
@ -28,6 +25,12 @@ import exh.source.DelegatedHttpSource
|
|||||||
import exh.util.melt
|
import exh.util.melt
|
||||||
import kotlinx.android.synthetic.main.eh_activity_captcha.toolbar
|
import kotlinx.android.synthetic.main.eh_activity_captcha.toolbar
|
||||||
import kotlinx.android.synthetic.main.eh_activity_captcha.webview
|
import kotlinx.android.synthetic.main.eh_activity_captcha.webview
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.MultipartBody
|
import okhttp3.MultipartBody
|
||||||
@ -153,9 +156,9 @@ class BrowserActionActivity : AppCompatActivity() {
|
|||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.map {
|
.map {
|
||||||
val json = JsonParser.parseString(it.body!!.string())
|
val json = Json.decodeFromString<JsonObject>(it.body!!.string())
|
||||||
it.close()
|
it.close()
|
||||||
json["token"].string
|
json["token"]!!.jsonPrimitive.content
|
||||||
}.melt()
|
}.melt()
|
||||||
|
|
||||||
webview.addJavascriptInterface(this@BrowserActionActivity, "exh")
|
webview.addJavascriptInterface(this@BrowserActionActivity, "exh")
|
||||||
@ -317,7 +320,7 @@ class BrowserActionActivity : AppCompatActivity() {
|
|||||||
.build()
|
.build()
|
||||||
).asObservableSuccess()
|
).asObservableSuccess()
|
||||||
}.map { response ->
|
}.map { response ->
|
||||||
JsonParser.parseString(response.body!!.string())["results"][0]["alternatives"][0]["transcript"].string.trim()
|
Json.decodeFromString<JsonObject>(response.body!!.string())["results"]!!.jsonArray[0].jsonObject["alternatives"]!!.jsonArray[0].jsonObject["transcript"]!!.jsonPrimitive.content.trim()
|
||||||
}.toSingle()
|
}.toSingle()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,7 +47,7 @@ class HitomiDescriptionAdapter(
|
|||||||
val meta = controller.presenter.meta
|
val meta = controller.presenter.meta
|
||||||
if (meta == null || meta !is HitomiSearchMetadata) return
|
if (meta == null || meta !is HitomiSearchMetadata) return
|
||||||
|
|
||||||
val genre = meta.type
|
val genre = meta.genre
|
||||||
if (genre != null) {
|
if (genre != null) {
|
||||||
val pair = when (genre) {
|
val pair = when (genre) {
|
||||||
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
"doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||||
|
@ -47,7 +47,7 @@ class PervEdenDescriptionAdapter(
|
|||||||
val meta = controller.presenter.meta
|
val meta = controller.presenter.meta
|
||||||
if (meta == null || meta !is PervEdenSearchMetadata) return
|
if (meta == null || meta !is PervEdenSearchMetadata) return
|
||||||
|
|
||||||
val genre = meta.type
|
val genre = meta.genre
|
||||||
if (genre != null) {
|
if (genre != null) {
|
||||||
val pair = when (genre) {
|
val pair = when (genre) {
|
||||||
"Doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
"Doujinshi" -> Pair(SourceTagsUtil.DOUJINSHI_COLOR, R.string.doujinshi)
|
||||||
|
@ -1,21 +1,20 @@
|
|||||||
package xyz.nulldev.ts.api.http.serializer
|
package xyz.nulldev.ts.api.http.serializer
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.bool
|
|
||||||
import com.github.salomonbrys.kotson.byte
|
|
||||||
import com.github.salomonbrys.kotson.char
|
|
||||||
import com.github.salomonbrys.kotson.double
|
|
||||||
import com.github.salomonbrys.kotson.float
|
|
||||||
import com.github.salomonbrys.kotson.get
|
|
||||||
import com.github.salomonbrys.kotson.int
|
|
||||||
import com.github.salomonbrys.kotson.long
|
|
||||||
import com.github.salomonbrys.kotson.obj
|
|
||||||
import com.github.salomonbrys.kotson.set
|
|
||||||
import com.github.salomonbrys.kotson.short
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import kotlinx.serialization.json.JsonArray
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.boolean
|
||||||
|
import kotlinx.serialization.json.buildJsonArray
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.double
|
||||||
|
import kotlinx.serialization.json.float
|
||||||
|
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
|
||||||
|
import kotlinx.serialization.json.putJsonObject
|
||||||
import kotlin.reflect.KMutableProperty1
|
import kotlin.reflect.KMutableProperty1
|
||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
|
||||||
@ -35,7 +34,7 @@ class FilterSerializer {
|
|||||||
SortSerializer(this)
|
SortSerializer(this)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun serialize(filters: FilterList) = JsonArray().apply {
|
fun serialize(filters: FilterList) = buildJsonArray {
|
||||||
filters.forEach {
|
filters.forEach {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
add(serialize(it as Filter<Any?>))
|
add(serialize(it as Filter<Any?>))
|
||||||
@ -43,26 +42,31 @@ class FilterSerializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun serialize(filter: Filter<Any?>): JsonObject {
|
fun serialize(filter: Filter<Any?>): JsonObject {
|
||||||
val out = JsonObject()
|
|
||||||
for (serializer in serializers) {
|
for (serializer in serializers) {
|
||||||
if (filter::class.isSubclassOf(serializer.clazz)) {
|
if (filter::class.isSubclassOf(serializer.clazz)) {
|
||||||
// TODO Not sure how to deal with the mess of types here
|
// TODO Not sure how to deal with the mess of types here
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
serializer as Serializer<Filter<Any?>>
|
serializer as Serializer<Filter<Any?>>
|
||||||
|
|
||||||
serializer.serialize(out, filter)
|
return buildJsonObject {
|
||||||
|
with(serializer) { serialize(filter) }
|
||||||
|
|
||||||
out[CLASS_MAPPINGS] = JsonObject()
|
val classMappings = mutableListOf<Pair<String, Any>>()
|
||||||
|
|
||||||
serializer.mappings().forEach {
|
serializer.mappings().forEach {
|
||||||
val res = it.second.get(filter)
|
val res = it.second.get(filter)
|
||||||
out[it.first] = res
|
put(it.first, res.toString())
|
||||||
out[CLASS_MAPPINGS][it.first] = res?.javaClass?.name ?: "null"
|
classMappings += it.first to (res?.javaClass?.name ?: "null")
|
||||||
|
}
|
||||||
|
|
||||||
|
putJsonObject(CLASS_MAPPINGS) {
|
||||||
|
classMappings.forEach { (t, u) ->
|
||||||
|
put(t, u.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
put(TYPE, serializer.type)
|
||||||
}
|
}
|
||||||
|
|
||||||
out[TYPE] = serializer.type
|
|
||||||
|
|
||||||
return out
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw IllegalArgumentException("Cannot serialize this Filter object!")
|
throw IllegalArgumentException("Cannot serialize this Filter object!")
|
||||||
@ -71,13 +75,13 @@ class FilterSerializer {
|
|||||||
fun deserialize(filters: FilterList, json: JsonArray) {
|
fun deserialize(filters: FilterList, json: JsonArray) {
|
||||||
filters.zip(json).forEach { (filter, obj) ->
|
filters.zip(json).forEach { (filter, obj) ->
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
deserialize(filter as Filter<Any?>, obj.obj)
|
deserialize(filter as Filter<Any?>, obj.jsonObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deserialize(filter: Filter<Any?>, json: JsonObject) {
|
fun deserialize(filter: Filter<Any?>, json: JsonObject) {
|
||||||
val serializer = serializers.find {
|
val serializer = serializers.find {
|
||||||
it.type == json[TYPE].string
|
it.type == json[TYPE]!!.jsonPrimitive.content
|
||||||
} ?: throw IllegalArgumentException("Cannot deserialize this type!")
|
} ?: throw IllegalArgumentException("Cannot deserialize this type!")
|
||||||
|
|
||||||
// TODO Not sure how to deal with the mess of types here
|
// TODO Not sure how to deal with the mess of types here
|
||||||
@ -88,17 +92,17 @@ class FilterSerializer {
|
|||||||
|
|
||||||
serializer.mappings().forEach {
|
serializer.mappings().forEach {
|
||||||
if (it.second is KMutableProperty1) {
|
if (it.second is KMutableProperty1) {
|
||||||
val obj = json[it.first]
|
val obj = json[it.first]!!.jsonPrimitive
|
||||||
val res: Any? = when (json[CLASS_MAPPINGS][it.first].string) {
|
val res: Any? = when (json[CLASS_MAPPINGS]!!.jsonObject[it.first]!!.jsonPrimitive.content) {
|
||||||
java.lang.Integer::class.java.name -> obj.int
|
java.lang.Integer::class.java.name -> obj.int
|
||||||
java.lang.Long::class.java.name -> obj.long
|
java.lang.Long::class.java.name -> obj.long
|
||||||
java.lang.Float::class.java.name -> obj.float
|
java.lang.Float::class.java.name -> obj.float
|
||||||
java.lang.Double::class.java.name -> obj.double
|
java.lang.Double::class.java.name -> obj.double
|
||||||
java.lang.String::class.java.name -> obj.string
|
java.lang.String::class.java.name -> obj.content
|
||||||
java.lang.Boolean::class.java.name -> obj.bool
|
java.lang.Boolean::class.java.name -> obj.boolean
|
||||||
java.lang.Byte::class.java.name -> obj.byte
|
java.lang.Byte::class.java.name -> obj.content.toByte()
|
||||||
java.lang.Short::class.java.name -> obj.short
|
java.lang.Short::class.java.name -> obj.content.toShort()
|
||||||
java.lang.Character::class.java.name -> obj.char
|
java.lang.Character::class.java.name -> obj.content[0]
|
||||||
"null" -> null
|
"null" -> null
|
||||||
else -> throw IllegalArgumentException("Cannot deserialize this type!")
|
else -> throw IllegalArgumentException("Cannot deserialize this type!")
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
package xyz.nulldev.ts.api.http.serializer
|
package xyz.nulldev.ts.api.http.serializer
|
||||||
|
|
||||||
import com.github.salomonbrys.kotson.bool
|
|
||||||
import com.github.salomonbrys.kotson.int
|
|
||||||
import com.github.salomonbrys.kotson.nullArray
|
|
||||||
import com.github.salomonbrys.kotson.nullObj
|
|
||||||
import com.github.salomonbrys.kotson.set
|
|
||||||
import com.github.salomonbrys.kotson.string
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonNull
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import kotlinx.serialization.json.JsonNull
|
||||||
|
import kotlinx.serialization.json.JsonObject
|
||||||
|
import kotlinx.serialization.json.JsonObjectBuilder
|
||||||
|
import kotlinx.serialization.json.add
|
||||||
|
import kotlinx.serialization.json.boolean
|
||||||
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
|
import kotlinx.serialization.json.int
|
||||||
|
import kotlinx.serialization.json.jsonArray
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import kotlinx.serialization.json.put
|
||||||
|
import kotlinx.serialization.json.putJsonArray
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
import kotlin.reflect.KProperty1
|
import kotlin.reflect.KProperty1
|
||||||
|
|
||||||
interface Serializer<in T : Filter<out Any?>> {
|
interface Serializer<in T : Filter<out Any?>> {
|
||||||
fun serialize(json: JsonObject, filter: T) {}
|
fun JsonObjectBuilder.serialize(filter: T) {}
|
||||||
fun deserialize(json: JsonObject, filter: T) {}
|
fun deserialize(json: JsonObject, filter: T) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -76,9 +79,9 @@ class SelectSerializer(override val serializer: FilterSerializer) : Serializer<F
|
|||||||
override val type = "SELECT"
|
override val type = "SELECT"
|
||||||
override val clazz = Filter.Select::class
|
override val clazz = Filter.Select::class
|
||||||
|
|
||||||
override fun serialize(json: JsonObject, filter: Filter.Select<Any>) {
|
override fun JsonObjectBuilder.serialize(filter: Filter.Select<Any>) {
|
||||||
// Serialize values to JSON
|
// Serialize values to JSON
|
||||||
json[VALUES] = JsonArray().apply {
|
putJsonArray(VALUES) {
|
||||||
filter.values.map {
|
filter.values.map {
|
||||||
it.toString()
|
it.toString()
|
||||||
}.forEach { add(it) }
|
}.forEach { add(it) }
|
||||||
@ -146,15 +149,15 @@ class GroupSerializer(override val serializer: FilterSerializer) : Serializer<Fi
|
|||||||
override val type = "GROUP"
|
override val type = "GROUP"
|
||||||
override val clazz = Filter.Group::class
|
override val clazz = Filter.Group::class
|
||||||
|
|
||||||
override fun serialize(json: JsonObject, filter: Filter.Group<Any?>) {
|
override fun JsonObjectBuilder.serialize(filter: Filter.Group<Any?>) {
|
||||||
json[STATE] = JsonArray().apply {
|
putJsonArray(STATE) {
|
||||||
filter.state.forEach {
|
filter.state.forEach {
|
||||||
add(
|
add(
|
||||||
if (it is Filter<*>) {
|
if (it is Filter<*>) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
serializer.serialize(it as Filter<Any?>)
|
serializer.serialize(it as Filter<Any?>)
|
||||||
} else {
|
} else {
|
||||||
JsonNull.INSTANCE
|
JsonNull
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -162,10 +165,10 @@ class GroupSerializer(override val serializer: FilterSerializer) : Serializer<Fi
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun deserialize(json: JsonObject, filter: Filter.Group<Any?>) {
|
override fun deserialize(json: JsonObject, filter: Filter.Group<Any?>) {
|
||||||
json[STATE].asJsonArray.forEachIndexed { index, jsonElement ->
|
json[STATE]!!.jsonArray.forEachIndexed { index, jsonElement ->
|
||||||
if (!jsonElement.isJsonNull) {
|
if (jsonElement !is JsonNull) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
serializer.deserialize(filter.state[index] as Filter<Any?>, jsonElement.asJsonObject)
|
serializer.deserialize(filter.state[index] as Filter<Any?>, jsonElement.jsonObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,27 +187,29 @@ class SortSerializer(override val serializer: FilterSerializer) : Serializer<Fil
|
|||||||
override val type = "SORT"
|
override val type = "SORT"
|
||||||
override val clazz = Filter.Sort::class
|
override val clazz = Filter.Sort::class
|
||||||
|
|
||||||
override fun serialize(json: JsonObject, filter: Filter.Sort) {
|
override fun JsonObjectBuilder.serialize(filter: Filter.Sort) {
|
||||||
// Serialize values
|
// Serialize values
|
||||||
json[VALUES] = JsonArray().apply {
|
putJsonArray(VALUES) {
|
||||||
filter.values.forEach { add(it) }
|
filter.values.forEach { add(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serialize state
|
// Serialize state
|
||||||
json[STATE] = filter.state?.let { (index, ascending) ->
|
put(
|
||||||
JsonObject().apply {
|
STATE,
|
||||||
this[STATE_INDEX] = index
|
filter.state?.let { (index, ascending) ->
|
||||||
this[STATE_ASCENDING] = ascending
|
buildJsonObject {
|
||||||
}
|
put(STATE_INDEX, index)
|
||||||
} ?: JsonNull.INSTANCE
|
put(STATE_ASCENDING, ascending)
|
||||||
|
}
|
||||||
|
} ?: JsonNull
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserialize(json: JsonObject, filter: Filter.Sort) {
|
override fun deserialize(json: JsonObject, filter: Filter.Sort) {
|
||||||
// Deserialize state
|
// Deserialize state
|
||||||
filter.state = json[STATE].nullObj?.let {
|
filter.state = (json[STATE] as? JsonObject)?.let {
|
||||||
Filter.Sort.Selection(
|
Filter.Sort.Selection(
|
||||||
it[STATE_INDEX].int,
|
it[STATE_INDEX]!!.jsonPrimitive.int,
|
||||||
it[STATE_ASCENDING].bool
|
it[STATE_ASCENDING]!!.jsonPrimitive.boolean
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,19 +232,17 @@ class AutoCompleteSerializer(override val serializer: FilterSerializer) : Serial
|
|||||||
override val type = "AUTOCOMPLETE"
|
override val type = "AUTOCOMPLETE"
|
||||||
override val clazz = Filter.AutoComplete::class
|
override val clazz = Filter.AutoComplete::class
|
||||||
|
|
||||||
override fun serialize(json: JsonObject, filter: Filter.AutoComplete) {
|
override fun JsonObjectBuilder.serialize(filter: Filter.AutoComplete) {
|
||||||
// Serialize values to JSON
|
// Serialize values to JSON
|
||||||
json[STATE] = JsonArray().apply {
|
putJsonArray(STATE) {
|
||||||
filter.state.forEach { add(it) }
|
filter.state.forEach { add(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun deserialize(json: JsonObject, filter: Filter.AutoComplete) {
|
override fun deserialize(json: JsonObject, filter: Filter.AutoComplete) {
|
||||||
// Deserialize state
|
// Deserialize state
|
||||||
json[STATE].nullArray?.let { array ->
|
filter.state = json[STATE]!!.jsonArray.map {
|
||||||
filter.state = array.map {
|
it.jsonPrimitive.content
|
||||||
it.string
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user