diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt index 9d16ddb5bc..fe9e9e65d6 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuApi.kt @@ -24,6 +24,22 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) .build() .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 { return Observable.defer { // @formatter:off @@ -48,7 +64,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) ) ) ) - // @formatter:on rest.addLibManga(jsonObject("data" to data)) .map { json -> @@ -77,12 +92,25 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } } + fun search(query: String): Observable> { - 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> { + val jsonObject = jsonObject("params" to "query=$query$algoliaFilter") + return algoliaRest + .getSearchQuery(algoliaAppId, key, jsonObject) .map { json -> - val data = json["data"].array - data.map { KitsuManga(it.obj) } - .filter { it.type != "novel" } + val data = json["hits"].array + data.map { KitsuSearchManga(it.obj) } + .filter { it.subType != "novel" } .map { it.toTrack() } } } @@ -143,10 +171,6 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) @Body data: JsonObject ): Observable - @GET("manga") - fun search( - @Query("filter[text]", encoded = true) query: String - ): Observable @GET("library-entries") fun findLibManga( @@ -168,6 +192,16 @@ class KitsuApi(private val client: OkHttpClient, interceptor: KitsuInterceptor) } + private interface SearchKeyRest { + @GET("media/") + fun getKey(): Observable + } + + 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 + } + private interface LoginRest { @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 loginUrl = "https://kitsu.io/api/" 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 { return baseMangaUrl + remoteId diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt index 70fdef6d92..5334b0cd4a 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/track/kitsu/KitsuModels.kt @@ -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.model.TrackSearch -open class KitsuManga(obj: JsonObject) { +class KitsuSearchManga(obj: JsonObject) { val id by obj.byInt - val canonicalTitle by obj["attributes"].byString - val chapterCount = obj["attributes"].obj.get("chapterCount").nullInt - val type = obj["attributes"].obj.get("mangaType").nullString.orEmpty() - val original by obj["attributes"].obj["posterImage"].byString - val synopsis by obj["attributes"].byString - val startDate = obj["attributes"].obj.get("startDate").nullString.orEmpty() - open val status = obj["attributes"].obj.get("status").nullString.orEmpty() + private val canonicalTitle by obj.byString + private val chapterCount = obj.get("chapterCount").nullInt + val subType = obj.get("subType").nullString + val original by obj["posterImage"].byString + private val synopsis by obj.byString + private val startDate = obj.get("startDate").nullString + private val endDate = obj.get("endDate").nullString @CallSuper open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply { - media_id = this@KitsuManga.id + media_id = this@KitsuSearchManga.id title = canonicalTitle total_chapters = chapterCount ?: 0 cover_url = original summary = synopsis 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() } } -class KitsuLibManga(obj: JsonObject, manga: JsonObject) : KitsuManga(manga) { - val libraryId by obj.byInt("id") - override val status by obj["attributes"].byString - val ratingTwenty = obj["attributes"].obj.get("ratingTwenty").nullString + +class KitsuLibManga(obj: JsonObject, manga: JsonObject) { + val id by manga.byInt + 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 - override fun toTrack() = super.toTrack().apply { - media_id = libraryId // TODO migrate media ids to library ids + open fun toTrack() = TrackSearch.create(TrackManager.KITSU).apply { + 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() score = ratingTwenty?.let { it.toInt() / 2f } ?: 0f last_chapter_read = progress