From 4c3d741a7c03790bf9e4421ab80a5d0834141a7a Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Thu, 25 Aug 2022 13:44:13 +0200 Subject: [PATCH] Rename and fix Crunchyroll --- {Kamyroll => Crunchyroll}/build.gradle.kts | 2 +- .../src/main/AndroidManifest.xml | 0 .../kotlin/com/lagradost/CookieInterceptor.kt | 46 +++++++ .../com/lagradost/CrunchyrollProvider.kt | 120 ++++++++++-------- .../lagradost/CrunchyrollProviderPlugin.kt | 2 +- .../main/kotlin/com/lagradost/HttpSession.kt | 50 -------- 6 files changed, 112 insertions(+), 108 deletions(-) rename {Kamyroll => Crunchyroll}/build.gradle.kts (97%) rename {Kamyroll => Crunchyroll}/src/main/AndroidManifest.xml (100%) create mode 100644 Crunchyroll/src/main/kotlin/com/lagradost/CookieInterceptor.kt rename Kamyroll/src/main/kotlin/com/lagradost/KrunchyProvider.kt => Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProvider.kt (85%) rename Kamyroll/src/main/kotlin/com/lagradost/KrunchyProviderPlugin.kt => Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProviderPlugin.kt (89%) delete mode 100644 Kamyroll/src/main/kotlin/com/lagradost/HttpSession.kt diff --git a/Kamyroll/build.gradle.kts b/Crunchyroll/build.gradle.kts similarity index 97% rename from Kamyroll/build.gradle.kts rename to Crunchyroll/build.gradle.kts index 37a5de6..f650b1c 100644 --- a/Kamyroll/build.gradle.kts +++ b/Crunchyroll/build.gradle.kts @@ -1,5 +1,5 @@ // use an integer for version numbers -version = 2 +version = 3 cloudstream { diff --git a/Kamyroll/src/main/AndroidManifest.xml b/Crunchyroll/src/main/AndroidManifest.xml similarity index 100% rename from Kamyroll/src/main/AndroidManifest.xml rename to Crunchyroll/src/main/AndroidManifest.xml diff --git a/Crunchyroll/src/main/kotlin/com/lagradost/CookieInterceptor.kt b/Crunchyroll/src/main/kotlin/com/lagradost/CookieInterceptor.kt new file mode 100644 index 0000000..ff11972 --- /dev/null +++ b/Crunchyroll/src/main/kotlin/com/lagradost/CookieInterceptor.kt @@ -0,0 +1,46 @@ +package com.lagradost + +import com.lagradost.nicehttp.Requests +import okhttp3.* +import okhttp3.internal.parseCookie + +/** + * An HTTP session manager. + * + * This class simply keeps cookies across requests. No security about which site should use which cookies. + * + */ + +class CustomSession( + client: OkHttpClient +) : Requests() { + var cookies = mutableMapOf() + + init { + this.baseClient = client + .newBuilder() + .addInterceptor { + val time = System.currentTimeMillis() + val request = it.request() + request.headers.forEach { header -> + if (header.first.equals("cookie", ignoreCase = true)) { + val cookie = parseCookie(time, request.url, header.second) ?: return@forEach + cookies += cookie.name to cookie + } + } + it.proceed(request) + } + .cookieJar(CustomCookieJar()) + .build() + } + + inner class CustomCookieJar : CookieJar { + override fun loadForRequest(url: HttpUrl): List { + return this@CustomSession.cookies.values.toList() + } + + override fun saveFromResponse(url: HttpUrl, cookies: List) { + this@CustomSession.cookies += cookies.map { it.name to it } + } + } +} \ No newline at end of file diff --git a/Kamyroll/src/main/kotlin/com/lagradost/KrunchyProvider.kt b/Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProvider.kt similarity index 85% rename from Kamyroll/src/main/kotlin/com/lagradost/KrunchyProvider.kt rename to Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProvider.kt index 2cf771a..dc3a2af 100644 --- a/Kamyroll/src/main/kotlin/com/lagradost/KrunchyProvider.kt +++ b/Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProvider.kt @@ -2,14 +2,15 @@ package com.lagradost import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.* +import com.lagradost.cloudstream3.APIHolder.capitalize import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.getQualityFromName import com.lagradost.nicehttp.NiceResponse +import kotlinx.coroutines.delay import org.jsoup.Jsoup -import java.net.URI import java.util.* private fun String.toAscii() = this.map { it.code }.joinToString() @@ -18,14 +19,16 @@ class KrunchyGeoBypasser { companion object { const val BYPASS_SERVER = "https://cr-unblocker.us.to/start_session" val headers = mapOf( - "Accept" to "*/*", - "Accept-Encoding" to "gzip, deflate", - "Connection" to "keep-alive", - "Referer" to "https://google.com/", - "User-Agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36".toAscii() + "accept" to "*/*", +// "Accept-Encoding" to "gzip, deflate", + "connection" to "keep-alive", +// "Referer" to "https://google.com/", + "user-agent" to "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36".toAscii() ) var sessionId: String? = null - val session = HttpSession() + + // val interceptor = CookieInterceptor() + val session = CustomSession(app.baseClient) } data class KrunchySession( @@ -54,6 +57,8 @@ class KrunchyGeoBypasser { private suspend fun autoLoadSession(): Boolean { if (sessionId != null) return true getSessionId() + // Do not spam the api! + delay(3000) return autoLoadSession() } @@ -69,6 +74,7 @@ class KrunchyProvider : MainAPI() { val episodeNumRegex = Regex("""Episode (\d+)""") } + // Do not make https! It will fail! override var mainUrl = "http://www.crunchyroll.com" override var name: String = "Crunchyroll" override var lang = "en" @@ -87,13 +93,15 @@ class KrunchyProvider : MainAPI() { ) override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { + println("GETMAINPAGE ") val categoryData = request.data + val paginated = categoryData.endsWith("=") val pagedLink = if (paginated) categoryData + page else categoryData val items = mutableListOf() // Only fetch page at first-time load of homepage - if (page <= 1) { + if (page <= 1 && request.name == "Popular") { val doc = Jsoup.parse(crUnblock.geoBypassRequest(mainUrl).text) val featured = doc.select(".js-featured-show-list > li").mapNotNull { anime -> val url = @@ -145,7 +153,9 @@ class KrunchyProvider : MainAPI() { ) ) } - items.add(HomePageList("Featured", featured)) + if (featured.isNotEmpty()) { + items.add(HomePageList("Featured", featured)) + } } if (paginated || !paginated && page <= 1) { @@ -176,25 +186,23 @@ class KrunchyProvider : MainAPI() { } if (items.isNotEmpty()) { - return newHomePageResponse(items.toList() - ) + return newHomePageResponse(items) } throw ErrorLoadingException() } - private fun getCloseMatches(sequence: String, items: Collection): ArrayList { - val closeMatches = ArrayList() + // Maybe fuzzy match in the future + private fun getCloseMatches(sequence: String, items: Collection): List { val a = sequence.trim().lowercase() - for (item in items) { + return items.mapNotNull { item -> val b = item.trim().lowercase() - if (b.contains(a)) { - closeMatches.add(item) - } else if (a.contains(b)) { - closeMatches.add(item) - } + if (b.contains(a)) + item + else if (a.contains(b)) + item + else null } - return closeMatches } private data class CrunchyAnimeData( @@ -261,7 +269,7 @@ class KrunchyProvider : MainAPI() { } val genres = soup.select(".large-margin-bottom > ul:nth-child(2) li:nth-child(2) a") - .map { it.text() } + .map { it.text().capitalize() } val year = genres.filter { it.toIntOrNull() != null }.map { it.toInt() }.sortedBy { it } .getOrNull(0) @@ -364,7 +372,19 @@ class KrunchyProvider : MainAPI() { @JsonProperty("url") val url: String, @JsonProperty("resolution") val resolution: String?, @JsonProperty("title") var title: String? - ) + ) { + fun title(): String { + return when { + this.hardsubLang == "enUS" && this.audioLang == "jaJP" -> "Hardsub (English)" + this.hardsubLang == "esLA" && this.audioLang == "jaJP" -> "Hardsub (Latino)" + this.hardsubLang == "esES" && this.audioLang == "jaJP" -> "Hardsub (Español España)" + this.audioLang == "esLA" -> "Latino" + this.audioLang == "esES" -> "Español España" + this.audioLang == "enUS" -> "English (US)" + else -> "RAW" + } + } + } data class KrunchyVideo( @JsonProperty("streams") val streams: List, @@ -387,6 +407,7 @@ class KrunchyProvider : MainAPI() { if (!dat.isNullOrEmpty()) { val json = parseJson(dat) val streams = ArrayList() + for (stream in json.streams) { if ( listOf( @@ -408,21 +429,13 @@ class KrunchyProvider : MainAPI() { "enUS", null ).contains(stream.hardsubLang)) - && URI(stream.url).path.endsWith(".m3u") - +// && URI(stream.url).path.endsWith(".m3u") ) { - stream.title = - if (stream.hardsubLang == "enUS" && stream.audioLang == "jaJP") "Hardsub (English)" - else if (stream.hardsubLang == "esLA" && stream.audioLang == "jaJP") "Hardsub (Latino)" - else if (stream.hardsubLang == "esES" && stream.audioLang == "jaJP") "Hardsub (Español España)" - else if (stream.audioLang == "esLA") "Latino" - else if (stream.audioLang == "esES") "Español España" - else if (stream.audioLang == "enUS") "English (US)" - else "RAW" + stream.title = stream.title() streams.add(stream) } - //Premium eps - if (stream.format == "trailer_hls" && listOf( + // Premium eps + else if (stream.format == "trailer_hls" && listOf( "jaJP", "esLA", "esES", @@ -430,34 +443,29 @@ class KrunchyProvider : MainAPI() { ).contains(stream.audioLang) && (listOf("esLA", "esES", "enUS", null).contains(stream.hardsubLang)) ) { - stream.title = - if (stream.hardsubLang == "enUS" && stream.audioLang == "jaJP") "Hardsub (English)" - else if (stream.hardsubLang == "esLA" && stream.audioLang == "jaJP") "Hardsub (Latino)" - else if (stream.hardsubLang == "esES" && stream.audioLang == "jaJP") "Hardsub (Español España)" - else if (stream.audioLang == "esLA") "Latino" - else if (stream.audioLang == "esES") "Español España" - else if (stream.audioLang == "enUS") "English (US)" - else "RAW" + stream.title = stream.title() streams.add(stream) } } } + streams.apmap { stream -> if (stream.url.contains("m3u8") && stream.format!!.contains("adaptive")) { - hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(stream.url, null), false).apmap { - callback( - ExtractorLink( - "Crunchyroll", - "Crunchy - ${stream.title} - ${it.quality}p", - it.streamUrl, - "", - getQualityFromName(it.quality.toString()), - true + hlsHelper.m3u8Generation(M3u8Helper.M3u8Stream(stream.url, null), false) + .forEach { + callback( + ExtractorLink( + "Crunchyroll", + "Crunchy - ${stream.title}", + it.streamUrl, + "", + getQualityFromName(it.quality.toString()), + true + ) ) - ) - } + } } else if (stream.format == "trailer_hls") { - val premiumstream = stream.url + val premiumStream = stream.url .replace("\\/", "/") .replace(Regex("\\/clipFrom.*?index.m3u8"), "").replace("'_,'", "'_'") .replace(stream.url.split("/")[2], "fy.v.vrv.co") @@ -465,7 +473,7 @@ class KrunchyProvider : MainAPI() { ExtractorLink( this.name, "Crunchy - ${stream.title} ★", - premiumstream, + premiumStream, "", Qualities.Unknown.value, false @@ -473,7 +481,7 @@ class KrunchyProvider : MainAPI() { ) } else null } - json.subtitles.apmap { + json.subtitles.forEach { val langclean = it.language.replace("esLA", "Spanish") .replace("enUS", "English") .replace("esES", "Spanish (Spain)") diff --git a/Kamyroll/src/main/kotlin/com/lagradost/KrunchyProviderPlugin.kt b/Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProviderPlugin.kt similarity index 89% rename from Kamyroll/src/main/kotlin/com/lagradost/KrunchyProviderPlugin.kt rename to Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProviderPlugin.kt index e8d3291..26997ee 100644 --- a/Kamyroll/src/main/kotlin/com/lagradost/KrunchyProviderPlugin.kt +++ b/Crunchyroll/src/main/kotlin/com/lagradost/CrunchyrollProviderPlugin.kt @@ -6,7 +6,7 @@ import com.lagradost.cloudstream3.plugins.Plugin import android.content.Context @CloudstreamPlugin -class KrunchyProviderPlugin: Plugin() { +class CrunchyrollProviderPlugin: Plugin() { override fun load(context: Context) { // All providers should be added in this manner. Please don't edit the providers list directly. registerMainAPI(KrunchyProvider()) diff --git a/Kamyroll/src/main/kotlin/com/lagradost/HttpSession.kt b/Kamyroll/src/main/kotlin/com/lagradost/HttpSession.kt deleted file mode 100644 index bce399b..0000000 --- a/Kamyroll/src/main/kotlin/com/lagradost/HttpSession.kt +++ /dev/null @@ -1,50 +0,0 @@ -package com.lagradost -//Credits https://github.com/ArjixWasTaken/CloudStream-3/blob/master/app/src/main/java/com/ArjixWasTaken/cloudstream3/utils/HttpSession.kt -import com.lagradost.cloudstream3.app -import com.lagradost.nicehttp.NiceResponse - -/** - * An HTTP session manager. - * - * This class simply keeps cookies across requests. - * - * @property sessionCookies A cookie jar. - * - * TODO: be replaced with built in Session once that works as it should. - */ -class HttpSession { - private val sessionCookies: MutableMap = mutableMapOf() - - suspend fun get( - url: String, - headers: Map = mapOf(), - cookies: Map = mapOf(), - ): NiceResponse { - sessionCookies.putAll(cookies) - val res = - app.get( - url, - headers, - cookies = sessionCookies, - ) - sessionCookies.putAll(res.headers.filter { it.first.lowercase() == "set-cookie" }) - return res - } - - suspend fun post( - url: String, - headers: Map = mapOf(), - cookies: Map = mapOf(), - ): NiceResponse { - sessionCookies.putAll(cookies) - val res = - app.post( - url, - headers, - cookies = sessionCookies, - ) - - sessionCookies.putAll(res.headers.filter { it.first.lowercase() == "set-cookie" }) - return res - } -} \ No newline at end of file