From 3cc5bdb4602982edaa5e96345ca9cd543eaeb94d Mon Sep 17 00:00:00 2001 From: hexated Date: Fri, 20 Jan 2023 07:33:01 +0700 Subject: [PATCH] more fix missing anime in Crunchyroll --- .../main/kotlin/com/hexated/SoraExtractor.kt | 36 ++++++++----- .../src/main/kotlin/com/hexated/SoraStream.kt | 1 + .../src/main/kotlin/com/hexated/SoraUtils.kt | 53 +++++++++++++++++-- 3 files changed, 72 insertions(+), 18 deletions(-) diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt index 2b901518..a06caaec 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraExtractor.kt @@ -1665,20 +1665,7 @@ object SoraExtractor : SoraStream() { subtitleCallback: (SubtitleFile) -> Unit, callback: (ExtractorLink) -> Unit ) { - val res = (searchCrunchyroll(title) - ?: searchCrunchyroll(title?.substringBefore(" ")))?.results - - val id = (if (res?.size == 1) { - res.firstOrNull() - } else { - res?.find { - (it.title.equals( - title, - true - ) || it.title.fixTitle().equals(title.fixTitle(), true)) && it.type.equals("series") - } - })?.id ?: return - + val id = searchCrunchyrollAnimeId(title ?: return) ?: searchKamyrollAnimeId(title) ?: return val detail = app.get("$consumetCrunchyrollAPI/info?id=$id&mediaType=series").text val epsId = tryParseJson(detail)?.findCrunchyrollId( title, @@ -2259,4 +2246,25 @@ data class MediaAni( data class DataAni( @JsonProperty("data") val data: MediaAni? = null, +) + +data class KamyrollSearch( + @JsonProperty("items") var items: ArrayList = arrayListOf() +) + +data class KamyrollItems( + @JsonProperty("type") var type: String? = null, + @JsonProperty("items") var items: ArrayList = arrayListOf() +) + +data class KamyrollAnimes( + @JsonProperty("id") var id: String? = null, + @JsonProperty("slug_title") var slugTitle: String? = null, + @JsonProperty("title") var title: String? = null, + @JsonProperty("media_type") var mediaType: String? = null +) + +data class KamyrollToken( + @JsonProperty("access_token") val access_token: String? = null, + @JsonProperty("token_type") val token_type: String? = null, ) \ No newline at end of file diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt index 68d5a2d5..8bb3fd46 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraStream.kt @@ -62,6 +62,7 @@ open class SoraStream : TmdbProvider() { const val jikanAPI = "https://api.jikan.moe/v4" const val gdbot = "https://gdbot.xyz" const val consumetAnilistAPI = "https://api.consumet.org/meta/anilist" + const val kamyrollAPI = "https://api.kamyroll.tech" private val mainAPI = base64DecodeAPI("cHA=LmE=ZWw=cmM=dmU=aC4=dGM=d2E=eHA=Ly8=czo=dHA=aHQ=") diff --git a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt index f4c69c5b..ae8cf713 100644 --- a/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt +++ b/SoraStream/src/main/kotlin/com/hexated/SoraUtils.kt @@ -3,6 +3,7 @@ package com.hexated import com.hexated.SoraStream.Companion.consumetCrunchyrollAPI import com.hexated.SoraStream.Companion.filmxyAPI import com.hexated.SoraStream.Companion.gdbot +import com.hexated.SoraStream.Companion.kamyrollAPI import com.hexated.SoraStream.Companion.tvMoviesAPI import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.getCaptchaToken @@ -469,9 +470,53 @@ fun Document.findTvMoviesIframe(): String? { ?.substringBefore("'>") } -suspend fun searchCrunchyroll(title: String?) : ConsumetSearchResponse? { - return app.get("${consumetCrunchyrollAPI}/$title") - .parsedSafe() +suspend fun searchKamyrollAnimeId(title: String): String? { + return app.get( + "$kamyrollAPI/content/v1/search", + headers = getCrunchyrollToken(), + params = mapOf( + "query" to title, + "channel_id" to "crunchyroll", + "limit" to "10", + ) + ).parsedSafe()?.items?.find { item -> + item.items.any { + (it.title?.contains(title, true) == true || it.slugTitle?.contains( + "${title.fixTitle()}", + true + ) == true) && it.mediaType == "series" + } + }?.items?.firstOrNull()?.id +} + +suspend fun searchCrunchyrollAnimeId(title: String): String? { + val res = app.get("${consumetCrunchyrollAPI}/$title") + .parsedSafe()?.results + return (if (res?.size == 1) { + res.firstOrNull() + } else { + res?.find { + (it.title?.contains( + title, + true + ) == true || it.title.fixTitle() + ?.contains("${title.fixTitle()}", true) == true) && it.type.equals("series") + } + })?.id +} + +suspend fun getCrunchyrollToken(): Map { + val res = app.get( + "$kamyrollAPI/auth/v1/token", + params = mapOf( + "device_id" to "com.service.data", + "device_type" to "sorastream", + "access_token" to "HMbQeThWmZq4t7w", + ) + ).parsedSafe() + return mapOf( + "Authorization" to "${res?.token_type} ${res?.access_token}" + ) } fun CrunchyrollDetails.findCrunchyrollId( @@ -497,7 +542,7 @@ fun List>?.matchingEpisode(episode: Int?): String? { } fun String?.fixTitle(): String? { - return this?.replace(Regex("[!%:'?]|( &)"), "")?.replace(" ", "-")?.lowercase() + return this?.replace(Regex("[!%:'?,]|( &)"), "")?.replace(" ", "-")?.lowercase() ?.replace("-–-", "-") }