mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Extractors (#677)
* StreamSB fix and Jawcloud * Fixes and referer for gogoanime * streamsb fix * Update StreamSB.kt Co-authored-by: Osten <11805592+LagradOst@users.noreply.github.com>
This commit is contained in:
parent
8f9ac96de5
commit
6500d3d897
6 changed files with 243 additions and 58 deletions
|
@ -305,7 +305,7 @@ class GogoanimeProvider : MainAPI() {
|
||||||
this.name,
|
this.name,
|
||||||
"${this.name} ${source.label?.replace("0 P", "0p") ?: ""}",
|
"${this.name} ${source.label?.replace("0 P", "0p") ?: ""}",
|
||||||
source.file,
|
source.file,
|
||||||
"",
|
"https://gogoplay.io",
|
||||||
getQualityFromName(source.label ?: ""),
|
getQualityFromName(source.label ?: ""),
|
||||||
isM3u8 = source.type == "hls"
|
isM3u8 = source.type == "hls"
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.apmap
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class ZplayerV2 : GenericM3U8() {
|
||||||
|
override val name = "Zplayer V2"
|
||||||
|
override val mainUrl = "https://v2.zplayer.live"
|
||||||
|
}
|
||||||
|
|
||||||
|
open class GenericM3U8 : ExtractorApi() {
|
||||||
|
override val name = "Upstream"
|
||||||
|
override val mainUrl = "https://upstream.to"
|
||||||
|
override val requiresReferer = false
|
||||||
|
|
||||||
|
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||||
|
val response = app.get(
|
||||||
|
url, interceptor = WebViewResolver(
|
||||||
|
Regex("""master\.m3u8""")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
val sources = mutableListOf<ExtractorLink>()
|
||||||
|
if (response.url.contains("m3u8")) M3u8Helper().m3u8Generation(
|
||||||
|
M3u8Helper.M3u8Stream(
|
||||||
|
response.url,
|
||||||
|
headers = response.headers.toMap()
|
||||||
|
), true
|
||||||
|
)
|
||||||
|
.map { stream ->
|
||||||
|
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
|
||||||
|
sources.add( ExtractorLink(
|
||||||
|
name,
|
||||||
|
"$name $qualityString",
|
||||||
|
stream.streamUrl,
|
||||||
|
url,
|
||||||
|
getQualityFromName(stream.quality.toString()),
|
||||||
|
true
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return sources
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.apmap
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
|
||||||
|
|
||||||
|
open class Jawcloud : ExtractorApi() {
|
||||||
|
override val name = "Jawcloud"
|
||||||
|
override val mainUrl = "https://jawcloud.co"
|
||||||
|
override val requiresReferer = false
|
||||||
|
|
||||||
|
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
val doc = app.get(url).document
|
||||||
|
val urlString = doc.select("html body div source").attr("src")
|
||||||
|
val sources = mutableListOf<ExtractorLink>()
|
||||||
|
if (urlString.contains("m3u8")) M3u8Helper().m3u8Generation(
|
||||||
|
M3u8Helper.M3u8Stream(
|
||||||
|
urlString,
|
||||||
|
headers = app.get(url).headers.toMap()
|
||||||
|
), true
|
||||||
|
)
|
||||||
|
.map { stream ->
|
||||||
|
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
|
||||||
|
sources.add( ExtractorLink(
|
||||||
|
name,
|
||||||
|
"$name $qualityString",
|
||||||
|
stream.streamUrl,
|
||||||
|
url,
|
||||||
|
getQualityFromName(stream.quality.toString()),
|
||||||
|
true
|
||||||
|
))
|
||||||
|
}
|
||||||
|
return sources
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,17 +9,13 @@ import com.lagradost.cloudstream3.utils.Qualities
|
||||||
import com.lagradost.cloudstream3.utils.getPostForm
|
import com.lagradost.cloudstream3.utils.getPostForm
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
class SBPlay1 : SBPlay() {
|
//class SBPlay1 : SBPlay() {
|
||||||
override val mainUrl = "https://sbplay1.com"
|
// override val mainUrl = "https://sbplay1.com"
|
||||||
}
|
//}
|
||||||
|
|
||||||
class SBPlay2 : SBPlay() {
|
//class SBPlay2 : SBPlay() {
|
||||||
override val mainUrl = "https://sbplay2.com"
|
// override val mainUrl = "https://sbplay2.com"
|
||||||
}
|
//}
|
||||||
|
|
||||||
class SBPlay3 : SBPlay() {
|
|
||||||
override val mainUrl = "https://pelistop.co"
|
|
||||||
}
|
|
||||||
|
|
||||||
open class SBPlay : ExtractorApi() {
|
open class SBPlay : ExtractorApi() {
|
||||||
override val mainUrl = "https://sbplay.one"
|
override val mainUrl = "https://sbplay.one"
|
||||||
|
|
|
@ -1,52 +1,142 @@
|
||||||
package com.lagradost.cloudstream3.extractors
|
package com.lagradost.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.USER_AGENT
|
||||||
|
import com.lagradost.cloudstream3.apmap
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
import com.lagradost.cloudstream3.app
|
import com.lagradost.cloudstream3.app
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
|
||||||
import com.lagradost.cloudstream3.utils.getAndUnpack
|
|
||||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
|
||||||
|
|
||||||
class StreamSB : ExtractorApi() {
|
|
||||||
override val name = "StreamSB"
|
class StreamSB1 : StreamSB() {
|
||||||
|
override val mainUrl = "https://sbplay1.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamSB2 : StreamSB() {
|
||||||
|
override val mainUrl = "https://sbplay2.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamSB3 : StreamSB() {
|
||||||
|
override val mainUrl = "https://sbplay.one"
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamSB4 : StreamSB() {
|
||||||
|
override val mainUrl = "https://cloudemb.com"
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamSB5 : StreamSB() {
|
||||||
override val mainUrl = "https://sbplay.org"
|
override val mainUrl = "https://sbplay.org"
|
||||||
private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*"(.*?)"""")
|
}
|
||||||
|
|
||||||
//private val m3u8Regex = Regex(""".*?(\d*).m3u8""")
|
class StreamSB6 : StreamSB() {
|
||||||
//private val urlRegex = Regex("""(.*?)([^/]+$)""")
|
override val mainUrl = "https://embedsb.com"
|
||||||
|
}
|
||||||
|
|
||||||
// 1: Resolution 2: url
|
class StreamSB7 : StreamSB() {
|
||||||
private val m3u8UrlRegex = Regex("""RESOLUTION=\d*x(\d*).*\n(http.*.m3u8)""")
|
override val mainUrl = "https://pelistop.co"
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamSB8 : StreamSB() {
|
||||||
|
override val mainUrl = "https://streamsb.net"
|
||||||
|
}
|
||||||
|
|
||||||
|
class StreamSB9 : StreamSB() {
|
||||||
|
override val mainUrl = "https://sbplay.one"
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt
|
||||||
|
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
|
||||||
|
open class StreamSB : ExtractorApi() {
|
||||||
|
override val name = "StreamSB"
|
||||||
|
override val mainUrl = "https://watchsb.com"
|
||||||
override val requiresReferer = false
|
override val requiresReferer = false
|
||||||
|
|
||||||
// https://sbembed.com/embed-ns50b0cukf9j.html -> https://sbvideo.net/play/ns50b0cukf9j
|
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
|
||||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
private fun bytesToHex(bytes: ByteArray): String {
|
||||||
val newUrl = url.replace("sbplay.org/embed-", "sbplay.org/play/").removeSuffix(".html")
|
val hexChars = CharArray(bytes.size * 2)
|
||||||
with(app.get(newUrl, timeout = 10)) {
|
for (j in bytes.indices) {
|
||||||
getAndUnpack(this.text).let {
|
val v = bytes[j].toInt() and 0xFF
|
||||||
sourceRegex.findAll(it).forEach { sourceMatch ->
|
|
||||||
val extractedUrl = sourceMatch.groupValues[1]
|
hexChars[j * 2] = hexArray[v ushr 4]
|
||||||
if (extractedUrl.contains(".m3u8")) {
|
hexChars[j * 2 + 1] = hexArray[v and 0x0F]
|
||||||
with(app.get(extractedUrl)) {
|
|
||||||
m3u8UrlRegex.findAll(this.text).forEach { match ->
|
|
||||||
val extractedUrlM3u8 = match.groupValues[2]
|
|
||||||
val extractedRes = match.groupValues[1]
|
|
||||||
extractedLinksList.add(
|
|
||||||
ExtractorLink(
|
|
||||||
name,
|
|
||||||
"$name ${extractedRes}p",
|
|
||||||
extractedUrlM3u8,
|
|
||||||
extractedUrl,
|
|
||||||
getQualityFromName(extractedRes),
|
|
||||||
true
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return extractedLinksList
|
return String(hexChars)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class StreamData (
|
||||||
|
@JsonProperty("file") val file: String,
|
||||||
|
@JsonProperty("cdn_img") val cdnImg: String,
|
||||||
|
@JsonProperty("hash") val hash: String,
|
||||||
|
@JsonProperty("subs") val subs: List<String>,
|
||||||
|
@JsonProperty("length") val length: String,
|
||||||
|
@JsonProperty("id") val id: String,
|
||||||
|
@JsonProperty("title") val title: String,
|
||||||
|
@JsonProperty("backup") val backup: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Main (
|
||||||
|
@JsonProperty("stream_data") val streamData: StreamData,
|
||||||
|
@JsonProperty("status_code") val statusCode: Int,
|
||||||
|
)
|
||||||
|
|
||||||
|
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
val regexID = Regex("(embed-[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+|\\/e\\/[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||||
|
val id = regexID.findAll(url).map {
|
||||||
|
it.value.replace(Regex("(embed-|\\/e\\/)"),"")
|
||||||
|
}.first()
|
||||||
|
val bytes = id.toByteArray()
|
||||||
|
val bytesToHex = bytesToHex(bytes)
|
||||||
|
val master = "$mainUrl/sources40/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"
|
||||||
|
val headers = mapOf(
|
||||||
|
"Host" to url.substringAfter("https://").substringBefore("/"),
|
||||||
|
"User-Agent" to USER_AGENT,
|
||||||
|
"Accept" to "application/json, text/plain, */*",
|
||||||
|
"Accept-Language" to "en-US,en;q=0.5",
|
||||||
|
"Referer" to url,
|
||||||
|
"watchsb" to "streamsb",
|
||||||
|
"DNT" to "1",
|
||||||
|
"Connection" to "keep-alive",
|
||||||
|
"Sec-Fetch-Dest" to "empty",
|
||||||
|
"Sec-Fetch-Mode" to "no-cors",
|
||||||
|
"Sec-Fetch-Site" to "same-origin",
|
||||||
|
"TE" to "trailers",
|
||||||
|
"Pragma" to "no-cache",
|
||||||
|
"Cache-Control" to "no-cache",)
|
||||||
|
val urltext = app.get(master,
|
||||||
|
headers = headers,
|
||||||
|
allowRedirects = false
|
||||||
|
).text
|
||||||
|
val mapped = urltext.let { parseJson<Main>(it) }
|
||||||
|
if (urltext.contains("m3u8")) return M3u8Helper().m3u8Generation(
|
||||||
|
M3u8Helper.M3u8Stream(
|
||||||
|
mapped.streamData.file,
|
||||||
|
headers = mapOf(
|
||||||
|
"User-Agent" to USER_AGENT,
|
||||||
|
"Accept" to "*/*",
|
||||||
|
"Accept-Language" to "en-US,en;q=0.5",
|
||||||
|
"Accept-Encoding" to "gzip, deflate, br",
|
||||||
|
"Origin" to mainUrl,
|
||||||
|
"DNT" to "1",
|
||||||
|
"Connection" to "keep-alive",
|
||||||
|
"Referer" to "$mainUrl/",
|
||||||
|
"Sec-Fetch-Dest" to "empty",
|
||||||
|
"Sec-Fetch-Mode" to "cors",
|
||||||
|
"Sec-Fetch-Site" to "cross-site",),
|
||||||
|
), true
|
||||||
|
)
|
||||||
|
.map { stream ->
|
||||||
|
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
"$name $qualityString",
|
||||||
|
stream.streamUrl,
|
||||||
|
url,
|
||||||
|
getQualityFromName(stream.quality.toString()),
|
||||||
|
true
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -100,18 +100,27 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||||
Mcloud(),
|
Mcloud(),
|
||||||
XStreamCdn(),
|
XStreamCdn(),
|
||||||
StreamSB(),
|
StreamSB(),
|
||||||
|
StreamSB1(),
|
||||||
|
StreamSB2(),
|
||||||
|
StreamSB3(),
|
||||||
|
StreamSB4(),
|
||||||
|
StreamSB5(),
|
||||||
|
StreamSB6(),
|
||||||
|
StreamSB7(),
|
||||||
|
StreamSB8(),
|
||||||
|
StreamSB9(),
|
||||||
Streamhub(),
|
Streamhub(),
|
||||||
|
|
||||||
FEmbed(),
|
FEmbed(),
|
||||||
FeHD(),
|
FeHD(),
|
||||||
Fplayer(),
|
Fplayer(),
|
||||||
WatchSB(),
|
// WatchSB(), 'cause StreamSB.kt works
|
||||||
Uqload(),
|
Uqload(),
|
||||||
Uqload1(),
|
Uqload1(),
|
||||||
Evoload(),
|
Evoload(),
|
||||||
Evoload1(),
|
Evoload1(),
|
||||||
VoeExtractor(),
|
VoeExtractor(),
|
||||||
UpstreamExtractor(),
|
// UpstreamExtractor(), GenericM3U8.kt works
|
||||||
|
|
||||||
Tomatomatela(),
|
Tomatomatela(),
|
||||||
Cinestart(),
|
Cinestart(),
|
||||||
|
@ -125,10 +134,15 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||||
|
|
||||||
AsianLoad(),
|
AsianLoad(),
|
||||||
|
|
||||||
SBPlay(),
|
ZplayerV2(),
|
||||||
SBPlay1(),
|
GenericM3U8(),
|
||||||
SBPlay2(),
|
Jawcloud(),
|
||||||
SBPlay3(),
|
|
||||||
|
// StreamSB.kt works
|
||||||
|
// SBPlay(),
|
||||||
|
// SBPlay1(),
|
||||||
|
// SBPlay2(),
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
fun getExtractorApiFromName(name: String): ExtractorApi {
|
fun getExtractorApiFromName(name: String): ExtractorApi {
|
||||||
|
|
Loading…
Reference in a new issue