Changed Kitsu to use Algoria search directly (#1514)
* Changed Kitsu to use Algoria search directly, was recommended by the Kitsu Dev team * remove extra line * fixed end date bug added filtering out novel back in * save the retrofit instances locally for search.
This commit is contained in:
parent
136e90638a
commit
fd825b1049
@ -24,6 +24,22 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
.build()
|
.build()
|
||||||
.create(KitsuApi.Rest::class.java)
|
.create(KitsuApi.Rest::class.java)
|
||||||
|
|
||||||
|
private val searchRest = Retrofit.Builder()
|
||||||
|
.baseUrl(algoliaKeyUrl)
|
||||||
|
.client(client)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||||
|
.build()
|
||||||
|
.create(KitsuApi.SearchKeyRest::class.java)
|
||||||
|
|
||||||
|
private val algoliaRest = Retrofit.Builder()
|
||||||
|
.baseUrl(algoliaUrl)
|
||||||
|
.client(client)
|
||||||
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
|
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
|
||||||
|
.build()
|
||||||
|
.create(KitsuApi.AgoliaSearchRest::class.java)
|
||||||
|
|
||||||
fun addLibManga(track: Track, userId: String): Observable<Track> {
|
fun addLibManga(track: Track, userId: String): Observable<Track> {
|
||||||
return Observable.defer {
|
return Observable.defer {
|
||||||
// @formatter:off
|
// @formatter:off
|
||||||
@ -48,7 +64,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
// @formatter:on
|
|
||||||
|
|
||||||
rest.addLibManga(jsonObject("data" to data))
|
rest.addLibManga(jsonObject("data" to data))
|
||||||
.map { json ->
|
.map { json ->
|
||||||
@ -77,12 +92,25 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun search(query: String): Observable<List<TrackSearch>> {
|
fun search(query: String): Observable<List<TrackSearch>> {
|
||||||
return rest.search(query)
|
return searchRest
|
||||||
|
.getKey().map { json ->
|
||||||
|
json["media"].asJsonObject["key"].string
|
||||||
|
}.flatMap { key ->
|
||||||
|
algoliaSearch(key, query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun algoliaSearch(key: String, query: String): Observable<List<TrackSearch>> {
|
||||||
|
val jsonObject = jsonObject("params" to "query=$query$algoliaFilter")
|
||||||
|
return algoliaRest
|
||||||
|
.getSearchQuery(algoliaAppId, key, jsonObject)
|
||||||
.map { json ->
|
.map { json ->
|
||||||
val data = json["data"].array
|
val data = json["hits"].array
|
||||||
data.map { KitsuManga(it.obj) }
|
data.map { KitsuSearchManga(it.obj) }
|
||||||
.filter { it.type != "novel" }
|
.filter { it.subType != "novel" }
|
||||||
.map { it.toTrack() }
|
.map { it.toTrack() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -143,10 +171,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
@Body data: JsonObject
|
@Body data: JsonObject
|
||||||
): Observable<JsonObject>
|
): Observable<JsonObject>
|
||||||
|
|
||||||
@GET("manga")
|
|
||||||
fun search(
|
|
||||||
@Query("filter[text]", encoded = true) query: String
|
|
||||||
): Observable<JsonObject>
|
|
||||||
|
|
||||||
@GET("library-entries")
|
@GET("library-entries")
|
||||||
fun findLibManga(
|
fun findLibManga(
|
||||||
@ -168,6 +192,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private interface SearchKeyRest {
|
||||||
|
@GET("media/")
|
||||||
|
fun getKey(): Observable<JsonObject>
|
||||||
|
}
|
||||||
|
|
||||||
|
private interface AgoliaSearchRest {
|
||||||
|
@POST("query/")
|
||||||
|
fun getSearchQuery(@Header("X-Algolia-Application-Id") appid: String, @Header("X-Algolia-API-Key") key: String, @Body json: JsonObject): Observable<JsonObject>
|
||||||
|
}
|
||||||
|
|
||||||
private interface LoginRest {
|
private interface LoginRest {
|
||||||
|
|
||||||
@FormUrlEncoded
|
@FormUrlEncoded
|
||||||
@ -188,6 +222,11 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor)
|
|||||||
private const val baseUrl = "https://kitsu.io/api/edge/"
|
private const val baseUrl = "https://kitsu.io/api/edge/"
|
||||||
private const val loginUrl = "https://kitsu.io/api/"
|
private const val loginUrl = "https://kitsu.io/api/"
|
||||||
private const val baseMangaUrl = "https://kitsu.io/manga/"
|
private const val baseMangaUrl = "https://kitsu.io/manga/"
|
||||||
|
private const val algoliaKeyUrl = "https://kitsu.io/api/edge/algolia-keys/"
|
||||||
|
private const val algoliaUrl = "https://AWQO5J657S-dsn.algolia.net/1/indexes/production_media/"
|
||||||
|
private const val algoliaAppId = "AWQO5J657S"
|
||||||
|
private const val algoliaFilter = "&facetFilters=%5B%22kind%3Amanga%22%5D&attributesToRetrieve=%5B%22synopsis%22%2C%22canonicalTitle%22%2C%22chapterCount%22%2C%22posterImage%22%2C%22startDate%22%2C%22subtype%22%2C%22endDate%22%2C%20%22id%22%5D"
|
||||||
|
|
||||||
|
|
||||||
fun mangaUrl(remoteId: Int): String {
|
fun mangaUrl(remoteId: Int): String {
|
||||||
return baseMangaUrl + remoteId
|
return baseMangaUrl + remoteId
|
||||||
|
@ -7,38 +7,59 @@ import eu.kanade.tachiyomi.data.database.models.Track
|
|||||||
import eu.kanade.tachiyomi.data.track.TrackManager
|
import eu.kanade.tachiyomi.data.track.TrackManager
|
||||||
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
import eu.kanade.tachiyomi.data.track.model.TrackSearch
|
||||||
|
|
||||||
open class KitsuManga(obj: JsonObject) {
|
class KitsuSearchManga(obj: JsonObject) {
|
||||||
val id by obj.byInt
|
val id by obj.byInt
|
||||||
val canonicalTitle by obj["attributes"].byString
|
private val canonicalTitle by obj.byString
|
||||||
val chapterCount = obj["attributes"].obj.get("chapterCount").nullInt
|
private val chapterCount = obj.get("chapterCount").nullInt
|
||||||
val type = obj["attributes"].obj.get("mangaType").nullString.orEmpty()
|
val subType = obj.get("subType").nullString
|
||||||
val original by obj["attributes"].obj["posterImage"].byString
|
val original by obj["posterImage"].byString
|
||||||
val synopsis by obj["attributes"].byString
|
private val synopsis by obj.byString
|
||||||
val startDate = obj["attributes"].obj.get("startDate").nullString.orEmpty()
|
private val startDate = obj.get("startDate").nullString
|
||||||
open val status = obj["attributes"].obj.get("status").nullString.orEmpty()
|
private val endDate = obj.get("endDate").nullString
|
||||||
|
|
||||||
@CallSuper
|
@CallSuper
|
||||||
open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
|
open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
|
||||||
media_id = this@KitsuManga.id
|
media_id = this@KitsuSearchManga.id
|
||||||
title = canonicalTitle
|
title = canonicalTitle
|
||||||
total_chapters = chapterCount ?: 0
|
total_chapters = chapterCount ?: 0
|
||||||
cover_url = original
|
cover_url = original
|
||||||
summary = synopsis
|
summary = synopsis
|
||||||
tracking_url = KitsuApi.mangaUrl(media_id)
|
tracking_url = KitsuApi.mangaUrl(media_id)
|
||||||
publishing_status = this@KitsuManga.status
|
|
||||||
publishing_type = type
|
if (endDate == null) {
|
||||||
|
publishing_status = "Publishing"
|
||||||
|
} else {
|
||||||
|
publishing_status = "Finished"
|
||||||
|
}
|
||||||
|
publishing_type = subType ?: ""
|
||||||
start_date = startDate.orEmpty()
|
start_date = startDate.orEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) {
|
|
||||||
val libraryId by obj.byInt("id")
|
class KitsuLibManga(obj: JsonObject, manga: JsonObject) {
|
||||||
override val status by obj["attributes"].byString
|
val id by manga.byInt
|
||||||
val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
|
private val canonicalTitle by manga["attributes"].byString
|
||||||
|
private val chapterCount = manga["attributes"].obj.get("chapterCount").nullInt
|
||||||
|
val type = manga["attributes"].obj.get("mangaType").nullString.orEmpty()
|
||||||
|
val original by manga["attributes"].obj["posterImage"].byString
|
||||||
|
private val synopsis by manga["attributes"].byString
|
||||||
|
private val startDate = manga["attributes"].obj.get("startDate").nullString.orEmpty()
|
||||||
|
private val libraryId by obj.byInt("id")
|
||||||
|
val status by obj["attributes"].byString
|
||||||
|
private val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString
|
||||||
val progress by obj["attributes"].byInt
|
val progress by obj["attributes"].byInt
|
||||||
|
|
||||||
override fun toTrack() = super.toTrack().apply {
|
open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply {
|
||||||
media_id = libraryId // TODO migrate media ids to library ids
|
media_id = libraryId
|
||||||
|
title = canonicalTitle
|
||||||
|
total_chapters = chapterCount ?: 0
|
||||||
|
cover_url = original
|
||||||
|
summary = synopsis
|
||||||
|
tracking_url = KitsuApi.mangaUrl(media_id)
|
||||||
|
publishing_status = this@KitsuLibManga.status
|
||||||
|
publishing_type = type
|
||||||
|
start_date = startDate
|
||||||
status = toTrackStatus()
|
status = toTrackStatus()
|
||||||
score = ratingTwenty?.let { it.toInt() / 2f } ?: 0f
|
score = ratingTwenty?.let { it.toInt() / 2f } ?: 0f
|
||||||
last_chapter_read = progress
|
last_chapter_read = progress
|
||||||
|
Loading…
Reference in New Issue
Block a user