mirror of
				https://github.com/hexated/cloudstream-extensions-hexated.git
				synced 2024-08-15 00:03:22 +00:00 
			
		
		
		
	sora: fixed Crunchyroll and Zoro
This commit is contained in:
		
							parent
							
								
									92803be98d
								
							
						
					
					
						commit
						93c948bb8e
					
				
					 6 changed files with 298 additions and 461 deletions
				
			
		
							
								
								
									
										4
									
								
								.github/workflows/build.yml
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/build.yml
									
										
									
									
										vendored
									
									
								
							|  | @ -46,12 +46,16 @@ jobs: | |||
|           SORAHE: ${{ secrets.SORAHE }} | ||||
|           SORAXA: ${{ secrets.SORAXA }} | ||||
|           SORATED: ${{ secrets.SORATED }} | ||||
|           CRUNCHYROLL_BASIC_TOKEN: ${{ secrets.CRUNCHYROLL_BASIC_TOKEN }} | ||||
|           CRUNCHYROLL_REFRESH_TOKEN: ${{ secrets.CRUNCHYROLL_REFRESH_TOKEN }} | ||||
|         run: | | ||||
|           cd $GITHUB_WORKSPACE/src | ||||
|           echo SORA_API=$SORA_API >> local.properties | ||||
|           echo SORAHE=$SORAHE >> local.properties | ||||
|           echo SORAXA=$SORAXA >> local.properties | ||||
|           echo SORATED=$SORATED >> local.properties | ||||
|           echo CRUNCHYROLL_BASIC_TOKEN=$CRUNCHYROLL_BASIC_TOKEN >> local.properties | ||||
|           echo CRUNCHYROLL_REFRESH_TOKEN=$CRUNCHYROLL_REFRESH_TOKEN >> local.properties | ||||
| 
 | ||||
|       - name: Build Plugins | ||||
|         run: | | ||||
|  |  | |||
|  | @ -12,6 +12,8 @@ android { | |||
|         buildConfigField("String", "SORAHE", "\"${properties.getProperty("SORAHE")}\"") | ||||
|         buildConfigField("String", "SORAXA", "\"${properties.getProperty("SORAXA")}\"") | ||||
|         buildConfigField("String", "SORATED", "\"${properties.getProperty("SORATED")}\"") | ||||
|         buildConfigField("String", "CRUNCHYROLL_BASIC_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_BASIC_TOKEN")}\"") | ||||
|         buildConfigField("String", "CRUNCHYROLL_REFRESH_TOKEN", "\"${properties.getProperty("CRUNCHYROLL_REFRESH_TOKEN")}\"") | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
|  |  | |||
|  | @ -45,7 +45,9 @@ object SoraExtractor : SoraStream() { | |||
|                 val link = source.link ?: return@let | ||||
|                 if (link.contains("rabbitstream")) { | ||||
|                     extractRabbitStream( | ||||
|                         "Vidcloud", | ||||
|                         link, | ||||
|                         "$twoEmbedAPI/", | ||||
|                         subtitleCallback, | ||||
|                         callback, | ||||
|                         false, | ||||
|  | @ -188,21 +190,6 @@ object SoraExtractor : SoraStream() { | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     suspend fun invokeDatabaseGdrive( | ||||
|         imdbId: String? = null, | ||||
|         season: Int? = null, | ||||
|         episode: Int? = null, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ) { | ||||
|         val url = if (season == null) { | ||||
|             "$databaseGdriveAPI/player.php?imdb=$imdbId" | ||||
|         } else { | ||||
|             "$databaseGdriveAPI/player.php?type=series&imdb=$imdbId&season=$season&episode=$episode" | ||||
|         } | ||||
|         loadExtractor(url, databaseGdriveAPI, subtitleCallback, callback) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun invokeHDMovieBox( | ||||
|         title: String? = null, | ||||
|         season: Int? = null, | ||||
|  | @ -327,14 +314,13 @@ object SoraExtractor : SoraStream() { | |||
|         }, { | ||||
|             val iv = "9225679083961858" | ||||
|             val secretKey = "25742532592138496744665879883281" | ||||
|             val secretDecryptKey = secretKey | ||||
|             GogoHelper.extractVidstream( | ||||
|                 iframe.url, | ||||
|                 "Vidstream", | ||||
|                 callback, | ||||
|                 iv, | ||||
|                 secretKey, | ||||
|                 secretDecryptKey, | ||||
|                 secretKey, | ||||
|                 isUsingAdaptiveKeys = false, | ||||
|                 isUsingAdaptiveData = true, | ||||
|                 iframeDocument = iframeDoc | ||||
|  | @ -496,13 +482,12 @@ object SoraExtractor : SoraStream() { | |||
|         } else { | ||||
|             "${filmxyAPI}/tv/$imdbId" | ||||
|         } | ||||
|         val filmxyCookies = | ||||
|             getFilmxyCookies(imdbId, season) ?: throw ErrorLoadingException("No Cookies Found") | ||||
|         val filmxyCookies = getFilmxyCookies(imdbId, season) | ||||
| 
 | ||||
|         val cookiesDoc = mapOf( | ||||
|             "G_ENABLED_IDPS" to "google", | ||||
|             "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" to "${filmxyCookies.wLog}", | ||||
|             "PHPSESSID" to "${filmxyCookies.phpsessid}" | ||||
|             "wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01" to (filmxyCookies.wLog ?: return), | ||||
|             "PHPSESSID" to (filmxyCookies.phpsessid ?: return) | ||||
|         ) | ||||
| 
 | ||||
|         val doc = session.get(url, cookies = cookiesDoc).document | ||||
|  | @ -868,85 +853,10 @@ object SoraExtractor : SoraStream() { | |||
|             { | ||||
|                 invokeBiliBili(aniId, episode, subtitleCallback, callback) | ||||
|             }, | ||||
| //            { | ||||
| //                if (season != null) invokeAllanime(aniId, title, jpTitle, episode, callback) | ||||
| //            } | ||||
|         ) | ||||
|             { | ||||
|                 if (season != null) invokeCrunchyroll(aniId, epsTitle, season, episode, subtitleCallback, callback) | ||||
|             } | ||||
| 
 | ||||
|     private suspend fun invokeAllanime( | ||||
|         aniId: String? = null, | ||||
|         title: String? = null, | ||||
|         jpTitle: String? = null, | ||||
|         episode: Int? = null, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ) { | ||||
|         val aniDetail = | ||||
|             app.get("$consumetAnilistAPI/info/$aniId").parsedSafe<ConsumetDetails>() ?: return | ||||
|         val edges = app.get( | ||||
|             allanimeQueries( | ||||
|                 """{"search":{"query":"$title","allowAdult":false,"allowUnknown":false},"limit":26,"page":1,"translationType":"sub","countryOrigin":"ALL"}""", | ||||
|                 allanimeSearchQuery | ||||
|         ) | ||||
|         ) | ||||
|             .parsedSafe<AllanimeResponses>()?.data?.shows?.edges | ||||
|         val id = edges?.let { edge -> | ||||
|             if (edges.size == 1) { | ||||
|                 edge.firstOrNull() | ||||
|             } else { | ||||
|                 edge.find { | ||||
|                     (it.thumbnail == aniDetail.cover || it.thumbnail == aniDetail.image) || ( | ||||
|                             (it.name.equals( | ||||
|                                 aniDetail.title?.romaji, | ||||
|                                 true | ||||
|                             ) || it.name.equals( | ||||
|                                 jpTitle, | ||||
|                                 true | ||||
|                             ) || it.englishName.equals(aniDetail.title?.english, true)) | ||||
|                                     && it.airedStart?.year == aniDetail.releaseDate) | ||||
|                 } ?: edge.find { | ||||
|                     it.name.equals( | ||||
|                         aniDetail.title?.romaji, | ||||
|                         true | ||||
|                     ) || it.name.equals( | ||||
|                         jpTitle, | ||||
|                         true | ||||
|                     ) || it.englishName.equals( | ||||
|                         aniDetail.title?.english, | ||||
|                         true | ||||
|                     ) || it.englishName.equals(title, true) | ||||
|                 } | ||||
|             } | ||||
|         }?._id ?: return | ||||
| 
 | ||||
|         listOf( | ||||
|             "sub", | ||||
|             "dub" | ||||
|         ).apmap { tl -> | ||||
|             val server = app.get( | ||||
|                 allanimeQueries( | ||||
|                     """{"showId":"$id","translationType":"$tl","episodeString":"$episode"}""", | ||||
|                     allanimeServerQuery | ||||
|                 ) | ||||
|             ) | ||||
|                 .parsedSafe<AllanimeResponses>()?.data?.episode?.sourceUrls?.find { it.sourceName == "Ac" } | ||||
|             val serverUrl = fixUrl( | ||||
|                 server?.sourceUrl?.replace("/clock", "/clock.json") ?: return@apmap, | ||||
|                 "https://blog.allanime.pro" | ||||
|             ) | ||||
|             app.get(serverUrl) | ||||
|                 .parsedSafe<AllanimeLinks>()?.links?.filter { it.resolutionStr == "RAW" && it.hls == true } | ||||
|                 ?.forEach { source -> | ||||
|                     val translation = if (tl == "sub") "Raw" else "English Dub" | ||||
|                     M3u8Helper.generateM3u8( | ||||
|                         "Vrv [$translation]", | ||||
|                         source.link ?: return@apmap, | ||||
|                         "https://static.crunchyroll.com/", | ||||
|                     ).forEach(callback) | ||||
|                 } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun invokeBiliBili( | ||||
|  | @ -999,41 +909,47 @@ object SoraExtractor : SoraStream() { | |||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ) { | ||||
|         val episodeId = app.get("$consumetAnilistAPI/info/$aniId?provider=zoro") | ||||
|             .parsedSafe<ConsumetDetails>()?.episodes?.find { | ||||
|                 it.number == (episode ?: 1) | ||||
|             }?.id?.substringBeforeLast("$") ?: return | ||||
|         val animeId = | ||||
|             app.get("https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/anilist/anime/$aniId.json") | ||||
|                 .parsedSafe<MALSyncResponses>()?.pages?.zoro?.keys?.firstOrNull() | ||||
| 
 | ||||
|         listOf( | ||||
|             "$episodeId\$sub" to "Raw", | ||||
|             "$episodeId\$dub" to "English Dub", | ||||
|         ).apmap { (id, type) -> | ||||
|             val sources = app.get("$consumetZoroAPI/watch?episodeId=$id") | ||||
|                 .parsedSafe<ConsumetSourcesResponse>() ?: return@apmap null | ||||
|         val episodeId = app.get("$zoroAPI/ajax/v2/episode/list/${animeId ?: return}") | ||||
|             .parsedSafe<ZoroResponses>()?.html?.let { | ||||
|                 Jsoup.parse(it) | ||||
|             }?.select("div.ss-list a")?.find { it.attr("data-number") == "$episode" } | ||||
|             ?.attr("data-id") | ||||
| 
 | ||||
|             sources.sources?.map sources@{ | ||||
|                 callback.invoke( | ||||
|                     ExtractorLink( | ||||
|                         "Zoro [$type]", | ||||
|                         "Zoro [$type]", | ||||
|                         it.url ?: return@sources null, | ||||
|                         "", | ||||
|                         getQualityFromName(it.quality), | ||||
|                         it.isM3U8 ?: true | ||||
|                     ) | ||||
|         val servers = app.get("$zoroAPI/ajax/v2/episode/servers?episodeId=${episodeId ?: return}") | ||||
|             .parsedSafe<ZoroResponses>()?.html?.let { Jsoup.parse(it) } | ||||
|             ?.select("div.item.server-item")?.map { | ||||
|                 Triple( | ||||
|                     it.text(), | ||||
|                     it.attr("data-id"), | ||||
|                     it.attr("data-type"), | ||||
|                 ) | ||||
|             } | ||||
| 
 | ||||
|             sources.subtitles?.map subtitles@{ | ||||
|                 subtitleCallback.invoke( | ||||
|                     SubtitleFile( | ||||
|                         it.lang ?: "", | ||||
|                         it.url ?: return@subtitles null | ||||
|                     ) | ||||
|                 ) | ||||
|         servers?.apmap { server -> | ||||
|             val iframe = app.get("$zoroAPI/ajax/v2/episode/sources?id=${server.second ?: return@apmap}") | ||||
|                 .parsedSafe<ZoroResponses>()?.link ?: return@apmap | ||||
|             val audio = if(server.third == "sub") "Raw" else "English Dub" | ||||
|             if(server.first == "Vidstreaming" || server.first == "Vidcloud") { | ||||
|                 extractRabbitStream( | ||||
|                     "${server.first} [$audio]", | ||||
|                     iframe, | ||||
|                     "$zoroAPI/", | ||||
|                     subtitleCallback, | ||||
|                     callback, | ||||
|                     false, | ||||
|                     decryptKey = RabbitStream.getZoroKey() | ||||
|                 ) { it } | ||||
|             } else { | ||||
|                 loadExtractor(iframe,"$zoroAPI/", subtitleCallback, callback) | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     private suspend fun invokeAnimeKaizoku( | ||||
|  | @ -1551,52 +1467,78 @@ object SoraExtractor : SoraStream() { | |||
|     } | ||||
| 
 | ||||
|     suspend fun invokeCrunchyroll( | ||||
|         title: String? = null, | ||||
|         aniId: String? = null, | ||||
|         epsTitle: String? = null, | ||||
|         season: Int? = null, | ||||
|         episode: Int? = null, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit | ||||
|     ) { | ||||
|         val id = searchCrunchyrollAnimeId(title ?: return) ?: return | ||||
|         val detail = | ||||
|             app.get("$consumetCrunchyrollAPI/info/$id?fetchAllSeasons=true", timeout = 600L).text | ||||
|         val epsId = tryParseJson<CrunchyrollDetails>(detail)?.findCrunchyrollId( | ||||
|             season, | ||||
|             episode, | ||||
|             epsTitle | ||||
|         val id = getCrunchyrollId(aniId) ?: return | ||||
|         val audioLocal = listOf( | ||||
|             "ja-JP", | ||||
|             "en-US", | ||||
|             "zh-CN", | ||||
|         ) | ||||
|         val headers = getCrunchyrollToken() | ||||
|         val seasonIdData = app.get("$crunchyrollAPI/content/v2/cms/series/$id/seasons", headers = headers) | ||||
|             .parsedSafe<CrunchyrollResponses>()?.data?.let { s -> | ||||
|                 if (s.size == 1) { | ||||
|                     s.firstOrNull() | ||||
|                 } else { | ||||
|                     s.find { | ||||
|                         when (epsTitle) { | ||||
|                             "One Piece" -> it.season_number == 13 | ||||
|                             "Hunter x Hunter" -> it.season_number == 5 | ||||
|                             else -> it.season_number == season | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         val seasonId = seasonIdData?.versions?.filter { it.audio_locale in audioLocal } | ||||
|             ?.map { it.guid to it.audio_locale } | ||||
| 
 | ||||
|         epsId?.apmap { | ||||
|             delay(2000) | ||||
|             val json = | ||||
|         seasonId?.apmap { (sId, audioL) -> | ||||
|             val streamsLink = | ||||
|                 app.get( | ||||
|                     "$consumetCrunchyrollAPI/watch/${it?.first?.id ?: return@apmap null}", | ||||
|                     timeout = 600L | ||||
|                 ) | ||||
|                     .parsedSafe<ConsumetSourcesResponse>() | ||||
| 
 | ||||
|             json?.sources?.map source@{ source -> | ||||
|                 callback.invoke( | ||||
|                     ExtractorLink( | ||||
|                         "Crunchyroll", | ||||
|                         "Crunchyroll [${it.second ?: ""}]", | ||||
|                         source.url ?: return@source null, | ||||
|                         "https://static.crunchyroll.com/", | ||||
|                         source.quality?.removeSuffix("p")?.toIntOrNull() ?: return@source null, | ||||
|                     "$crunchyrollAPI/content/v2/cms/seasons/${sId ?: return@apmap}/episodes", | ||||
|                     headers = headers | ||||
|                 ).parsedSafe<CrunchyrollResponses>()?.data?.find { | ||||
|                     it.title.equals(epsTitle, true) || it.slug_title.equals( | ||||
|                         epsTitle.createSlug(), | ||||
|                         true | ||||
|                     ) | ||||
|                 ) | ||||
|                     ) || it.episode_number == episode | ||||
|                 }?.streams_link | ||||
|             val sources = | ||||
|                 app.get(fixUrl(streamsLink ?: return@apmap, crunchyrollAPI), headers = headers) | ||||
|                     .parsedSafe<CrunchyrollSourcesResponses>() | ||||
| 
 | ||||
|             listOf( | ||||
|                 "adaptive_hls", | ||||
|                 "vo_adaptive_hls" | ||||
|             ).map { hls -> | ||||
|                 val name = if (hls == "adaptive_hls") "Crunchyroll" else "Vrv" | ||||
|                 val audio = if (audioL == "en-US") "English Dub" else "Raw" | ||||
|                 val source = sources?.data?.firstOrNull()?.let { | ||||
|                     if (hls == "adaptive_hls") it.adaptive_hls else it.vo_adaptive_hls | ||||
|                 } | ||||
|                 M3u8Helper.generateM3u8( | ||||
|                     "$name [$audio]", | ||||
|                     source?.get("")?.get("url") ?: return@map, | ||||
|                     "https://static.crunchyroll.com/" | ||||
|                 ).forEach(callback) | ||||
|             } | ||||
| 
 | ||||
|             json?.subtitles?.map subtitle@{ sub -> | ||||
|             sources?.meta?.subtitles?.map { sub -> | ||||
|                 subtitleCallback.invoke( | ||||
|                     SubtitleFile( | ||||
|                         "${fixCrunchyrollLang(sub.lang ?: return@subtitle null) ?: sub.lang} [ass]", | ||||
|                         sub.url ?: return@subtitle null | ||||
|                         "${fixCrunchyrollLang(sub.key) ?: sub.key} [ass]", | ||||
|                         sub.value["url"] ?: return@map null | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -1900,6 +1842,7 @@ object SoraExtractor : SoraStream() { | |||
|         imdbId: String? = null, | ||||
|         season: Int? = null, | ||||
|         episode: Int? = null, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit, | ||||
|     ) { | ||||
|         val url = if (season == null) { | ||||
|  | @ -1927,6 +1870,9 @@ object SoraExtractor : SoraStream() { | |||
|                 it.first.contains("/nflim") -> { | ||||
|                     invokeSmashyNflim(it.second, it.first, callback) | ||||
|                 } | ||||
|                 it.first.contains("/rip") -> { | ||||
|                     invokeSmashyRip(it.second, it.first, subtitleCallback, callback) | ||||
|                 } | ||||
|                 else -> return@apmap | ||||
|             } | ||||
|         } | ||||
|  | @ -2121,46 +2067,6 @@ object SoraExtractor : SoraStream() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun invokePapaonMovies1( | ||||
|         apiUrl: String, | ||||
|         api: String, | ||||
|         title: String? = null, | ||||
|         year: Int? = null, | ||||
|         season: Int? = null, | ||||
|         episode: Int? = null, | ||||
|         callback: (ExtractorLink) -> Unit, | ||||
|     ) { | ||||
|         invokeIndex( | ||||
|             apiUrl, | ||||
|             api, | ||||
|             title, | ||||
|             year, | ||||
|             season, | ||||
|             episode, | ||||
|             callback, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun invokePapaonMovies2( | ||||
|         apiUrl: String, | ||||
|         api: String, | ||||
|         title: String? = null, | ||||
|         year: Int? = null, | ||||
|         season: Int? = null, | ||||
|         episode: Int? = null, | ||||
|         callback: (ExtractorLink) -> Unit, | ||||
|     ) { | ||||
|         invokeIndex( | ||||
|             apiUrl, | ||||
|             api, | ||||
|             title, | ||||
|             year, | ||||
|             season, | ||||
|             episode, | ||||
|             callback, | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun invokeJmdkhMovies( | ||||
|         apiUrl: String, | ||||
|         api: String, | ||||
|  | @ -2700,7 +2606,7 @@ object SoraExtractor : SoraStream() { | |||
|         season: Int? = null, | ||||
|         callback: (ExtractorLink) -> Unit, | ||||
|     ) { | ||||
|         val monsterMainUrl = "https://freedoze.monster" | ||||
|         val monsterMainUrl = "https://mobirs.monster" | ||||
|         val playSlug = if (season == null) { | ||||
|             "movies/play/$urlSlug" | ||||
|         } else { | ||||
|  | @ -2713,7 +2619,7 @@ object SoraExtractor : SoraStream() { | |||
|         val res = app.get(url).document | ||||
|         val script = res.selectFirst("script:containsData(window['show_storage'])")?.data() | ||||
|         val hash = Regex("hash:\\s*['\"](\\S+)['\"],").find(script ?: return)?.groupValues?.get(1) | ||||
|         val expires = Regex("expires:\\s*(\\d+),").find(script ?: return)?.groupValues?.get(1) | ||||
|         val expires = Regex("expires:\\s*(\\d+),").find(script)?.groupValues?.get(1) | ||||
| 
 | ||||
|         val videoUrl = if (season == null) { | ||||
|             "$monsterMainUrl/api/v1/security/movie-access?id_movie=$episodeId&hash=$hash&expires=$expires" | ||||
|  | @ -3051,71 +2957,6 @@ data class Load( | |||
|     @JsonProperty("data") val data: MediaDetail? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetHeaders( | ||||
|     @JsonProperty("Referer") val referer: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetSubtitles( | ||||
|     @JsonProperty("url") val url: String? = null, | ||||
|     @JsonProperty("lang") val lang: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetSources( | ||||
|     @JsonProperty("url") val url: String? = null, | ||||
|     @JsonProperty("quality") val quality: String? = null, | ||||
|     @JsonProperty("isM3U8") val isM3U8: Boolean? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetSourcesResponse( | ||||
|     @JsonProperty("headers") val headers: ConsumetHeaders? = null, | ||||
|     @JsonProperty("sources") val sources: ArrayList<ConsumetSources>? = arrayListOf(), | ||||
|     @JsonProperty("subtitles") val subtitles: ArrayList<ConsumetSubtitles>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetEpisodes( | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
|     @JsonProperty("type") val type: String? = null, | ||||
|     @JsonProperty("title") val title: String? = null, | ||||
|     @JsonProperty("number") val number: Int? = null, | ||||
|     @JsonProperty("season") val season: Int? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetTitle( | ||||
|     @JsonProperty("romaji") val romaji: String? = null, | ||||
|     @JsonProperty("english") val english: String? = null | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetDetails( | ||||
|     @JsonProperty("episodes") val episodes: ArrayList<ConsumetEpisodes>? = arrayListOf(), | ||||
|     @JsonProperty("image") val image: String? = null, | ||||
|     @JsonProperty("cover") val cover: String? = null, | ||||
|     @JsonProperty("title") val title: ConsumetTitle? = null, | ||||
|     @JsonProperty("releaseDate") val releaseDate: Int? = null | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollEpisodes( | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
|     @JsonProperty("title") val title: String? = null, | ||||
|     @JsonProperty("episode_number") val episode_number: Int? = null, | ||||
|     @JsonProperty("season_number") val season_number: Int? = null, | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollDetails( | ||||
|     @JsonProperty("episodes") val episodes: HashMap<String, List<CrunchyrollEpisodes>>? = hashMapOf(), | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetResults( | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
|     @JsonProperty("title") val title: String? = null, | ||||
|     @JsonProperty("seasons") val seasons: Int? = null, | ||||
|     @JsonProperty("releaseDate") val releaseDate: String? = null, | ||||
|     @JsonProperty("type") val type: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ConsumetSearchResponse( | ||||
|     @JsonProperty("results") val results: ArrayList<ConsumetResults>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class KisskhSources( | ||||
|     @JsonProperty("Video") val video: String?, | ||||
|     @JsonProperty("ThirdParty") val thirdParty: String?, | ||||
|  | @ -3246,23 +3087,6 @@ data class SorastreamVideos( | |||
|     @JsonProperty("currentDefinition") val currentDefinition: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class SapphireSubtitles( | ||||
|     @JsonProperty("language") val language: String? = null, | ||||
|     @JsonProperty("url") val url: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class SapphireStreams( | ||||
|     @JsonProperty("format") val format: String? = null, | ||||
|     @JsonProperty("audio_lang") val audio_lang: String? = null, | ||||
|     @JsonProperty("hardsub_lang") val hardsub_lang: String? = null, | ||||
|     @JsonProperty("url") val url: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class SapphireSources( | ||||
|     @JsonProperty("streams") val streams: ArrayList<SapphireStreams>? = arrayListOf(), | ||||
|     @JsonProperty("subtitles") val subtitles: ArrayList<SapphireSubtitles>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class BiliBiliEpisodes( | ||||
|     @JsonProperty("id") val id: Int? = null, | ||||
|     @JsonProperty("sourceId") val sourceId: String? = null, | ||||
|  | @ -3325,74 +3149,6 @@ data class PutlockerResponses( | |||
|     @JsonProperty("backupLink") val backupLink: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeStreams( | ||||
|     @JsonProperty("format") val format: String? = null, | ||||
|     @JsonProperty("url") val url: String? = null, | ||||
|     @JsonProperty("audio_lang") val audio_lang: String? = null, | ||||
|     @JsonProperty("hardsub_lang") val hardsub_lang: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimePortData( | ||||
|     @JsonProperty("streams") val streams: ArrayList<AllanimeStreams>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeLink( | ||||
|     @JsonProperty("portData") val portData: AllanimePortData? = null, | ||||
|     @JsonProperty("resolutionStr") val resolutionStr: String? = null, | ||||
|     @JsonProperty("src") val src: String? = null, | ||||
|     @JsonProperty("link") val link: String? = null, | ||||
|     @JsonProperty("hls") val hls: Boolean? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeLinks( | ||||
|     @JsonProperty("links") val links: ArrayList<AllanimeLink>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeSourceUrls( | ||||
|     @JsonProperty("sourceUrl") val sourceUrl: String? = null, | ||||
|     @JsonProperty("sourceName") val sourceName: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeEpisode( | ||||
|     @JsonProperty("sourceUrls") val sourceUrls: ArrayList<AllanimeSourceUrls>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeAvailableEpisodesDetail( | ||||
|     @JsonProperty("sub") val sub: ArrayList<String>? = arrayListOf(), | ||||
|     @JsonProperty("dub") val dub: ArrayList<String>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeDetailShow( | ||||
|     @JsonProperty("availableEpisodesDetail") val availableEpisodesDetail: AllanimeAvailableEpisodesDetail? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeAiredStart( | ||||
|     @JsonProperty("year") val year: Int? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeEdges( | ||||
|     @JsonProperty("_id") val _id: String? = null, | ||||
|     @JsonProperty("name") val name: String? = null, | ||||
|     @JsonProperty("englishName") val englishName: String? = null, | ||||
|     @JsonProperty("thumbnail") val thumbnail: String? = null, | ||||
|     @JsonProperty("type") val type: String? = null, | ||||
|     @JsonProperty("airedStart") val airedStart: AllanimeAiredStart? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeShows( | ||||
|     @JsonProperty("edges") val edges: ArrayList<AllanimeEdges>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeData( | ||||
|     @JsonProperty("shows") val shows: AllanimeShows? = null, | ||||
|     @JsonProperty("show") val show: AllanimeDetailShow? = null, | ||||
|     @JsonProperty("episode") val episode: AllanimeEpisode? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AllanimeResponses( | ||||
|     @JsonProperty("data") val data: AllanimeData? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ShivamhwSources( | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
|     @JsonProperty("stream_link") val stream_link: String? = null, | ||||
|  | @ -3449,3 +3205,73 @@ data class VizcloudData( | |||
| data class VizcloudResponses( | ||||
|     @JsonProperty("data") val data: VizcloudData? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AnilistExternalLinks( | ||||
|     @JsonProperty("id") var id: Int? = null, | ||||
|     @JsonProperty("site") var site: String? = null, | ||||
|     @JsonProperty("url") var url: String? = null, | ||||
|     @JsonProperty("type") var type: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class AnilistMedia( | ||||
|     @JsonProperty("externalLinks") var externalLinks: ArrayList<AnilistExternalLinks> = arrayListOf() | ||||
| ) | ||||
| 
 | ||||
| data class AnilistData( | ||||
|     @JsonProperty("Media") var Media: AnilistMedia? = AnilistMedia() | ||||
| ) | ||||
| 
 | ||||
| data class AnilistResponses( | ||||
|     @JsonProperty("data") var data: AnilistData? = AnilistData() | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollToken( | ||||
|     @JsonProperty("access_token") val accessToken: String? = null, | ||||
|     @JsonProperty("expires_in") val expiresIn: Int? = null, | ||||
|     @JsonProperty("token_type") val tokenType: String? = null, | ||||
|     @JsonProperty("scope") val scope: String? = null, | ||||
|     @JsonProperty("country") val country: String? = null | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollVersions( | ||||
|     @JsonProperty("audio_locale") val audio_locale: String? = null, | ||||
|     @JsonProperty("guid") val guid: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollData( | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
|     @JsonProperty("title") val title: String? = null, | ||||
|     @JsonProperty("slug_title") val slug_title: String? = null, | ||||
|     @JsonProperty("season_number") val season_number: Int? = null, | ||||
|     @JsonProperty("episode_number") val episode_number: Int? = null, | ||||
|     @JsonProperty("versions") val versions: ArrayList<CrunchyrollVersions>? = null, | ||||
|     @JsonProperty("streams_link") val streams_link: String? = null, | ||||
|     @JsonProperty("adaptive_hls") val adaptive_hls: HashMap<String, HashMap<String, String>>? = hashMapOf(), | ||||
|     @JsonProperty("vo_adaptive_hls") val vo_adaptive_hls: HashMap<String, HashMap<String, String>>? = hashMapOf(), | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollResponses( | ||||
|     @JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollMeta( | ||||
|     @JsonProperty("subtitles") val subtitles: HashMap<String, HashMap<String, String>>? = hashMapOf(), | ||||
| ) | ||||
| 
 | ||||
| data class CrunchyrollSourcesResponses( | ||||
|     @JsonProperty("data") val data: ArrayList<CrunchyrollData>? = arrayListOf(), | ||||
|     @JsonProperty("meta") val meta: CrunchyrollMeta? = null, | ||||
| ) | ||||
| 
 | ||||
| data class MALSyncPages( | ||||
|     @JsonProperty("Zoro") val zoro: HashMap<String, HashMap<String, String>>? = hashMapOf(), | ||||
| ) | ||||
| 
 | ||||
| data class MALSyncResponses( | ||||
|     @JsonProperty("Pages") val pages: MALSyncPages? = null, | ||||
| ) | ||||
| 
 | ||||
| data class ZoroResponses( | ||||
|     @JsonProperty("html") val html: String? = null, | ||||
|     @JsonProperty("link") val link: String? = null, | ||||
| ) | ||||
|  | @ -6,7 +6,6 @@ import com.hexated.SoraExtractor.invokeAsk4Movies | |||
| import com.hexated.SoraExtractor.invokeBlackmovies | ||||
| import com.hexated.SoraExtractor.invokeBollyMaza | ||||
| import com.hexated.SoraExtractor.invokeCodexmovies | ||||
| import com.hexated.SoraExtractor.invokeCrunchyroll | ||||
| import com.hexated.SoraExtractor.invokeCryMovies | ||||
| import com.hexated.SoraExtractor.invokeDbgo | ||||
| import com.hexated.SoraExtractor.invokeFilmxy | ||||
|  | @ -17,7 +16,6 @@ import com.hexated.SoraExtractor.invokeMovieHab | |||
| import com.hexated.SoraExtractor.invokeNoverse | ||||
| import com.hexated.SoraExtractor.invokeSeries9 | ||||
| import com.hexated.SoraExtractor.invokeTwoEmbed | ||||
| import com.hexated.SoraExtractor.invokeUniqueStream | ||||
| import com.hexated.SoraExtractor.invokeVidSrc | ||||
| import com.hexated.SoraExtractor.invokeXmovies | ||||
| import com.lagradost.cloudstream3.* | ||||
|  | @ -41,8 +39,6 @@ import com.hexated.SoraExtractor.invokeMoviesbay | |||
| import com.hexated.SoraExtractor.invokeMoviezAdd | ||||
| import com.hexated.SoraExtractor.invokeNinetv | ||||
| import com.hexated.SoraExtractor.invokeNowTv | ||||
| import com.hexated.SoraExtractor.invokePapaonMovies1 | ||||
| import com.hexated.SoraExtractor.invokePapaonMovies2 | ||||
| import com.hexated.SoraExtractor.invokePutlocker | ||||
| import com.hexated.SoraExtractor.invokeRStream | ||||
| import com.hexated.SoraExtractor.invokeRinzrymovies | ||||
|  | @ -51,7 +47,6 @@ import com.hexated.SoraExtractor.invokeShinobiMovies | |||
| import com.hexated.SoraExtractor.invokeShivamhw | ||||
| import com.hexated.SoraExtractor.invokeSmashyStream | ||||
| import com.hexated.SoraExtractor.invokeSoraStream | ||||
| import com.hexated.SoraExtractor.invokeTgarMovies | ||||
| import com.hexated.SoraExtractor.invokeTvMovies | ||||
| import com.hexated.SoraExtractor.invokeUhdmovies | ||||
| import com.hexated.SoraExtractor.invokeVitoenMovies | ||||
|  | @ -81,17 +76,14 @@ open class SoraStream : TmdbProvider() { | |||
|         private const val tmdbAPI = "https://api.themoviedb.org/3" | ||||
|         const val tmdb2anilist = "https://tmdb2anilist.slidemovies.org" | ||||
|         const val gdbot = "https://gdtot.pro" | ||||
|         const val consumetAnilistAPI = "https://api.consumet.org/meta/anilist" | ||||
| 
 | ||||
|         private val apiKey = | ||||
|             base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL | ||||
|         private val apiKey = base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL | ||||
| 
 | ||||
|         /** ALL SOURCES */ | ||||
|         const val twoEmbedAPI = "https://www.2embed.to" | ||||
|         const val vidSrcAPI = "https://v2.vidsrc.me" | ||||
|         const val dbgoAPI = "https://dbgo.fun" | ||||
|         const val movieHabAPI = "https://moviehab.com" | ||||
|         const val databaseGdriveAPI = "https://databasegdriveplayer.co" | ||||
|         const val hdMovieBoxAPI = "https://hdmoviebox.net" | ||||
|         const val series9API = "https://series9.sh" | ||||
|         const val idlixAPI = "https://idlixian.com" | ||||
|  | @ -100,11 +92,11 @@ open class SoraStream : TmdbProvider() { | |||
|         const val filmxyAPI = "https://www.filmxy.vip" | ||||
|         const val kimcartoonAPI = "https://kimcartoon.li" | ||||
|         const val xMovieAPI = "https://xemovies.to" | ||||
|         const val consumetZoroAPI = "https://api.consumet.org/anime/zoro" | ||||
|         const val allanimeAPI = "https://api.allanime.to" | ||||
|         const val zoroAPI = "https://sanji.to" | ||||
|         const val crunchyrollAPI = "https://beta-api.crunchyroll.com" | ||||
|         const val kissKhAPI = "https://kisskh.co" | ||||
|         const val lingAPI = "https://ling-online.net" | ||||
|         const val uhdmoviesAPI = "https://uhdmovies.one" | ||||
|         const val uhdmoviesAPI = "https://uhdmovies.bio" | ||||
|         const val fwatayakoAPI = "https://5100.svetacdn.in" | ||||
|         const val gMoviesAPI = "https://gdrivemovies.xyz" | ||||
|         const val fdMoviesAPI = "https://freedrivemovie.lol" | ||||
|  | @ -600,7 +592,7 @@ open class SoraStream : TmdbProvider() { | |||
|                 invokeMovie123Net(res.title, res.season, res.episode, subtitleCallback, callback) | ||||
|             }, | ||||
|             { | ||||
|                 invokeSmashyStream(res.imdbId, res.season, res.episode, callback) | ||||
|                 invokeSmashyStream(res.imdbId, res.season, res.episode, subtitleCallback, callback) | ||||
|             }, | ||||
|             { | ||||
|                 invokeWatchsomuch( | ||||
|  |  | |||
|  | @ -167,7 +167,7 @@ class SoraStreamLite : SoraStream() { | |||
|                 invokeKimcartoon(res.title, res.season, res.episode, subtitleCallback, callback) | ||||
|             }, | ||||
|             { | ||||
|                 invokeSmashyStream(res.imdbId, res.season, res.episode, callback) | ||||
|                 invokeSmashyStream(res.imdbId, res.season, res.episode, subtitleCallback, callback) | ||||
|             }, | ||||
|             { | ||||
|                 invokeXmovies( | ||||
|  |  | |||
|  | @ -2,10 +2,9 @@ package com.hexated | |||
| 
 | ||||
| import android.util.Base64 | ||||
| import com.fasterxml.jackson.annotation.JsonProperty | ||||
| import com.hexated.SoraStream.Companion.allanimeAPI | ||||
| import com.hexated.SoraStream.Companion.base64DecodeAPI | ||||
| import com.hexated.SoraStream.Companion.baymoviesAPI | ||||
| import com.hexated.SoraStream.Companion.consumetCrunchyrollAPI | ||||
| import com.hexated.SoraStream.Companion.crunchyrollAPI | ||||
| import com.hexated.SoraStream.Companion.filmxyAPI | ||||
| import com.hexated.SoraStream.Companion.gdbot | ||||
| import com.hexated.SoraStream.Companion.putlockerAPI | ||||
|  | @ -17,10 +16,12 @@ import com.lagradost.cloudstream3.* | |||
| import com.lagradost.cloudstream3.APIHolder.getCaptchaToken | ||||
| import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall | ||||
| import com.lagradost.cloudstream3.utils.* | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.toJson | ||||
| import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson | ||||
| import com.lagradost.cloudstream3.utils.Coroutines.ioSafe | ||||
| import com.lagradost.nicehttp.NiceResponse | ||||
| import com.lagradost.nicehttp.RequestBodyTypes | ||||
| import com.lagradost.nicehttp.requestCreator | ||||
| import kotlinx.coroutines.delay | ||||
| import okhttp3.FormBody | ||||
| import okhttp3.Headers | ||||
|  | @ -28,10 +29,7 @@ import okhttp3.HttpUrl.Companion.toHttpUrl | |||
| import okhttp3.MediaType.Companion.toMediaTypeOrNull | ||||
| import okhttp3.RequestBody.Companion.toRequestBody | ||||
| import org.jsoup.nodes.Document | ||||
| import java.net.URI | ||||
| import java.net.URL | ||||
| import java.net.URLDecoder | ||||
| import java.net.URLEncoder | ||||
| import java.net.* | ||||
| import java.nio.charset.StandardCharsets | ||||
| import java.security.MessageDigest | ||||
| import java.security.SecureRandom | ||||
|  | @ -45,56 +43,13 @@ import kotlin.math.min | |||
| val soraAPI = base64DecodeAPI("cA==YXA=cy8=Y20=di8=LnQ=b2s=a2w=bG8=aS4=YXA=ZS0=aWw=b2I=LW0=Z2E=Ly8=czo=dHA=aHQ=") | ||||
| val bflixChipperKey = base64DecodeAPI("Yjc=ejM=TzA=YTk=WHE=WnU=bXU=RFo=") | ||||
| val bflixKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" | ||||
| val kaguyaBaseUrl = "https://kaguya.app/" | ||||
| const val kaguyaBaseUrl = "https://kaguya.app/" | ||||
| val soraHeaders = mapOf( | ||||
|     "lang" to "en", | ||||
|     "versioncode" to "33", | ||||
|     "clienttype" to "android_Official", | ||||
|     "deviceid" to getDeviceId(), | ||||
| ) | ||||
| val allanimeSearchQuery = """ | ||||
|         query( | ||||
|                 ${'$'}search: SearchInput | ||||
|                 ${'$'}limit: Int | ||||
|                 ${'$'}page: Int | ||||
|                 ${'$'}translationType: VaildTranslationTypeEnumType | ||||
|                 ${'$'}countryOrigin: VaildCountryOriginEnumType | ||||
|             ) { | ||||
|             shows( | ||||
|                 search: ${'$'}search | ||||
|                 limit: ${'$'}limit | ||||
|                 page: ${'$'}page | ||||
|                 translationType: ${'$'}translationType | ||||
|                 countryOrigin: ${'$'}countryOrigin | ||||
|             ) { | ||||
|                 pageInfo { | ||||
|                     total | ||||
|                 } | ||||
|                 edges { | ||||
|                     _id | ||||
|                     name | ||||
|                     thumbnail | ||||
|                     englishName | ||||
|                     nativeName | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     """.trimIndent().trim() | ||||
| val allanimeServerQuery = """ | ||||
|         query( | ||||
|                 ${'$'}showId: String!, | ||||
|                 ${'$'}translationType: VaildTranslationTypeEnumType!, | ||||
|                 ${'$'}episodeString: String! | ||||
|             ) { | ||||
|             episode( | ||||
|                 showId: ${'$'}showId | ||||
|                 translationType: ${'$'}translationType | ||||
|                 episodeString: ${'$'}episodeString | ||||
|             ) { | ||||
|                 sourceUrls | ||||
|             } | ||||
|         } | ||||
|     """.trimIndent().trim() | ||||
| val encodedIndex = arrayOf( | ||||
|     "GamMovies", | ||||
|     "JSMovies", | ||||
|  | @ -574,6 +529,45 @@ suspend fun invokeSmashyNflim( | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| suspend fun invokeSmashyRip( | ||||
|     name: String, | ||||
|     url: String, | ||||
|     subtitleCallback: (SubtitleFile) -> Unit, | ||||
|     callback: (ExtractorLink) -> Unit, | ||||
| ) { | ||||
|     val script = app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return | ||||
| 
 | ||||
|     val source = Regex("file:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) | ||||
|     val subtitle = Regex("subtitle:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) | ||||
| 
 | ||||
|     source?.split(",")?.map { links -> | ||||
|         val quality = Regex("\\[(\\d+)]").find(links)?.groupValues?.getOrNull(1)?.trim() | ||||
|         val link = links.removePrefix("[$quality]").substringAfter("dev/").trim() | ||||
|         callback.invoke( | ||||
|             ExtractorLink( | ||||
|                 "Smashy [$name]", | ||||
|                 "Smashy [$name]", | ||||
|                 link, | ||||
|                 "", | ||||
|                 quality?.toIntOrNull() ?: return@map, | ||||
|                 isM3u8 = true, | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     subtitle?.replace("<br>", "")?.split(",")?.map { sub -> | ||||
|         val lang = Regex("\\[(.*?)]").find(sub)?.groupValues?.getOrNull(1)?.trim() | ||||
|         val link = sub.removePrefix("[$lang]") | ||||
|         subtitleCallback.invoke( | ||||
|             SubtitleFile( | ||||
|                 lang.orEmpty().ifEmpty { return@map }, | ||||
|                 link | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| suspend fun getSoraIdAndType(title: String?, year: Int?, season: Int?): Pair<String, String>? { | ||||
|     val doc = | ||||
|         app.get("${base64DecodeAPI("b20=LmM=b2s=a2w=bG8=Ly8=czo=dHA=aHQ=")}/search?keyword=$title").document | ||||
|  | @ -825,7 +819,7 @@ suspend fun getTvMoviesServer(url: String, season: Int?, episode: Int?): Pair<St | |||
|     } | ||||
| } | ||||
| 
 | ||||
| suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies? { | ||||
| suspend fun getFilmxyCookies(imdbId: String? = null, season: Int? = null): FilmxyCookies { | ||||
| 
 | ||||
|     val url = if (season == null) { | ||||
|         "${filmxyAPI}/movie/$imdbId" | ||||
|  | @ -905,47 +899,68 @@ suspend fun searchWatchOnline( | |||
|     ) | ||||
| } | ||||
| 
 | ||||
| suspend fun searchCrunchyrollAnimeId(title: String): String? { | ||||
|     val res = app.get("${consumetCrunchyrollAPI}/search/$title", timeout = 600L) | ||||
|         .parsedSafe<ConsumetSearchResponse>()?.results | ||||
|     return (if (res?.size == 1) { | ||||
|         res.firstOrNull() | ||||
|     } else { | ||||
|         res?.find { | ||||
|             (it.title?.contains( | ||||
|                 title, | ||||
|                 true | ||||
|             ) == true || it.title.createSlug() | ||||
|                 ?.contains("${title.createSlug()}", true) == true) && it.type.equals("series") | ||||
| //modified code from https://github.com/jmir1/aniyomi-extensions/blob/master/src/all/kamyroll/src/eu/kanade/tachiyomi/animeextension/all/kamyroll/AccessTokenInterceptor.kt | ||||
| fun getCrunchyrollToken(): Map<String, String> { | ||||
|     val client = app.baseClient.newBuilder() | ||||
|         .proxy(Proxy(Proxy.Type.SOCKS, InetSocketAddress("cr-unblocker.us.to", 1080))) | ||||
|         .build() | ||||
| 
 | ||||
|     Authenticator.setDefault(object : Authenticator() { | ||||
|         override fun getPasswordAuthentication(): PasswordAuthentication { | ||||
|             return PasswordAuthentication("crunblocker", "crunblocker".toCharArray()) | ||||
|         } | ||||
|     })?.id | ||||
| } | ||||
|     }) | ||||
| 
 | ||||
| fun CrunchyrollDetails.findCrunchyrollId( | ||||
|     season: Int?, | ||||
|     episode: Int?, | ||||
|     epsTitle: String? | ||||
| ): List<Pair<CrunchyrollEpisodes?, String?>?> { | ||||
|     val sub = this.episodes?.filterKeys { it.contains("subbed") } | ||||
|         .matchingEpisode(epsTitle, season, episode) to "Raw" | ||||
|     val dub = this.episodes?.filterKeys { it.contains("English Dub") } | ||||
|         .matchingEpisode(epsTitle, season, episode) to "English Dub" | ||||
|     return listOf(sub, dub) | ||||
| } | ||||
| 
 | ||||
| fun Map<String, List<CrunchyrollEpisodes>>?.matchingEpisode( | ||||
|     epsTitle: String?, | ||||
|     season: Int?, | ||||
|     episode: Int? | ||||
| ): CrunchyrollEpisodes? { | ||||
|     return this?.mapNotNull { eps -> | ||||
|         eps.value.find { | ||||
|             (it.episode_number == episode && it.season_number == season) || it.title.equals( | ||||
|                 epsTitle, | ||||
|                 true | ||||
|     val request = requestCreator( | ||||
|         method = "POST", | ||||
|         url = "$crunchyrollAPI/auth/v1/token", | ||||
|         headers = mapOf( | ||||
|             "User-Agent" to "Crunchyroll/3.26.1 Android/11 okhttp/4.9.2", | ||||
|             "Content-Type" to "application/x-www-form-urlencoded", | ||||
|             "Authorization" to "Basic ${BuildConfig.CRUNCHYROLL_BASIC_TOKEN}" | ||||
|         ), | ||||
|         data = mapOf( | ||||
|             "refresh_token" to BuildConfig.CRUNCHYROLL_REFRESH_TOKEN, | ||||
|             "grant_type" to "refresh_token", | ||||
|             "scope" to "offline_access" | ||||
|         ) | ||||
|         } ?: eps.value.find { it.episode_number == episode } | ||||
|     }?.firstOrNull() | ||||
|     ) | ||||
| 
 | ||||
|     val response = tryParseJson<CrunchyrollToken>(client.newCall(request).execute().body.string()) | ||||
|     return mapOf("Authorization" to "${response?.tokenType} ${response?.accessToken}") | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| suspend fun getCrunchyrollId(aniId: String?): String? { | ||||
|     val query = """ | ||||
|         query media(${'$'}id: Int, ${'$'}type: MediaType, ${'$'}isAdult: Boolean) { | ||||
|           Media(id: ${'$'}id, type: ${'$'}type, isAdult: ${'$'}isAdult) { | ||||
|             id | ||||
|             externalLinks { | ||||
|               id | ||||
|               site | ||||
|               url | ||||
|               type | ||||
|             } | ||||
|           } | ||||
|         } | ||||
|     """.trimIndent().trim() | ||||
| 
 | ||||
|     val variables = mapOf( | ||||
|         "id" to aniId, | ||||
|         "isAdult" to false, | ||||
|         "type" to "ANIME", | ||||
|     ) | ||||
| 
 | ||||
|     val data = mapOf( | ||||
|         "query" to query, | ||||
|         "variables" to variables | ||||
|     ).toJson().toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull()) | ||||
| 
 | ||||
|     return app.post("https://graphql.anilist.co", requestBody = data) | ||||
|         .parsedSafe<AnilistResponses>()?.data?.Media?.externalLinks?.find { it.site == "VRV" }?.url?.let { | ||||
|             Regex("series/(\\w+)/?").find(it)?.groupValues?.get(1) | ||||
|         } | ||||
| } | ||||
| 
 | ||||
| suspend fun extractPutlockerSources(url: String?): NiceResponse? { | ||||
|  | @ -1120,10 +1135,6 @@ fun String.decryptGomoviesJson(key: String = "123"): String { | |||
|     return sb.toString() | ||||
| } | ||||
| 
 | ||||
| fun allanimeQueries(variables: String, query: String) : String { | ||||
|     return "${allanimeAPI}/allanimeapi?variables=$variables&query=$query" | ||||
| } | ||||
| 
 | ||||
| fun Headers.getGomoviesCookies(cookieKey: String = "set-cookie"): Map<String, String> { | ||||
|     val cookieList = | ||||
|         this.filter { it.first.equals(cookieKey, ignoreCase = true) }.mapNotNull { | ||||
|  | @ -1292,7 +1303,7 @@ private fun decryptVrf(input: String, key: String): String { | |||
|     val t = if (input.replace("""[\t\n\f\r]""".toRegex(), "").length % 4 == 0) { | ||||
|         input.replace("""==?$""".toRegex(), "") | ||||
|     } else input | ||||
|     if (t.length % 4 == 1 || t.contains("""[^+/0-9A-Za-z]""".toRegex())) throw Exception("bad input") | ||||
|     if (t.length % 4 == 1 || t.contains("""[^+/\dA-Za-z]""".toRegex())) throw Exception("bad input") | ||||
|     var i: Int | ||||
|     var r = "" | ||||
|     var e = 0 | ||||
|  | @ -1359,10 +1370,6 @@ fun getBaseUrl(url: String): String { | |||
|     } | ||||
| } | ||||
| 
 | ||||
| fun String.decodeBase64(): String { | ||||
|     return Base64.decode(this, Base64.DEFAULT).toString(Charsets.UTF_8) | ||||
| } | ||||
| 
 | ||||
| fun decode(input: String): String = URLDecoder.decode(input, "utf-8") | ||||
| 
 | ||||
| fun encode(input: String): String = URLEncoder.encode(input, "utf-8").replace("+", "%20") | ||||
|  | @ -1599,7 +1606,9 @@ object CryptoAES { | |||
| object RabbitStream { | ||||
| 
 | ||||
|     suspend fun MainAPI.extractRabbitStream( | ||||
|         server: String, | ||||
|         url: String, | ||||
|         ref: String, | ||||
|         subtitleCallback: (SubtitleFile) -> Unit, | ||||
|         callback: (ExtractorLink) -> Unit, | ||||
|         useSidAuthentication: Boolean, | ||||
|  | @ -1681,8 +1690,8 @@ object RabbitStream { | |||
|         list.forEach { subList -> | ||||
|             subList.first?.forEach { source -> | ||||
|                 source?.toExtractorLink( | ||||
|                     "Vidcloud", | ||||
|                     "$twoEmbedAPI/", | ||||
|                     server, | ||||
|                     ref, | ||||
|                     extractorData, | ||||
|                 ) | ||||
|                     ?.forEach { | ||||
|  | @ -1792,11 +1801,15 @@ object RabbitStream { | |||
|         return code.reversed() | ||||
|     } | ||||
| 
 | ||||
|     suspend fun getKey(): String? { | ||||
|     suspend fun getKey(): String { | ||||
|         return app.get("https://raw.githubusercontent.com/enimax-anime/key/e4/key.txt") | ||||
|             .text | ||||
|     } | ||||
| 
 | ||||
|     suspend fun getZoroKey(): String { | ||||
|         return app.get("https://raw.githubusercontent.com/enimax-anime/key/e6/key.txt").text | ||||
|     } | ||||
| 
 | ||||
|     private inline fun <reified T> decryptMapped(input: String, key: String): T? { | ||||
|         return tryParseJson(decrypt(input, key)) | ||||
|     } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue