mirror of
https://github.com/hexated/cloudstream-extensions-hexated.git
synced 2024-08-15 00:03:22 +00:00
parent
7d49cd44a0
commit
11b4998d1d
9 changed files with 137 additions and 141 deletions
|
@ -1,7 +1,7 @@
|
|||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
// use an integer for version numbers
|
||||
version = 217
|
||||
version = 218
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
|
|
|
@ -1275,7 +1275,7 @@ object SoraExtractor : SoraStream() {
|
|||
val selector =
|
||||
if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)"
|
||||
val server = app.get(
|
||||
href ?: return@apmap, interceptor = wpredisInterceptor
|
||||
href ?: return@apmap, interceptor = wpRedisInterceptor
|
||||
).document.selectFirst("div.entry-content > $selector")
|
||||
?.attr("href") ?: return@apmap
|
||||
|
||||
|
@ -1717,13 +1717,13 @@ object SoraExtractor : SoraStream() {
|
|||
"$url&apikey=whXgvN4kVyoubGwqXpw26Oy3PVryl8dm",
|
||||
referer = "https://watcha.movie/"
|
||||
).text
|
||||
val link = Regex("\"file\":\"(http.*?)\"").find(res)?.groupValues?.getOrNull(1) ?: return
|
||||
val link = Regex("\"file\":\"(http.*?)\"").find(res)?.groupValues?.getOrNull(1)
|
||||
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
"RStream",
|
||||
"RStream",
|
||||
link,
|
||||
link ?: return,
|
||||
"$rStreamAPI/",
|
||||
Qualities.P1080.value,
|
||||
INFER_TYPE
|
||||
|
@ -2053,7 +2053,7 @@ object SoraExtractor : SoraStream() {
|
|||
"$dahmerMoviesAPI/tvs/${title?.replace(":", " -")}/Season $season/"
|
||||
}
|
||||
|
||||
val request = app.get(url, timeout = 120L)
|
||||
val request = app.get(url, interceptor = TimeOutInterceptor())
|
||||
if (!request.isSuccessful) return
|
||||
val paths = request.document.select("a").map {
|
||||
it.text() to it.attr("href")
|
||||
|
@ -2382,12 +2382,18 @@ object SoraExtractor : SoraStream() {
|
|||
callback: (ExtractorLink) -> Unit,
|
||||
referer: String = "https://bflix.gs/"
|
||||
) {
|
||||
suspend fun String.isSuccess() : Boolean {
|
||||
return app.get(this, referer = referer).isSuccessful
|
||||
}
|
||||
val slug = getEpisodeSlug(season, episode)
|
||||
var url =
|
||||
if (season == null) "$nowTvAPI/$tmdbId.mp4" else "$nowTvAPI/tv/$tmdbId/s${season}e${slug.second}.mp4"
|
||||
if (!app.get(url, referer = referer).isSuccessful) {
|
||||
url =
|
||||
if (season == null) "$nowTvAPI/$imdbId.mp4" else "$nowTvAPI/tv/$imdbId/s${season}e${slug.second}.mp4"
|
||||
var url = if (season == null) "$nowTvAPI/$tmdbId.mp4" else "$nowTvAPI/tv/$tmdbId/s${season}e${slug.second}.mp4"
|
||||
if (!url.isSuccess()) {
|
||||
url = if (season == null) {
|
||||
val temp = "$nowTvAPI/$imdbId.mp4"
|
||||
if (temp.isSuccess()) temp else "$nowTvAPI/$tmdbId-1.mp4"
|
||||
} else {
|
||||
"$nowTvAPI/tv/$imdbId/s${season}e${slug.second}.mp4"
|
||||
}
|
||||
if (!app.get(url, referer = referer).isSuccessful) return
|
||||
}
|
||||
callback.invoke(
|
||||
|
|
|
@ -68,7 +68,7 @@ open class SoraStream : TmdbProvider() {
|
|||
TvType.Anime,
|
||||
)
|
||||
|
||||
val wpredisInterceptor by lazy { CloudflareKiller() }
|
||||
val wpRedisInterceptor by lazy { CloudflareKiller() }
|
||||
val multiInterceptor by lazy { CloudflareKiller() }
|
||||
|
||||
/** AUTHOR : Hexated & Sora */
|
||||
|
@ -250,8 +250,7 @@ open class SoraStream : TmdbProvider() {
|
|||
val recommendations =
|
||||
res.recommendations?.results?.mapNotNull { media -> media.toSearchResponse() }
|
||||
|
||||
val trailer =
|
||||
res.videos?.results?.map { "https://www.youtube.com/watch?v=${it.key}" }?.randomOrNull()
|
||||
val trailer = res.videos?.results?.map { "https://www.youtube.com/watch?v=${it.key}" }
|
||||
|
||||
return if (type == TvType.TvSeries) {
|
||||
val lastSeason = res.last_episode_to_air?.season_number
|
||||
|
|
|
@ -23,6 +23,7 @@ import com.lagradost.nicehttp.requestCreator
|
|||
import kotlinx.coroutines.delay
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
|
@ -1285,23 +1286,17 @@ private enum class Symbol(val decimalValue: Int) {
|
|||
}
|
||||
}
|
||||
|
||||
suspend fun request(
|
||||
url: String,
|
||||
allowRedirects: Boolean = true,
|
||||
timeout: Long = 60L
|
||||
): Response {
|
||||
val client = OkHttpClient().newBuilder()
|
||||
.connectTimeout(timeout, TimeUnit.SECONDS)
|
||||
.readTimeout(timeout, TimeUnit.SECONDS)
|
||||
.writeTimeout(timeout, TimeUnit.SECONDS)
|
||||
.followRedirects(allowRedirects)
|
||||
.followSslRedirects(allowRedirects)
|
||||
.build()
|
||||
|
||||
val request: Request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
return client.newCall(request).await()
|
||||
class TimeOutInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val call = chain
|
||||
.withConnectTimeout(60, TimeUnit.SECONDS)
|
||||
.withReadTimeout(60, TimeUnit.SECONDS)
|
||||
.withWriteTimeout(60, TimeUnit.SECONDS)
|
||||
.request()
|
||||
.newBuilder()
|
||||
.build()
|
||||
return chain.proceed(call)
|
||||
}
|
||||
}
|
||||
|
||||
// steal from https://github.com/aniyomiorg/aniyomi-extensions/blob/master/src/en/aniwave/src/eu/kanade/tachiyomi/animeextension/en/nineanime/AniwaveUtils.kt
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
// use an integer for version numbers
|
||||
version = 12
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
// use an integer for version numbers
|
||||
version = 13
|
||||
|
||||
android {
|
||||
defaultConfig {
|
||||
val properties = Properties()
|
||||
properties.load(project.rootProject.file("local.properties").inputStream())
|
||||
|
||||
buildConfigField("String", "TMDB_API", "\"${properties.getProperty("TMDB_API")}\"")
|
||||
}
|
||||
}
|
||||
|
||||
cloudstream {
|
||||
language = "en"
|
||||
|
|
|
@ -10,24 +10,23 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
|||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import java.net.URI
|
||||
|
||||
private const val TRACKER_LIST_URL =
|
||||
"https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt"
|
||||
|
||||
class StremioC : MainAPI() {
|
||||
override var mainUrl = "https://stremio.github.io/stremio-static-addon-example"
|
||||
override var name = "StremioC"
|
||||
override val supportedTypes = setOf(TvType.Others)
|
||||
override val hasMainPage = true
|
||||
private val cinemataUrl = "https://v3-cinemeta.strem.io"
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse? {
|
||||
companion object {
|
||||
private const val cinemataUrl = "https://v3-cinemeta.strem.io"
|
||||
private const val TRACKER_LIST_URL = "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt"
|
||||
}
|
||||
|
||||
override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
|
||||
mainUrl = mainUrl.fixSourceUrl()
|
||||
val res = tryParseJson<Manifest>(request("${mainUrl}/manifest.json").body.string()) ?: return null
|
||||
val res = app.get("${mainUrl}/manifest.json").parsedSafe<Manifest>()
|
||||
val lists = mutableListOf<HomePageList>()
|
||||
res.catalogs.apmap { catalog ->
|
||||
res?.catalogs?.apmap { catalog ->
|
||||
catalog.toHomePageList(this).let {
|
||||
if (it.list.isNotEmpty()) lists.add(it)
|
||||
}
|
||||
|
@ -38,11 +37,11 @@ class StremioC : MainAPI() {
|
|||
)
|
||||
}
|
||||
|
||||
override suspend fun search(query: String): List<SearchResponse>? {
|
||||
override suspend fun search(query: String): List<SearchResponse> {
|
||||
mainUrl = mainUrl.fixSourceUrl()
|
||||
val res = tryParseJson<Manifest>(request("${mainUrl}/manifest.json").body.string()) ?: return null
|
||||
val res = app.get("${mainUrl}/manifest.json").parsedSafe<Manifest>()
|
||||
val list = mutableListOf<SearchResponse>()
|
||||
res.catalogs.apmap { catalog ->
|
||||
res?.catalogs?.apmap { catalog ->
|
||||
list.addAll(catalog.search(query, this))
|
||||
}
|
||||
return list.distinct()
|
||||
|
@ -64,10 +63,13 @@ class StremioC : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
val loadData = parseJson<LoadData>(data)
|
||||
val request = request("${mainUrl}/stream/${loadData.type}/${loadData.id}.json")
|
||||
if (request.code.isSuccessful()) {
|
||||
val res = tryParseJson<StreamsResponse>(request.body.string()) ?: return false
|
||||
res.streams.forEach { stream ->
|
||||
val request = app.get(
|
||||
"${mainUrl}/stream/${loadData.type}/${loadData.id}.json",
|
||||
interceptor = interceptor
|
||||
)
|
||||
if (request.isSuccessful) {
|
||||
val res = request.parsedSafe<StreamsResponse>()
|
||||
res?.streams?.forEach { stream ->
|
||||
stream.runCallback(subtitleCallback, callback)
|
||||
}
|
||||
} else {
|
||||
|
@ -103,15 +105,14 @@ class StremioC : MainAPI() {
|
|||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val sites =
|
||||
AcraApplication.getKey<Array<CustomSite>>(USER_PROVIDER_API)?.toMutableList()
|
||||
?: mutableListOf()
|
||||
val sites = AcraApplication.getKey<Array<CustomSite>>(USER_PROVIDER_API)?.toMutableList()
|
||||
?: mutableListOf()
|
||||
sites.filter { it.parentJavaClass == "StremioX" }.apmap { site ->
|
||||
val request = request("${site.url.fixSourceUrl()}/stream/${type}/${id}.json").body.string()
|
||||
val res =
|
||||
tryParseJson<StreamsResponse>(request)
|
||||
?: return@apmap
|
||||
res.streams.forEach { stream ->
|
||||
val res = app.get(
|
||||
"${site.url.fixSourceUrl()}/stream/${type}/${id}.json",
|
||||
interceptor = interceptor
|
||||
).parsedSafe<StreamsResponse>()
|
||||
res?.streams?.forEach { stream ->
|
||||
stream.runCallback(subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
@ -151,11 +152,11 @@ class StremioC : MainAPI() {
|
|||
suspend fun search(query: String, provider: StremioC): List<SearchResponse> {
|
||||
val entries = mutableListOf<SearchResponse>()
|
||||
types.forEach { type ->
|
||||
val json = request("${provider.mainUrl}/catalog/${type}/${id}/search=${query}.json").body.string()
|
||||
val res =
|
||||
tryParseJson<CatalogResponse>(json)
|
||||
?: return@forEach
|
||||
res.metas?.forEach { entry ->
|
||||
val res = app.get(
|
||||
"${provider.mainUrl}/catalog/${type}/${id}/search=${query}.json",
|
||||
interceptor = interceptor
|
||||
).parsedSafe<CatalogResponse>()
|
||||
res?.metas?.forEach { entry ->
|
||||
entries.add(entry.toSearchResponse(provider))
|
||||
}
|
||||
}
|
||||
|
@ -165,11 +166,11 @@ class StremioC : MainAPI() {
|
|||
suspend fun toHomePageList(provider: StremioC): HomePageList {
|
||||
val entries = mutableListOf<SearchResponse>()
|
||||
types.forEach { type ->
|
||||
val json = request("${provider.mainUrl}/catalog/${type}/${id}.json").body.string()
|
||||
val res =
|
||||
tryParseJson<CatalogResponse>(json)
|
||||
?: return@forEach
|
||||
res.metas?.forEach { entry ->
|
||||
val res = app.get(
|
||||
"${provider.mainUrl}/catalog/${type}/${id}.json",
|
||||
interceptor = interceptor
|
||||
).parsedSafe<CatalogResponse>()
|
||||
res?.metas?.forEach { entry ->
|
||||
entries.add(entry.toSearchResponse(provider))
|
||||
}
|
||||
}
|
||||
|
@ -186,6 +187,7 @@ class StremioC : MainAPI() {
|
|||
val source: String?,
|
||||
val type: String?
|
||||
)
|
||||
|
||||
private data class CatalogEntry(
|
||||
@JsonProperty("name") val name: String,
|
||||
@JsonProperty("id") val id: String,
|
||||
|
@ -226,7 +228,7 @@ class StremioC : MainAPI() {
|
|||
year = yearNum?.toIntOrNull()
|
||||
tags = genre ?: genres
|
||||
addActors(cast)
|
||||
addTrailer(trailersSources?.map { "https://www.youtube.com/watch?v=${it.source}" }?.randomOrNull())
|
||||
addTrailer(trailersSources?.map { "https://www.youtube.com/watch?v=${it.source}" })
|
||||
addImdbId(imdbId)
|
||||
}
|
||||
} else {
|
||||
|
@ -245,7 +247,8 @@ class StremioC : MainAPI() {
|
|||
year = yearNum?.toIntOrNull()
|
||||
tags = genre ?: genres
|
||||
addActors(cast)
|
||||
addTrailer(trailersSources?.map { "https://www.youtube.com/watch?v=${it.source}" }?.randomOrNull())
|
||||
addTrailer(trailersSources?.map { "https://www.youtube.com/watch?v=${it.source}" }
|
||||
?.randomOrNull())
|
||||
addImdbId(imdbId)
|
||||
}
|
||||
}
|
||||
|
@ -285,13 +288,14 @@ class StremioC : MainAPI() {
|
|||
)
|
||||
|
||||
private data class ProxyHeaders(
|
||||
val request: Map<String,String>?,
|
||||
val request: Map<String, String>?,
|
||||
)
|
||||
|
||||
private data class BehaviorHints(
|
||||
val proxyHeaders: ProxyHeaders?,
|
||||
val headers: Map<String,String>?,
|
||||
val headers: Map<String, String>?,
|
||||
)
|
||||
|
||||
private data class Stream(
|
||||
val name: String?,
|
||||
val title: String?,
|
||||
|
@ -312,12 +316,13 @@ class StremioC : MainAPI() {
|
|||
callback.invoke(
|
||||
ExtractorLink(
|
||||
name ?: "",
|
||||
fixRDSourceName(name, title),
|
||||
fixSourceName(name, title),
|
||||
url,
|
||||
"",
|
||||
getQualityFromName(description),
|
||||
headers = behaviorHints?.proxyHeaders?.request ?: behaviorHints?.headers ?: mapOf(),
|
||||
isM3u8 = URI(url).path.endsWith(".m3u8")
|
||||
getQuality(listOf(description,title,name)),
|
||||
headers = behaviorHints?.proxyHeaders?.request ?: behaviorHints?.headers
|
||||
?: mapOf(),
|
||||
type = INFER_TYPE
|
||||
)
|
||||
)
|
||||
subtitles.map { sub ->
|
||||
|
|
|
@ -10,26 +10,21 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
|||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.toJson
|
||||
import java.net.URI
|
||||
import java.util.ArrayList
|
||||
import kotlin.math.roundToInt
|
||||
import com.lagradost.cloudstream3.metaproviders.TmdbProvider
|
||||
|
||||
open class StremioX : TmdbProvider() {
|
||||
class StremioX : TmdbProvider() {
|
||||
override var mainUrl = "https://torrentio.strem.fun"
|
||||
override var name = "StremioX"
|
||||
override val hasMainPage = true
|
||||
override val hasQuickSearch = true
|
||||
override val supportedTypes = setOf(
|
||||
TvType.Others,
|
||||
)
|
||||
override val supportedTypes = setOf(TvType.Others)
|
||||
|
||||
companion object {
|
||||
const val TRACKER_LIST_URL =
|
||||
"https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt"
|
||||
const val TRACKER_LIST_URL = "https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt"
|
||||
private const val tmdbAPI = "https://api.themoviedb.org/3"
|
||||
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 const val apiKey = BuildConfig.TMDB_API
|
||||
|
||||
fun getType(t: String?): TvType {
|
||||
return when (t) {
|
||||
|
@ -44,11 +39,6 @@ open class StremioX : TmdbProvider() {
|
|||
else -> ShowStatus.Completed
|
||||
}
|
||||
}
|
||||
|
||||
private fun base64DecodeAPI(api: String): String {
|
||||
return api.chunked(4).map { base64Decode(it) }.reversed().joinToString("")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override val mainPage = mainPageOf(
|
||||
|
@ -159,7 +149,7 @@ open class StremioX : TmdbProvider() {
|
|||
eps.seasonNumber,
|
||||
eps.episodeNumber
|
||||
).toJson(),
|
||||
name = eps.name + if (isUpcoming(eps.airDate)) " - [UPCOMING]" else "",
|
||||
name = eps.name + if (isUpcoming(eps.airDate)) " • [UPCOMING]" else "",
|
||||
season = eps.seasonNumber,
|
||||
episode = eps.episodeNumber,
|
||||
posterUrl = getImageUrl(eps.stillPath),
|
||||
|
@ -177,7 +167,7 @@ open class StremioX : TmdbProvider() {
|
|||
this.backgroundPosterUrl = bgPoster
|
||||
this.year = year
|
||||
this.plot = res.overview
|
||||
this.tags = if (isAnime) keywords else genres
|
||||
this.tags = keywords.takeIf { !it.isNullOrEmpty() } ?: genres
|
||||
this.rating = rating
|
||||
this.showStatus = getStatus(res.status)
|
||||
this.recommendations = recommendations
|
||||
|
@ -200,7 +190,7 @@ open class StremioX : TmdbProvider() {
|
|||
this.year = year
|
||||
this.plot = res.overview
|
||||
this.duration = res.runtime
|
||||
this.tags = if (isAnime) keywords else genres
|
||||
this.tags = keywords.takeIf { !it.isNullOrEmpty() } ?: genres
|
||||
this.rating = rating
|
||||
this.recommendations = recommendations
|
||||
this.actors = actors
|
||||
|
@ -243,13 +233,13 @@ open class StremioX : TmdbProvider() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val fixMainUrl = mainUrl.fixSourceUrl()
|
||||
val url = if(season == null) {
|
||||
val url = if (season == null) {
|
||||
"$fixMainUrl/stream/movie/$imdbId.json"
|
||||
} else {
|
||||
"$fixMainUrl/stream/series/$imdbId:$season:$episode.json"
|
||||
}
|
||||
val res = AppUtils.tryParseJson<StreamsResponse>(request(url).body.string()) ?: return
|
||||
res.streams.forEach { stream ->
|
||||
val res = app.get(url, interceptor = interceptor).parsedSafe<StreamsResponse>()
|
||||
res?.streams?.forEach { stream ->
|
||||
stream.runCallback(subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
@ -262,12 +252,12 @@ open class StremioX : TmdbProvider() {
|
|||
)
|
||||
|
||||
private data class ProxyHeaders(
|
||||
val request: Map<String,String>?,
|
||||
val request: Map<String, String>?,
|
||||
)
|
||||
|
||||
private data class BehaviorHints(
|
||||
val proxyHeaders: ProxyHeaders?,
|
||||
val headers: Map<String,String>?,
|
||||
val headers: Map<String, String>?,
|
||||
)
|
||||
|
||||
private data class Stream(
|
||||
|
@ -290,12 +280,13 @@ open class StremioX : TmdbProvider() {
|
|||
callback.invoke(
|
||||
ExtractorLink(
|
||||
name ?: "",
|
||||
fixRDSourceName(name, title),
|
||||
fixSourceName(name, title),
|
||||
url,
|
||||
"",
|
||||
getQualityFromName(description),
|
||||
headers = behaviorHints?.proxyHeaders?.request ?: behaviorHints?.headers ?: mapOf(),
|
||||
isM3u8 = URI(url).path.endsWith(".m3u8")
|
||||
getQuality(listOf(description,title,name)),
|
||||
headers = behaviorHints?.proxyHeaders?.request ?: behaviorHints?.headers
|
||||
?: mapOf(),
|
||||
type = INFER_TYPE
|
||||
)
|
||||
)
|
||||
subtitles.map { sub ->
|
||||
|
|
|
@ -3,10 +3,9 @@ package com.hexated
|
|||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64Encode
|
||||
import com.lagradost.cloudstream3.utils.SubtitleHelper
|
||||
|
||||
const val openSubAPI = "https://opensubtitles.strem.io/stremio/v1"
|
||||
const val openSubAPI = "https://opensubtitles-v3.strem.io"
|
||||
const val watchSomuchAPI = "https://watchsomuch.tv"
|
||||
|
||||
object SubsExtractors {
|
||||
|
@ -16,22 +15,20 @@ object SubsExtractors {
|
|||
episode: Int? = null,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
) {
|
||||
val id = if(season == null) {
|
||||
imdbId
|
||||
val slug = if(season == null) {
|
||||
"movie/$imdbId"
|
||||
} else {
|
||||
"$imdbId $season $episode"
|
||||
"series/$imdbId:$season:$episode"
|
||||
}
|
||||
val data = base64Encode("""{"id":1,"jsonrpc":"2.0","method":"subtitles.find","params":[null,{"query":{"itemHash":"$id"}}]}""".toByteArray())
|
||||
app.get("${openSubAPI}/q.json?b=$data").parsedSafe<OsResult>()?.result?.all?.map { sub ->
|
||||
app.get("${openSubAPI}/subtitles/$slug.json").parsedSafe<OsResult>()?.subtitles?.map { sub ->
|
||||
subtitleCallback.invoke(
|
||||
SubtitleFile(
|
||||
SubtitleHelper.fromThreeLettersToLanguage(sub.lang ?: "") ?: sub.lang
|
||||
?: "",
|
||||
?: return@map,
|
||||
sub.url ?: return@map
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
suspend fun invokeWatchsomuch(
|
||||
|
@ -81,12 +78,8 @@ object SubsExtractors {
|
|||
@JsonProperty("lang") val lang: String? = null,
|
||||
)
|
||||
|
||||
data class OsAll(
|
||||
@JsonProperty("all") val all: ArrayList<OsSubtitles>? = arrayListOf(),
|
||||
)
|
||||
|
||||
data class OsResult(
|
||||
@JsonProperty("result") val result: OsAll? = null,
|
||||
@JsonProperty("subtitles") val subtitles: ArrayList<OsSubtitles>? = arrayListOf(),
|
||||
)
|
||||
|
||||
data class WatchsomuchTorrents(
|
||||
|
|
|
@ -1,53 +1,50 @@
|
|||
package com.hexated
|
||||
|
||||
import com.lagradost.cloudstream3.APIHolder
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.nicehttp.Requests.Companion.await
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Response
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
const val defaultTimeOut = 30L
|
||||
suspend fun request(
|
||||
url: String,
|
||||
allowRedirects: Boolean = true,
|
||||
timeout: Long = defaultTimeOut
|
||||
): Response {
|
||||
val client = OkHttpClient().newBuilder()
|
||||
.connectTimeout(timeout, TimeUnit.SECONDS)
|
||||
.readTimeout(timeout, TimeUnit.SECONDS)
|
||||
.writeTimeout(timeout, TimeUnit.SECONDS)
|
||||
.followRedirects(allowRedirects)
|
||||
.followSslRedirects(allowRedirects)
|
||||
.build()
|
||||
val interceptor = TimeOutInterceptor()
|
||||
|
||||
val request: Request = Request.Builder()
|
||||
.url(url)
|
||||
.build()
|
||||
return client.newCall(request).await()
|
||||
}
|
||||
|
||||
fun Int.isSuccessful() : Boolean {
|
||||
return this in 200..299
|
||||
class TimeOutInterceptor : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val call = chain
|
||||
.withConnectTimeout(60, TimeUnit.SECONDS)
|
||||
.withReadTimeout(60, TimeUnit.SECONDS)
|
||||
.withWriteTimeout(60, TimeUnit.SECONDS)
|
||||
.request()
|
||||
.newBuilder()
|
||||
.build()
|
||||
return chain.proceed(call)
|
||||
}
|
||||
}
|
||||
|
||||
fun String.fixSourceUrl(): String {
|
||||
return this.replace("/manifest.json", "").replace("stremio://", "https://")
|
||||
}
|
||||
|
||||
fun fixRDSourceName(name: String?, title: String?): String {
|
||||
fun fixSourceName(name: String?, title: String?): String {
|
||||
return when {
|
||||
name?.contains("[RD+]", true) == true -> "[RD+] $title"
|
||||
name?.contains("[RD download]", true) == true -> "[RD] $title"
|
||||
name?.contains("[RD download]", true) == true -> "[RD download] $title"
|
||||
!name.isNullOrEmpty() && !title.isNullOrEmpty() -> "$name $title"
|
||||
else -> title ?: name ?: ""
|
||||
}
|
||||
}
|
||||
|
||||
fun getQuality(qualities: List<String?>): Int {
|
||||
fun String.getQuality(): String? {
|
||||
return Regex("(\\d{3,4}[pP])").find(this)?.groupValues?.getOrNull(1)
|
||||
}
|
||||
val quality = qualities.firstNotNullOfOrNull { it?.getQuality() }
|
||||
return getQualityFromName(quality)
|
||||
}
|
||||
|
||||
fun getEpisodeSlug(
|
||||
season: Int? = null,
|
||||
episode: Int? = null,
|
||||
|
|
Loading…
Reference in a new issue