* refactor: use NoResultsException * refactor: cleanup RecommendationPagingSources * refactor: turn wake/wifi lock functions into reusable extensions * feat: implement batch recommendation (initial version) * fix: serialization issues * fix: wrong source id * refactor: increase performance using virtual paging * refactor: update string * refactor: handle 404 of MD source correctly * style: add newline * refactor: create universal throttle manager * refactor: throttle requests * chore: remove unused strings * feat: rank recommendations by match count * feat: add badges indicating match count to batch recommendations * fix: handle rec search with no results * fix: validate flags in pre-search bottom sheet * feat: implement 'hide library entries' for recommendation search using custom SmartSearchEngine for library items * style: run spotless * fix: cancel button * fix: racing condition causing loss of state * Avoid runBlocking in a property getter * Remove unnecessary `synchronized` * Fixes screen staying on in library tab. (jobobby04/TachiyomiSY#1451) (cherry picked from commit 254980695bc39fe064e7aeb181ecdbf70c1eff95) --------- Co-authored-by: Cuong-Tran <cuongtran.tm@gmail.com> Co-authored-by: NGB-Was-Taken <76197326+NGB-Was-Taken@users.noreply.github.com>
114 lines
4 KiB
Kotlin
114 lines
4 KiB
Kotlin
package exh.recs.sources
|
|
|
|
import dev.icerock.moko.resources.StringResource
|
|
import eu.kanade.tachiyomi.network.GET
|
|
import eu.kanade.tachiyomi.network.POST
|
|
import eu.kanade.tachiyomi.network.awaitSuccess
|
|
import eu.kanade.tachiyomi.network.parseAs
|
|
import eu.kanade.tachiyomi.source.model.SManga
|
|
import kotlinx.serialization.json.JsonArray
|
|
import kotlinx.serialization.json.JsonElement
|
|
import kotlinx.serialization.json.JsonObject
|
|
import kotlinx.serialization.json.buildJsonObject
|
|
import kotlinx.serialization.json.contentOrNull
|
|
import kotlinx.serialization.json.jsonArray
|
|
import kotlinx.serialization.json.jsonObject
|
|
import kotlinx.serialization.json.jsonPrimitive
|
|
import kotlinx.serialization.json.put
|
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
import okhttp3.MediaType.Companion.toMediaType
|
|
import okhttp3.RequestBody.Companion.toRequestBody
|
|
import tachiyomi.core.common.util.system.logcat
|
|
import tachiyomi.data.source.NoResultsException
|
|
import tachiyomi.domain.manga.model.Manga
|
|
import tachiyomi.i18n.sy.SYMR
|
|
|
|
abstract class MangaUpdatesPagingSource(manga: Manga) : TrackerRecommendationPagingSource(
|
|
"https://api.mangaupdates.com/v1/",
|
|
manga,
|
|
) {
|
|
override val name: String
|
|
get() = "MangaUpdates"
|
|
|
|
override val associatedTrackerId: Long
|
|
get() = trackerManager.mangaUpdates.id
|
|
|
|
protected abstract val recommendationJsonObjectName: String
|
|
|
|
override suspend fun getRecsById(id: String): List<SManga> {
|
|
val apiUrl = endpoint.toHttpUrl()
|
|
.newBuilder()
|
|
.addPathSegment("series")
|
|
.addPathSegment(id)
|
|
.build()
|
|
|
|
val data = with(json) { client.newCall(GET(apiUrl)).awaitSuccess().parseAs<JsonObject>() }
|
|
return getRecommendations(data[recommendationJsonObjectName]!!.jsonArray)
|
|
}
|
|
|
|
private fun getRecommendations(recommendations: JsonArray): List<SManga> {
|
|
return recommendations
|
|
.map(JsonElement::jsonObject)
|
|
.map { rec ->
|
|
logcat { "MANGAUPDATES > RECOMMENDATION: " + rec["series_name"]!!.jsonPrimitive.content }
|
|
SManga(
|
|
title = rec["series_name"]!!.jsonPrimitive.content,
|
|
url = rec["series_url"]!!.jsonPrimitive.content,
|
|
thumbnail_url = rec["series_image"]
|
|
?.jsonObject
|
|
?.get("url")
|
|
?.jsonObject
|
|
?.get("original")
|
|
?.jsonPrimitive
|
|
?.contentOrNull,
|
|
initialized = true,
|
|
)
|
|
}
|
|
}
|
|
|
|
override suspend fun getRecsBySearch(search: String): List<SManga> {
|
|
val url = endpoint.toHttpUrl()
|
|
.newBuilder()
|
|
.addPathSegments("series/search")
|
|
.build()
|
|
.toString()
|
|
|
|
val payload = buildJsonObject {
|
|
put("search", search)
|
|
put("stype", "title")
|
|
}
|
|
|
|
val body = payload
|
|
.toString()
|
|
.toRequestBody("application/json; charset=utf-8".toMediaType())
|
|
|
|
val data = with(json) {
|
|
client.newCall(POST(url, body = body))
|
|
.awaitSuccess()
|
|
.parseAs<JsonObject>()
|
|
}
|
|
return getRecsById(
|
|
data["results"]!!
|
|
.jsonArray
|
|
.ifEmpty { throw NoResultsException() }
|
|
.first()
|
|
.jsonObject["record"]!!
|
|
.jsonObject["series_id"]!!
|
|
.jsonPrimitive.content,
|
|
)
|
|
}
|
|
}
|
|
|
|
class MangaUpdatesCommunityPagingSource(manga: Manga) : MangaUpdatesPagingSource(manga) {
|
|
override val category: StringResource
|
|
get() = SYMR.strings.community_recommendations
|
|
override val recommendationJsonObjectName: String
|
|
get() = "recommendations"
|
|
}
|
|
|
|
class MangaUpdatesSimilarPagingSource(manga: Manga) : MangaUpdatesPagingSource(manga) {
|
|
override val category: StringResource
|
|
get() = SYMR.strings.similar_titles
|
|
override val recommendationJsonObjectName: String
|
|
get() = "category_recommendations"
|
|
}
|