mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-10-30 22:07:57 +01:00 
			
		
		
		
	Implement MyAnimeList recommendations (#7)
Co-authored-by: she11sh0cked <she11sh0cked@users.noreply.github.com>
This commit is contained in:
		| @@ -10,6 +10,7 @@ import com.google.gson.JsonParser | ||||
| import eu.kanade.tachiyomi.network.asObservableSuccess | ||||
| import eu.kanade.tachiyomi.source.model.MangasPage | ||||
| import eu.kanade.tachiyomi.source.model.SMangaImpl | ||||
| import okhttp3.HttpUrl.Companion.toHttpUrlOrNull | ||||
| import okhttp3.MediaType.Companion.toMediaTypeOrNull | ||||
| import okhttp3.OkHttpClient | ||||
| import okhttp3.Request | ||||
| @@ -17,10 +18,81 @@ import okhttp3.RequestBody.Companion.toRequestBody | ||||
| import rx.Observable | ||||
| import rx.schedulers.Schedulers | ||||
|  | ||||
| open class RecommendsPager(val title: String) : Pager() { | ||||
| open class RecommendsPager(val title: String, val preferredApi: API = API.MYANIMELIST) : Pager() { | ||||
|     private val client = OkHttpClient.Builder().build() | ||||
|  | ||||
|     override fun requestNext(): Observable<MangasPage> { | ||||
|     private fun myAnimeList(): Observable<List<SMangaImpl>>? { | ||||
|         fun getId(): Observable<String> { | ||||
|             val endpoint = | ||||
|                 myAnimeListEndpoint.toHttpUrlOrNull() | ||||
|                     ?: throw Exception("Could not convert endpoint url") | ||||
|             val urlBuilder = endpoint.newBuilder() | ||||
|             urlBuilder.addPathSegment("search") | ||||
|             urlBuilder.addPathSegment("manga") | ||||
|             urlBuilder.addQueryParameter("q", title) | ||||
|             val url = urlBuilder.build().toUrl() | ||||
|  | ||||
|             val request = Request.Builder() | ||||
|                 .url(url) | ||||
|                 .get() | ||||
|                 .build() | ||||
|  | ||||
|             return client.newCall(request) | ||||
|                 .asObservableSuccess().subscribeOn(Schedulers.io()) | ||||
|                 .map { netResponse -> | ||||
|                     val responseBody = netResponse.body?.string().orEmpty() | ||||
|                     if (responseBody.isEmpty()) { | ||||
|                         throw Exception("Null Response") | ||||
|                     } | ||||
|                     val response = JsonParser.parseString(responseBody).obj | ||||
|                     val results = response["results"].array | ||||
|                     val firstResult = results[0].obj | ||||
|                     val id = firstResult["mal_id"].string | ||||
|                     if (id.isEmpty()) { | ||||
|                         throw Exception("Not found") | ||||
|                     } | ||||
|                     id | ||||
|                 } | ||||
|         } | ||||
|  | ||||
|         return getId().map { id -> | ||||
|             val endpoint = | ||||
|                 myAnimeListEndpoint.toHttpUrlOrNull() | ||||
|                     ?: throw Exception("Could not convert endpoint url") | ||||
|             val urlBuilder = endpoint.newBuilder() | ||||
|             urlBuilder.addPathSegment("manga") | ||||
|             urlBuilder.addPathSegment(id) | ||||
|             urlBuilder.addPathSegment("recommendations") | ||||
|             val url = urlBuilder.build().toUrl() | ||||
|  | ||||
|             val request = Request.Builder() | ||||
|                 .url(url) | ||||
|                 .get() | ||||
|                 .build() | ||||
|  | ||||
|             client.newCall(request) | ||||
|                 .asObservableSuccess().subscribeOn(Schedulers.io()) | ||||
|                 .map { netResponse -> | ||||
|                     val responseBody = netResponse.body?.string().orEmpty() | ||||
|                     if (responseBody.isEmpty()) { | ||||
|                         throw Exception("Null Response") | ||||
|                     } | ||||
|                     val response = JsonParser.parseString(responseBody).obj | ||||
|                     val recommendations = response["recommendations"].array | ||||
|                     recommendations.map { rec -> | ||||
|                         Log.d("MYANIMELIST RECOMMEND", "${rec["title"].string}") | ||||
|                         SMangaImpl().apply { | ||||
|                             this.title = rec["title"].string | ||||
|                             this.thumbnail_url = rec["image_url"].string | ||||
|                             this.initialized = true | ||||
|                             this.url = rec["url"].string | ||||
|                         } | ||||
|                     } | ||||
|                 }.toBlocking().first() | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun anilist(): Observable<List<SMangaImpl>>? { | ||||
|         val query = | ||||
|             """ | ||||
|             { | ||||
| @@ -53,7 +125,7 @@ open class RecommendsPager(val title: String) : Pager() { | ||||
|         ) | ||||
|         val body = payload.toString().toRequestBody("application/json; charset=utf-8".toMediaTypeOrNull()) | ||||
|         val request = Request.Builder() | ||||
|             .url(apiUrl) | ||||
|             .url(anilistEndpoint) | ||||
|             .post(body) | ||||
|             .build() | ||||
|  | ||||
| @@ -71,7 +143,7 @@ open class RecommendsPager(val title: String) : Pager() { | ||||
|                 val edges = recommendations["edges"].array | ||||
|                 edges.map { | ||||
|                     val rec = it["node"]["mediaRecommendation"].obj | ||||
|                     Log.d("RECOMMEND", "${rec["title"].obj["romaji"].string}") | ||||
|                     Log.d("ANILIST RECOMMEND", "${rec["title"].obj["romaji"].string}") | ||||
|                     SMangaImpl().apply { | ||||
|                         this.title = rec["title"].obj["romaji"].string | ||||
|                         this.thumbnail_url = rec["coverImage"].obj["large"].string | ||||
| @@ -79,13 +151,39 @@ open class RecommendsPager(val title: String) : Pager() { | ||||
|                         this.url = rec["siteUrl"].string | ||||
|                     } | ||||
|                 } | ||||
|             }.map { | ||||
|                 MangasPage(it, false) | ||||
|             }.doOnNext { | ||||
|                 onPageReceived(it) | ||||
|             } | ||||
|     } | ||||
|  | ||||
|     override fun requestNext(): Observable<MangasPage> { | ||||
|         val apiList = API.values().toMutableList() | ||||
|         apiList.removeAt(apiList.indexOf(preferredApi)) | ||||
|         apiList.add(0, preferredApi) | ||||
|  | ||||
|         var recommendations: Observable<List<SMangaImpl>>? = null | ||||
|         for (api in apiList) { | ||||
|             recommendations = when (api) { | ||||
|                 API.MYANIMELIST -> myAnimeList() | ||||
|                 API.ANILIST -> anilist() | ||||
|             } | ||||
|                 ?: throw Exception("Could not get recommendations") | ||||
|  | ||||
|             val recommendationsBlocking = recommendations.toBlocking().first() | ||||
|             if (recommendationsBlocking.isNotEmpty()) { | ||||
|                 break | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return recommendations!!.map { | ||||
|             MangasPage(it, false) | ||||
|         }.doOnNext { | ||||
|             onPageReceived(it) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         const val apiUrl = "https://graphql.anilist.co/" | ||||
|         private const val myAnimeListEndpoint = "https://api.jikan.moe/v3/" | ||||
|         private const val anilistEndpoint = "https://graphql.anilist.co/" | ||||
|  | ||||
|         enum class API { MYANIMELIST, ANILIST } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user