mirror of
				https://github.com/hexated/cloudstream-extensions-hexated.git
				synced 2024-08-15 00:03:22 +00:00 
			
		
		
		
	sora: added netflix
This commit is contained in:
		
							parent
							
								
									4077d1275d
								
							
						
					
					
						commit
						36e77332c5
					
				
					 12 changed files with 167 additions and 28 deletions
				
			
		|  | @ -1,5 +1,5 @@ | |||
| // use an integer for version numbers | ||||
| version = 17 | ||||
| version = 18 | ||||
| 
 | ||||
| 
 | ||||
| cloudstream { | ||||
|  |  | |||
|  | @ -59,7 +59,7 @@ class NontonAnimeIDProvider : MainAPI() { | |||
| 
 | ||||
|         document.select("aside#sidebar_right > div.side").forEach { block -> | ||||
|             val header = block.selectFirst("h3")!!.ownText().trim() | ||||
|             val animes = block.select("ul li.fullwdth").mapNotNull { | ||||
|             val animes = block.select("div.bor").mapNotNull { | ||||
|                 it.toSearchResultPopular() | ||||
|             } | ||||
|             if (animes.isNotEmpty()) homePageList.add(HomePageList(header, animes)) | ||||
|  | @ -71,7 +71,7 @@ class NontonAnimeIDProvider : MainAPI() { | |||
|     private fun Element.toSearchResult(): AnimeSearchResponse? { | ||||
|         val href = fixUrl(this.selectFirst("a")!!.attr("href")) | ||||
|         val title = this.selectFirst("h3.title")?.text() ?: return null | ||||
|         val posterUrl = fixUrl(this.select("img").attr("data-src")) | ||||
|         val posterUrl = fixUrl(this.select("img").attr("src")) | ||||
| 
 | ||||
|         return newAnimeSearchResponse(title, href, TvType.Anime) { | ||||
|             this.posterUrl = posterUrl | ||||
|  | @ -83,7 +83,7 @@ class NontonAnimeIDProvider : MainAPI() { | |||
|     private fun Element.toSearchResultPopular(): AnimeSearchResponse? { | ||||
|         val href = fixUrl(this.selectFirst("a")!!.attr("href")) | ||||
|         val title = this.selectFirst("h4")?.text()?.trim() ?: return null | ||||
|         val posterUrl = fixUrl(this.select("img").attr("data-src")) | ||||
|         val posterUrl = fixUrl(this.select("img").attr("src")) | ||||
| 
 | ||||
|         return newAnimeSearchResponse(title, href, TvType.Anime) { | ||||
|             this.posterUrl = posterUrl | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // use an integer for version numbers | ||||
| version = 15 | ||||
| version = 16 | ||||
| 
 | ||||
| 
 | ||||
| cloudstream { | ||||
|  |  | |||
|  | @ -4,9 +4,13 @@ import com.lagradost.cloudstream3.* | |||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addAniListId | ||||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addMalId | ||||
| import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer | ||||
| import com.lagradost.cloudstream3.network.CloudflareKiller | ||||
| import com.lagradost.cloudstream3.utils.ExtractorLink | ||||
| import com.lagradost.cloudstream3.utils.Qualities | ||||
| import com.lagradost.cloudstream3.utils.loadExtractor | ||||
| import okhttp3.Interceptor | ||||
| import okhttp3.Response | ||||
| import org.jsoup.Jsoup | ||||
| import org.jsoup.nodes.Element | ||||
| 
 | ||||
| class Samehadaku : MainAPI() { | ||||
|  | @ -15,13 +19,26 @@ class Samehadaku : MainAPI() { | |||
|     override val hasMainPage = true | ||||
|     override var lang = "id" | ||||
|     override val hasDownloadSupport = true | ||||
| 
 | ||||
|     private val cloudflareKiller by lazy { CloudflareKiller() } | ||||
|     private val interceptor by lazy { CloudflareInterceptor(cloudflareKiller) } | ||||
|     override val supportedTypes = setOf( | ||||
|         TvType.Anime, | ||||
|         TvType.AnimeMovie, | ||||
|         TvType.OVA | ||||
|     ) | ||||
| 
 | ||||
|     class CloudflareInterceptor(private val cloudflareKiller: CloudflareKiller): Interceptor { | ||||
|         override fun intercept(chain: Interceptor.Chain): Response { | ||||
|             val request = chain.request() | ||||
|             val response = chain.proceed(request) | ||||
|             val doc = Jsoup.parse(response.peekBody(1024 * 1024).string()) | ||||
|             if (doc.select("title").text() == "Just a moment...") { | ||||
|                 return cloudflareKiller.intercept(chain) | ||||
|             } | ||||
|             return response | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     companion object { | ||||
|         const val acefile = "https://acefile.co" | ||||
| 
 | ||||
|  | @ -52,7 +69,7 @@ class Samehadaku : MainAPI() { | |||
|         val items = mutableListOf<HomePageList>() | ||||
| 
 | ||||
|         if (request.name != "Episode Terbaru" && page <= 1) { | ||||
|             val doc = app.get(request.data).document | ||||
|             val doc = app.get(request.data, interceptor = interceptor).document | ||||
|             doc.select("div.widget_senction:not(:contains(Baca Komik))").forEach { block -> | ||||
|                 val header = block.selectFirst("div.widget-title h3")?.ownText() ?: return@forEach | ||||
|                 val home = block.select("div.animepost").mapNotNull { | ||||
|  | @ -64,7 +81,7 @@ class Samehadaku : MainAPI() { | |||
| 
 | ||||
|         if (request.name == "Episode Terbaru") { | ||||
|             val home = | ||||
|                 app.get(request.data + page).document.selectFirst("div.post-show")?.select("ul li") | ||||
|                 app.get(request.data + page, interceptor = interceptor).document.selectFirst("div.post-show")?.select("ul li") | ||||
|                     ?.mapNotNull { | ||||
|                         it.toSearchResult() | ||||
|                     } ?: throw ErrorLoadingException("No Media Found") | ||||
|  | @ -84,12 +101,13 @@ class Samehadaku : MainAPI() { | |||
|         return newAnimeSearchResponse(title, href ?: return null, TvType.Anime) { | ||||
|             this.posterUrl = posterUrl | ||||
|             addSub(epNum) | ||||
|             posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap() | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
|     override suspend fun search(query: String): List<SearchResponse> { | ||||
|         val document = app.get("$mainUrl/?s=$query").document | ||||
|         val document = app.get("$mainUrl/?s=$query", interceptor = interceptor).document | ||||
|         return document.select("main#main div.animepost").mapNotNull { | ||||
|             it.toSearchResult() | ||||
|         } | ||||
|  | @ -99,10 +117,10 @@ class Samehadaku : MainAPI() { | |||
|         val fixUrl = if (url.contains("/anime/")) { | ||||
|             url | ||||
|         } else { | ||||
|             app.get(url).document.selectFirst("div.nvs.nvsc a")?.attr("href") | ||||
|             app.get(url, interceptor = interceptor).document.selectFirst("div.nvs.nvsc a")?.attr("href") | ||||
|         } | ||||
| 
 | ||||
|         val document = app.get(fixUrl ?: return null).document | ||||
|         val document = app.get(fixUrl ?: return null, interceptor = interceptor).document | ||||
|         val title = document.selectFirst("h1.entry-title")?.text()?.removeBloat() ?: return null | ||||
|         val poster = document.selectFirst("div.thumb > img")?.attr("src") | ||||
|         val tags = document.select("div.genre-info > a").map { it.text() } | ||||
|  | @ -147,6 +165,7 @@ class Samehadaku : MainAPI() { | |||
|             this.recommendations = recommendations | ||||
|             addMalId(tracker?.malId) | ||||
|             addAniListId(tracker?.aniId?.toIntOrNull()) | ||||
|             posterHeaders = cloudflareKiller.getCookieHeaders(mainUrl).toMap() | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
|  | @ -158,7 +177,7 @@ class Samehadaku : MainAPI() { | |||
|         callback: (ExtractorLink) -> Unit | ||||
|     ): Boolean { | ||||
| 
 | ||||
|         val document = app.get(data).document | ||||
|         val document = app.get(data, interceptor = interceptor).document | ||||
| 
 | ||||
|         argamap( | ||||
|             { | ||||
|  | @ -176,7 +195,8 @@ class Samehadaku : MainAPI() { | |||
|                             "type" to dataType | ||||
|                         ), | ||||
|                         referer = data, | ||||
|                         headers = mapOf("X-Requested-With" to "XMLHttpRequest") | ||||
|                         headers = mapOf("X-Requested-With" to "XMLHttpRequest"), | ||||
|                         interceptor = interceptor | ||||
|                     ).document.select("iframe").attr("src") | ||||
| 
 | ||||
|                     loadFixedExtractor(fixedIframe(iframe), it.text(), "$mainUrl/", subtitleCallback, callback) | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| import org.jetbrains.kotlin.konan.properties.Properties | ||||
| 
 | ||||
| // use an integer for version numbers | ||||
| version = 168 | ||||
| version = 169 | ||||
| 
 | ||||
| android { | ||||
|     defaultConfig { | ||||
|  |  | |||
|  | @ -13,6 +13,7 @@ import com.lagradost.cloudstream3.base64Decode | |||
| import com.lagradost.cloudstream3.extractors.Pixeldrain | ||||
| import com.lagradost.cloudstream3.utils.* | ||||
| import java.math.BigInteger | ||||
| import java.net.URI | ||||
| import java.security.MessageDigest | ||||
| 
 | ||||
| open class Playm4u : ExtractorApi() { | ||||
|  | @ -150,7 +151,7 @@ open class VCloud : ExtractorApi() { | |||
|         val changedLink = doc.selectFirst("script:containsData(url =)")?.data()?.let { | ||||
|             """url\s*=\s*['"](.*)['"];""".toRegex().find(it)?.groupValues?.get(1) | ||||
|                 ?.substringAfter("r=") | ||||
|         } | ||||
|         } ?: doc.selectFirst("div.div.vd.d-none a")?.attr("href") | ||||
|         val header = doc.selectFirst("div.card-header")?.text() | ||||
|         app.get( | ||||
|             base64Decode(changedLink ?: return), cookies = res.cookies, headers = mapOf( | ||||
|  | @ -158,7 +159,8 @@ open class VCloud : ExtractorApi() { | |||
|             ) | ||||
|         ).document.select("p.text-success ~ a").apmap { | ||||
|             val link = it.attr("href") | ||||
|             if (it.text().contains(Regex("Server : 1|2"))) { | ||||
|             val uri = URI(link) | ||||
|             if (uri.path.contains("workers.dev")) { | ||||
|                 callback.invoke( | ||||
|                     ExtractorLink( | ||||
|                         this.name, | ||||
|  | @ -184,6 +186,16 @@ open class VCloud : ExtractorApi() { | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| class HubcloudLol : VCloud() { | ||||
|     override val name = "Hubcloud" | ||||
|     override val mainUrl = "https://hubcloud.lol" | ||||
| } | ||||
| 
 | ||||
| class Hubcloud : VCloud() { | ||||
|     override val name = "Hubcloud" | ||||
|     override val mainUrl = "https://hubcloud.in" | ||||
| } | ||||
| 
 | ||||
| class Pixeldra : Pixeldrain() { | ||||
|     override val mainUrl = "https://pixeldra.in" | ||||
| } | ||||
|  |  | |||
|  | @ -5,12 +5,7 @@ import com.lagradost.cloudstream3.utils.* | |||
| import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson | ||||
| import com.lagradost.nicehttp.Requests | ||||
| import com.lagradost.nicehttp.Session | ||||
| import com.lagradost.cloudstream3.extractors.Filesim | ||||
| import com.lagradost.cloudstream3.extractors.GMPlayer | ||||
| import com.lagradost.cloudstream3.extractors.StreamSB | ||||
| import com.lagradost.cloudstream3.extractors.Voe | ||||
| import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler | ||||
| import com.lagradost.cloudstream3.extractors.helper.GogoHelper | ||||
| import com.lagradost.cloudstream3.network.CloudflareKiller | ||||
| import com.lagradost.nicehttp.RequestBodyTypes | ||||
| import kotlinx.coroutines.delay | ||||
|  | @ -319,7 +314,6 @@ object SoraExtractor : SoraStream() { | |||
|         callback: (ExtractorLink) -> Unit, | ||||
|         fixIframe: Boolean = false, | ||||
|         encrypt: Boolean = false, | ||||
|         key: String? = null, | ||||
|     ) { | ||||
|         fun String.fixBloat() : String { | ||||
|             return this.replace("\"", "").replace("\\", "") | ||||
|  | @ -572,8 +566,8 @@ object SoraExtractor : SoraStream() { | |||
|                         "${link.name} ${it.second}", | ||||
|                         link.url, | ||||
|                         link.referer, | ||||
|                         when { | ||||
|                             link.type == ExtractorLinkType.M3U8 -> link.quality | ||||
|                         when (link.type) { | ||||
|                             ExtractorLinkType.M3U8 -> link.quality | ||||
|                             else -> getQualityFromName(it.first) | ||||
|                         }, | ||||
|                         link.type, | ||||
|  | @ -900,8 +894,8 @@ object SoraExtractor : SoraStream() { | |||
|                         "${link.name} [${it.second}]", | ||||
|                         link.url, | ||||
|                         link.referer, | ||||
|                         when { | ||||
|                             link.type == ExtractorLinkType.M3U8 -> link.quality | ||||
|                         when (link.type) { | ||||
|                             ExtractorLinkType.M3U8 -> link.quality | ||||
|                             else -> it.third | ||||
|                         }, | ||||
|                         link.type, | ||||
|  | @ -2756,6 +2750,52 @@ object SoraExtractor : SoraStream() { | |||
|         ) | ||||
|     } | ||||
| 
 | ||||
|     suspend fun invokeNetflix( | ||||
|         imdbId: String? = null, | ||||
|         season: Int? = null, | ||||
|         episode: Int? = null, | ||||
|         callback: (ExtractorLink) -> Unit, | ||||
|     ) { | ||||
|         val headers = mapOf("X-Requested-With" to "XMLHttpRequest", "Cookie" to "hd=on") | ||||
|         val netflixId = imdbToNetflixId(imdbId, season) | ||||
|         val (title, id) = app.get( | ||||
|             "$netflixAPI/post.php?id=${netflixId ?: return}&t=${APIHolder.unixTime}", | ||||
|             headers = headers | ||||
|         ).parsedSafe<NetflixResponse>().let { media -> | ||||
|             if (season == null) { | ||||
|                 media?.title to netflixId | ||||
|             } else { | ||||
|                 val seasonId = media?.season?.find { it.s == "$season" }?.id | ||||
|                 val episodeId = | ||||
|                     app.get( | ||||
|                         "$netflixAPI/episodes.php?s=${seasonId}&series=$netflixId&t=${APIHolder.unixTime}", | ||||
|                         headers = headers | ||||
|                     ) | ||||
|                         .parsedSafe<NetflixResponse>()?.episodes?.find { it.ep == "E$episode" }?.id | ||||
|                 media?.title to episodeId | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         app.get( | ||||
|             "$netflixAPI/playlist.php?id=${id ?: return}&t=${title ?: return}&tm=${APIHolder.unixTime}", | ||||
|             headers = headers | ||||
|         ).text.let { | ||||
|             tryParseJson<ArrayList<NetflixResponse>>(it) | ||||
|         }?.firstOrNull()?.sources?.map { | ||||
|             callback.invoke( | ||||
|                 ExtractorLink( | ||||
|                     "Netflix", | ||||
|                     "Netflix", | ||||
|                     fixUrl(it.file ?: return@map, netflixAPI), | ||||
|                     "$netflixAPI/", | ||||
|                     getQualityFromName(it.file.substringAfter("q=")), | ||||
|                     INFER_TYPE, | ||||
|                     headers = mapOf("Cookie" to "hd=on") | ||||
|                 ) | ||||
|             ) | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -428,3 +428,36 @@ data class EMovieTraks( | |||
| data class FourCartoonSources( | ||||
|     @JsonProperty("videoSource") val videoSource: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class WatchhubStream( | ||||
|     @JsonProperty("name") val name: String? = null, | ||||
|     @JsonProperty("externalUrl") val externalUrl: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class WatchhubResponse( | ||||
|     @JsonProperty("streams") val streams: ArrayList<WatchhubStream>? = arrayListOf(), | ||||
| ) | ||||
| 
 | ||||
| data class NetflixSources( | ||||
|     @JsonProperty("file") val file: String? = null, | ||||
|     @JsonProperty("label") val label: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class NetflixEpisodes( | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
|     @JsonProperty("t") val t: String? = null, | ||||
|     @JsonProperty("s") val s: String? = null, | ||||
|     @JsonProperty("ep") val ep: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class NetflixSeason( | ||||
|     @JsonProperty("s") val s: String? = null, | ||||
|     @JsonProperty("id") val id: String? = null, | ||||
| ) | ||||
| 
 | ||||
| data class NetflixResponse( | ||||
|     @JsonProperty("title") val title: String? = null, | ||||
|     @JsonProperty("season") val season: ArrayList<NetflixSeason>? = arrayListOf(), | ||||
|     @JsonProperty("episodes") val episodes: ArrayList<NetflixEpisodes>? = arrayListOf(), | ||||
|     @JsonProperty("sources") val sources: ArrayList<NetflixSources>? = arrayListOf(), | ||||
| ) | ||||
|  |  | |||
|  | @ -41,6 +41,7 @@ import com.hexated.SoraExtractor.invokeFourCartoon | |||
| import com.hexated.SoraExtractor.invokeJump1 | ||||
| import com.hexated.SoraExtractor.invokeMoment | ||||
| import com.hexated.SoraExtractor.invokeMultimovies | ||||
| import com.hexated.SoraExtractor.invokeNetflix | ||||
| import com.hexated.SoraExtractor.invokeNetmovies | ||||
| import com.hexated.SoraExtractor.invokePobmovies | ||||
| import com.hexated.SoraExtractor.invokePrimewire | ||||
|  | @ -79,6 +80,7 @@ open class SoraStream : TmdbProvider() { | |||
|         const val malsyncAPI = "https://api.malsync.moe" | ||||
|         const val consumetHelper = "https://api.consumet.org/anime/9anime/helper" | ||||
|         const val jikanAPI = "https://api.jikan.moe/v4" | ||||
|         const val watchhubApi = "https://watchhub.strem.io" | ||||
| 
 | ||||
|         private val apiKey = | ||||
|             base64DecodeAPI("ZTM=NTg=MjM=MjM=ODc=MzI=OGQ=MmE=Nzk=Nzk=ZjI=NTA=NDY=NDA=MzA=YjA=") // PLEASE DON'T STEAL | ||||
|  | @ -131,6 +133,7 @@ open class SoraStream : TmdbProvider() { | |||
|         const val susflixAPI = "https://susflix.tv" | ||||
|         const val jump1API = "https://ca.jump1.net" | ||||
|         const val vegaMoviesAPI = "https://vegamovies.im" | ||||
|         const val netflixAPI = "https://m.netflixmirror.com" | ||||
| 
 | ||||
|         // INDEX SITE | ||||
|         const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev" | ||||
|  | @ -738,6 +741,14 @@ open class SoraStream : TmdbProvider() { | |||
|                     callback | ||||
|                 ) | ||||
|             }, | ||||
|             { | ||||
|                 if (!res.isAnime) invokeNetflix( | ||||
|                     res.imdbId, | ||||
|                     res.season, | ||||
|                     res.episode, | ||||
|                     callback | ||||
|                 ) | ||||
|             } | ||||
|         ) | ||||
| 
 | ||||
|         return true | ||||
|  |  | |||
|  | @ -28,6 +28,7 @@ import com.hexated.SoraExtractor.invokeFourCartoon | |||
| import com.hexated.SoraExtractor.invokeJump1 | ||||
| import com.hexated.SoraExtractor.invokeMoment | ||||
| import com.hexated.SoraExtractor.invokeMultimovies | ||||
| import com.hexated.SoraExtractor.invokeNetflix | ||||
| import com.hexated.SoraExtractor.invokeNetmovies | ||||
| import com.hexated.SoraExtractor.invokePrimewire | ||||
| import com.hexated.SoraExtractor.invokeVidSrc | ||||
|  | @ -327,6 +328,14 @@ class SoraStreamLite : SoraStream() { | |||
|                     callback | ||||
|                 ) | ||||
|             }, | ||||
|             { | ||||
|                 if (!res.isAnime) invokeNetflix( | ||||
|                     res.imdbId, | ||||
|                     res.season, | ||||
|                     res.episode, | ||||
|                     callback | ||||
|                 ) | ||||
|             } | ||||
|         ) | ||||
| 
 | ||||
|         return true | ||||
|  |  | |||
|  | @ -20,5 +20,7 @@ class SoraStreamPlugin: Plugin() { | |||
|         registerExtractorAPI(Playm4u()) | ||||
|         registerExtractorAPI(VCloud()) | ||||
|         registerExtractorAPI(Pixeldra()) | ||||
|         registerExtractorAPI(Hubcloud()) | ||||
|         registerExtractorAPI(HubcloudLol()) | ||||
|     } | ||||
| } | ||||
|  | @ -13,6 +13,7 @@ import com.hexated.SoraStream.Companion.malsyncAPI | |||
| import com.hexated.SoraStream.Companion.smashyStreamAPI | ||||
| import com.hexated.SoraStream.Companion.tvMoviesAPI | ||||
| import com.hexated.SoraStream.Companion.watchOnlineAPI | ||||
| import com.hexated.SoraStream.Companion.watchhubApi | ||||
| import com.lagradost.cloudstream3.* | ||||
| import com.lagradost.cloudstream3.APIHolder.getCaptchaToken | ||||
| import com.lagradost.cloudstream3.APIHolder.unixTimeMS | ||||
|  | @ -1139,6 +1140,17 @@ suspend fun tmdbToAnimeId(title: String?, year: Int?, season: String?, type: TvT | |||
| 
 | ||||
| } | ||||
| 
 | ||||
| suspend fun imdbToNetflixId(imdbId: String?, season: Int?): String? { | ||||
|     val url = if (season == null) { | ||||
|         "$watchhubApi/stream/movie/$imdbId.json" | ||||
|     } else { | ||||
|         "$watchhubApi/stream/series/$imdbId:1:1.json" | ||||
|     } | ||||
|     return app.get(url) | ||||
|         .parsedSafe<WatchhubResponse>()?.streams?.find { it.name == "Netflix" }?.externalUrl | ||||
|         ?.substringAfterLast("/") | ||||
| } | ||||
| 
 | ||||
| suspend fun loadCustomExtractor( | ||||
|     name: String? = null, | ||||
|     url: String, | ||||
|  | @ -1154,8 +1166,8 @@ suspend fun loadCustomExtractor( | |||
|                 name ?: link.name, | ||||
|                 link.url, | ||||
|                 link.referer, | ||||
|                 when { | ||||
|                     link.type == ExtractorLinkType.M3U8 -> link.quality | ||||
|                 when (link.type) { | ||||
|                     ExtractorLinkType.M3U8 -> link.quality | ||||
|                     else -> quality ?: link.quality | ||||
|                 }, | ||||
|                 link.type, | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue