2022-12-02 13:00:44 +00:00
package com.hexated
2023-02-04 10:58:06 +00:00
import android.util.Base64
2023-01-29 03:29:15 +00:00
import com.hexated.SoraStream.Companion.baymovies
2023-01-19 10:23:58 +00:00
import com.hexated.SoraStream.Companion.consumetCrunchyrollAPI
2022-12-07 19:17:24 +00:00
import com.hexated.SoraStream.Companion.filmxyAPI
2022-12-02 16:50:56 +00:00
import com.hexated.SoraStream.Companion.gdbot
2022-12-15 17:30:38 +00:00
import com.hexated.SoraStream.Companion.tvMoviesAPI
2023-01-29 03:29:15 +00:00
import com.lagradost.cloudstream3.*
2023-01-11 12:42:59 +00:00
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
2022-12-02 13:00:44 +00:00
import com.lagradost.cloudstream3.network.WebViewResolver
2023-01-21 06:25:04 +00:00
import com.lagradost.cloudstream3.utils.*
2022-12-07 19:17:24 +00:00
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
2023-01-11 01:28:46 +00:00
import com.lagradost.nicehttp.NiceResponse
2022-12-09 08:44:01 +00:00
import com.lagradost.nicehttp.RequestBodyTypes
2022-12-02 13:00:44 +00:00
import com.lagradost.nicehttp.requestCreator
2022-12-15 17:30:38 +00:00
import kotlinx.coroutines.delay
2022-12-07 15:06:48 +00:00
import okhttp3.FormBody
2022-12-02 13:00:44 +00:00
import okhttp3.HttpUrl.Companion.toHttpUrl
2022-12-09 08:44:01 +00:00
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
2022-12-10 12:25:28 +00:00
import org.jsoup.nodes.Document
2022-12-02 13:00:44 +00:00
import java.net.URI
2023-01-30 03:42:55 +00:00
import java.net.URL
2023-02-04 10:58:06 +00:00
import java.security.MessageDigest
import java.security.SecureRandom
import java.util.*
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
import kotlin.math.min
2022-12-02 13:00:44 +00:00
data class FilmxyCookies (
val phpsessid : String ? = null ,
val wLog : String ? = null ,
val wSec : String ? = null ,
)
2022-12-05 21:03:26 +00:00
fun String . filterIframe ( seasonNum : Int ? , lastSeason : Int ? , year : Int ? ) : Boolean {
2022-12-02 13:00:44 +00:00
return if ( seasonNum != null ) {
2022-12-05 21:03:26 +00:00
if ( lastSeason == 1 ) {
2023-02-07 14:44:14 +00:00
this . contains ( Regex ( " (?i)(S0? $seasonNum )|(Season \\ s0? $seasonNum )|( \\ d{3,4}p) " ) ) && ! this . contains (
2022-12-02 13:00:44 +00:00
" Download " ,
true
)
} else {
this . contains ( Regex ( " (?i)(S0? $seasonNum )|(Season \\ s0? $seasonNum ) " ) ) && ! this . contains (
" Download " ,
true
)
}
} else {
this . contains ( " $year " , true ) && ! this . contains ( " Download " , true )
}
}
fun String . filterMedia ( title : String ? , yearNum : Int ? , seasonNum : Int ? ) : Boolean {
return if ( seasonNum != null ) {
when {
seasonNum > 1 -> this . contains ( Regex ( " (?i)(Season \\ s0?1-0? $seasonNum )|(S0?1-S?0? $seasonNum ) " ) ) && this . contains (
" $title " ,
true
2022-12-17 12:53:12 +00:00
)
2022-12-02 13:00:44 +00:00
else -> this . contains ( Regex ( " (?i)(Season \\ s0?1)|(S0?1) " ) ) && this . contains (
" $title " ,
true
) && this . contains ( " $yearNum " )
}
} else {
this . contains ( " $title " , true ) && this . contains ( " $yearNum " )
}
}
2023-01-14 09:40:35 +00:00
fun Document . getMirrorLink ( ) : String ? {
return this . select ( " div.mb-4 a " ) . randomOrNull ( )
?. attr ( " href " )
}
fun Document . getMirrorServer ( server : Int ) : String {
return this . select ( " div.text-center a:contains(Server $server ) " ) . attr ( " href " )
}
2022-12-07 19:17:24 +00:00
suspend fun extractMirrorUHD ( url : String , ref : String ) : String ? {
2023-01-14 09:40:35 +00:00
var baseDoc = app . get ( fixUrl ( url , ref ) ) . document
var downLink = baseDoc . getMirrorLink ( )
run lit @ {
( 1. . 2 ) . forEach {
if ( downLink != null ) return @lit
val server = baseDoc . getMirrorServer ( it . plus ( 1 ) )
baseDoc = app . get ( fixUrl ( server , ref ) ) . document
downLink = baseDoc . getMirrorLink ( )
}
2022-12-07 19:17:24 +00:00
}
2023-01-14 09:40:35 +00:00
if ( downLink ?. contains ( " .mkv " ) == true || downLink ?. contains ( " .mp4 " ) == true ) return downLink
2022-12-07 19:17:24 +00:00
val downPage = app . get ( downLink ?: return null ) . document
return downPage . selectFirst ( " form[method=post] a.btn.btn-success " )
?. attr ( " onclick " ) ?. substringAfter ( " Openblank(' " ) ?. substringBefore ( " ') " ) ?: run {
val mirror = downPage . selectFirst ( " form[method=post] a.btn.btn-primary " )
?. attr ( " onclick " ) ?. substringAfter ( " Openblank(' " ) ?. substringBefore ( " ') " )
app . get (
mirror ?: return null
) . document . selectFirst ( " script:containsData(input.value =) " )
?. data ( ) ?. substringAfter ( " input.value = ' " ) ?. substringBefore ( " '; " )
}
}
suspend fun extractBackupUHD ( url : String ) : String ? {
val resumeDoc = app . get ( url )
val script = resumeDoc . document . selectFirst ( " script:containsData(FormData.) " ) ?. data ( )
val ssid = resumeDoc . cookies [ " PHPSESSID " ]
val baseIframe = getBaseUrl ( url )
2023-01-14 09:40:35 +00:00
val fetchLink =
script ?. substringAfter ( " fetch(' " ) ?. substringBefore ( " ', " ) ?. let { fixUrl ( it , baseIframe ) }
2022-12-07 19:17:24 +00:00
val token = script ?. substringAfter ( " 'token', ' " ) ?. substringBefore ( " '); " )
val body = FormBody . Builder ( )
. addEncoded ( " token " , " $token " )
. build ( )
val cookies = mapOf ( " PHPSESSID " to " $ssid " )
val result = app . post (
fetchLink ?: return null ,
requestBody = body ,
headers = mapOf (
" Accept " to " */* " ,
" Origin " to baseIframe ,
" Sec-Fetch-Site " to " same-origin "
) ,
cookies = cookies ,
referer = url
) . text
return tryParseJson < UHDBackupUrl > ( result ) ?. url
}
2022-12-02 16:50:56 +00:00
suspend fun extractGdbot ( url : String ) : String ? {
val headers = mapOf (
" Accept " to " text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 " ,
)
val res = app . get (
" $gdbot / " , headers = headers
)
val token = res . document . selectFirst ( " input[name=_token] " ) ?. attr ( " value " )
val cookiesSet = res . headers . filter { it . first == " set-cookie " }
2022-12-07 15:06:48 +00:00
val xsrf =
cookiesSet . find { it . second . contains ( " XSRF-TOKEN " ) } ?. second ?. substringAfter ( " XSRF-TOKEN= " )
?. substringBefore ( " ; " )
val session =
cookiesSet . find { it . second . contains ( " gdtot_proxy_session " ) } ?. second ?. substringAfter ( " gdtot_proxy_session= " )
?. substringBefore ( " ; " )
2022-12-02 16:50:56 +00:00
val cookies = mapOf (
" gdtot_proxy_session " to " $session " ,
" XSRF-TOKEN " to " $xsrf "
)
val requestFile = app . post (
" $gdbot /file " , data = mapOf (
" link " to url ,
" _token " to " $token "
) , headers = headers , referer = " $gdbot / " , cookies = cookies
) . document
return requestFile . selectFirst ( " div.mt-8 a.float-right " ) ?. attr ( " href " )
}
2022-12-09 08:44:01 +00:00
suspend fun extractDirectDl ( url : String ) : String ? {
2023-01-14 09:40:35 +00:00
val iframe = app . get ( url ) . document . selectFirst ( " li.flex.flex-col.py-6 a:contains(Direct DL) " )
?. attr ( " href " )
2022-12-09 08:44:01 +00:00
val request = app . get ( iframe ?: return null )
val driveDoc = request . document
val token = driveDoc . select ( " section#generate_url " ) . attr ( " data-token " )
val uid = driveDoc . select ( " section#generate_url " ) . attr ( " data-uid " )
val ssid = request . cookies [ " PHPSESSID " ]
2023-01-14 09:40:35 +00:00
val body =
""" {"type":"DOWNLOAD_GENERATE","payload":{"uid":"$uid","access_token":"$token"}} """ . toRequestBody (
RequestBodyTypes . JSON . toMediaTypeOrNull ( )
)
2022-12-09 08:44:01 +00:00
val json = app . post (
" https://rajbetmovies.com/action " , requestBody = body , headers = mapOf (
" Accept " to " application/json, text/plain, */* " ,
" Cookie " to " PHPSESSID= $ssid " ,
" X-Requested-With " to " xmlhttprequest "
) , referer = request . url
) . text
return tryParseJson < DirectDl > ( json ) ?. download _url
}
2022-12-07 15:06:48 +00:00
suspend fun extractDrivebot ( url : String ) : String ? {
2023-01-14 09:40:35 +00:00
val iframeDrivebot =
app . get ( url ) . document . selectFirst ( " li.flex.flex-col.py-6 a:contains(Drivebot) " )
2022-12-20 15:24:47 +00:00
?. attr ( " href " ) ?: return null
return getDrivebotLink ( iframeDrivebot )
}
suspend fun extractGdflix ( url : String ) : String ? {
2023-01-14 09:40:35 +00:00
val iframeGdflix =
app . get ( url ) . document . selectFirst ( " li.flex.flex-col.py-6 a:contains(GDFlix Direct) " )
?. attr ( " href " ) ?: return null
2022-12-20 15:24:47 +00:00
val base = getBaseUrl ( iframeGdflix )
2023-01-14 09:40:35 +00:00
val gdfDoc = app . get ( iframeGdflix ) . document . selectFirst ( " script:containsData(replace) " ) ?. data ( )
?. substringAfter ( " replace( \" " )
2022-12-20 15:24:47 +00:00
?. substringBefore ( " \" ) " ) ?. let {
app . get ( fixUrl ( it , base ) ) . document
}
val iframeDrivebot2 = gdfDoc ?. selectFirst ( " a.btn.btn-outline-warning " ) ?. attr ( " href " )
return getDrivebotLink ( iframeDrivebot2 )
}
suspend fun getDrivebotLink ( url : String ? ) : String ? {
val driveDoc = app . get ( url ?: return null )
2022-12-07 15:06:48 +00:00
val ssid = driveDoc . cookies [ " PHPSESSID " ]
val script = driveDoc . document . selectFirst ( " script:containsData(var formData) " ) ?. data ( )
2022-12-20 15:24:47 +00:00
val baseUrl = getBaseUrl ( url )
2022-12-07 15:06:48 +00:00
val token = script ?. substringAfter ( " 'token', ' " ) ?. substringBefore ( " '); " )
val link =
script ?. substringAfter ( " fetch(' " ) ?. substringBefore ( " ', " ) . let { " $baseUrl $it " }
val body = FormBody . Builder ( )
. addEncoded ( " token " , " $token " )
. build ( )
val cookies = mapOf ( " PHPSESSID " to " $ssid " )
val result = app . post (
link ,
requestBody = body ,
headers = mapOf (
" Accept " to " */* " ,
" Origin " to baseUrl ,
" Sec-Fetch-Site " to " same-origin "
) ,
cookies = cookies ,
2022-12-20 15:24:47 +00:00
referer = url
2022-12-07 15:06:48 +00:00
) . text
2022-12-07 19:17:24 +00:00
return tryParseJson < DriveBotLink > ( result ) ?. url
2022-12-07 15:06:48 +00:00
}
2022-12-12 13:24:46 +00:00
suspend fun extractOiya ( url : String , quality : String ) : String ? {
val doc = app . get ( url ) . document
return doc . selectFirst ( " div.wp-block-button a:matches((?i) $quality ) " ) ?. attr ( " href " )
?: doc . selectFirst ( " div.wp-block-button a " ) ?. attr ( " href " )
}
2022-12-15 17:30:38 +00:00
suspend fun extractCovyn ( url : String ? ) : Pair < String ? , String ? > ? {
val request = session . get ( url ?: return null , referer = " ${tvMoviesAPI} / " )
val filehosting = session . baseClient . cookieJar . loadForRequest ( url . toHttpUrl ( ) )
. find { it . name == " filehosting " } ?. value
val headers = mapOf (
" Accept " to " text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 " ,
" Connection " to " keep-alive " ,
" Cookie " to " filehosting= $filehosting " ,
)
val iframe = request . document . findTvMoviesIframe ( )
delay ( 10500 )
val request2 = session . get (
iframe ?: return null , referer = url , headers = headers
)
val iframe2 = request2 . document . findTvMoviesIframe ( )
delay ( 10500 )
val request3 = session . get (
iframe2 ?: return null , referer = iframe , headers = headers
)
val response = request3 . document
val videoLink = response . selectFirst ( " button.btn.btn--primary " ) ?. attr ( " onclick " )
?. substringAfter ( " location = ' " ) ?. substringBefore ( " '; " ) ?. let {
app . get (
it , referer = iframe2 , headers = headers
) . url
}
val size = response . selectFirst ( " ul.row--list li:contains(Filesize) span:last-child " )
?. text ( )
return Pair ( videoLink , size )
}
2022-12-29 13:19:16 +00:00
fun getDirectGdrive ( url : String ) : String {
2023-01-11 01:28:46 +00:00
return if ( url . contains ( " &export=download " ) ) {
2022-12-29 13:19:16 +00:00
url
2023-01-11 01:28:46 +00:00
} else {
" https://drive.google.com/uc?id= $ {
url . substringAfter ( " /d/ " ) . substringBefore ( " / " )
} & export = download "
2022-12-29 13:19:16 +00:00
}
}
2023-01-14 09:40:35 +00:00
suspend fun bypassOuo ( url : String ? ) : String ? {
2023-01-11 01:28:46 +00:00
var res = session . get ( url ?: return null )
2023-01-11 12:42:59 +00:00
run lit @ {
( 1. . 2 ) . forEach { _ ->
if ( res . headers [ " location " ] != null ) return @lit
val document = res . document
val nextUrl = document . select ( " form " ) . attr ( " action " )
val data = document . select ( " form input " ) . mapNotNull {
it . attr ( " name " ) to it . attr ( " value " )
} . toMap ( ) . toMutableMap ( )
val captchaKey =
document . select ( " script[src*=https://www.google.com/recaptcha/api.js?render=] " )
. attr ( " src " ) . substringAfter ( " render= " )
val token = getCaptchaToken ( url , captchaKey )
data [ " x-token " ] = token ?: " "
res = session . post (
nextUrl ,
data = data ,
headers = mapOf ( " content-type " to " application/x-www-form-urlencoded " ) ,
allowRedirects = false
)
}
2023-01-11 01:28:46 +00:00
}
return res . headers [ " location " ]
}
suspend fun fetchingKaizoku (
domain : String ,
postId : String ,
data : List < String > ,
ref : String
) : NiceResponse {
return app . post (
" $domain /wp-admin/admin-ajax.php " ,
data = mapOf (
" action " to " DDL " ,
" post_id " to postId ,
" div_id " to data . first ( ) ,
" tab_id " to data [ 1 ] ,
" num " to data [ 2 ] ,
" folder " to data . last ( )
) ,
headers = mapOf ( " X-Requested-With " to " XMLHttpRequest " ) ,
referer = ref
)
}
fun String . splitData ( ) : List < String > {
return this . substringAfterLast ( " DDL( " ) . substringBefore ( " ) " ) . split ( " , " )
. map { it . replace ( " ' " , " " ) . trim ( ) }
}
2023-01-02 17:15:40 +00:00
suspend fun bypassFdAds ( url : String ? ) : String ? {
2023-01-14 09:40:35 +00:00
val directUrl =
app . get ( url ?: return null , verify = false ) . document . select ( " a#link " ) . attr ( " href " )
. substringAfter ( " /go/ " )
. let { base64Decode ( it ) }
2023-01-03 16:42:50 +00:00
val doc = app . get ( directUrl , verify = false ) . document
val lastDoc = app . post (
doc . select ( " form#landing " ) . attr ( " action " ) ,
data = mapOf ( " go " to doc . select ( " form#landing input " ) . attr ( " value " ) ) ,
2022-12-07 15:06:48 +00:00
verify = false
) . document
2023-01-14 09:40:35 +00:00
val json = lastDoc . select ( " form#landing input[name=newwpsafelink] " ) . attr ( " value " )
. let { base64Decode ( it ) }
val finalJson =
tryParseJson < FDAds > ( json ) ?. linkr ?. substringAfter ( " redirect= " ) ?. let { base64Decode ( it ) }
2023-01-03 23:01:24 +00:00
return tryParseJson < Safelink > ( finalJson ) ?. safelink
2022-12-07 15:06:48 +00:00
}
2022-12-15 12:30:01 +00:00
suspend fun bypassHrefli ( url : String ) : String ? {
2023-01-14 09:40:35 +00:00
var res = app . get ( url . removePrefix ( " https://href.li/? " ) )
( 1. . 2 ) . forEach { _ ->
val document = res . document
val nextUrl = document . select ( " form " ) . attr ( " action " )
val data = document . select ( " form input " ) . mapNotNull {
it . attr ( " name " ) to it . attr ( " value " )
} . toMap ( )
res = app . post (
nextUrl ,
data = data ,
2022-12-15 12:30:01 +00:00
)
2023-01-14 09:40:35 +00:00
}
val script = res . document . selectFirst ( " script:containsData(verify_button) " ) ?. data ( )
val goUrl = script ?. substringAfter ( " \" href \" , \" " ) ?. substringBefore ( " \" ) " )
val cookies =
2022-12-15 12:30:01 +00:00
Regex ( " sumitbot_ \\ ('( \\ S+?)', \n |.?'( \\ S+?)', " ) . findAll ( script ?: return null ) . map {
2022-12-16 22:29:01 +00:00
it . groupValues [ 2 ]
2023-01-14 09:40:35 +00:00
} . toList ( ) . let {
mapOf ( it . first ( ) to it . last ( ) )
} . ifEmpty { return null }
2022-12-15 12:30:01 +00:00
return app . get (
2023-01-14 09:40:35 +00:00
goUrl ?: return null ,
2022-12-15 12:30:01 +00:00
cookies = cookies
) . document . selectFirst ( " meta[http-equiv=refresh] " ) ?. attr ( " content " ) ?. substringAfter ( " url= " )
}
2022-12-10 12:25:28 +00:00
suspend fun getTvMoviesServer ( url : String , season : Int ? , episode : Int ? ) : Pair < String , String ? > ? {
val req = app . get ( url )
2023-01-14 09:40:35 +00:00
if ( ! req . isSuccessful ) return null
2022-12-10 12:25:28 +00:00
val doc = req . document
return if ( season == null ) {
doc . select ( " table.wp-block-table tr:last-child td:first-child " ) . text ( ) to
doc . selectFirst ( " table.wp-block-table tr a " ) ?. attr ( " href " ) . let { link ->
app . get ( link ?: return null ) . document . select ( " div#text-url a " )
. mapIndexed { index , element ->
element . attr ( " href " ) to element . parent ( ) ?. textNodes ( ) ?. getOrNull ( index )
?. text ( )
} . filter { it . second ?. contains ( " Subtitles " , true ) == false }
. map { it . first }
} . lastOrNull ( )
} else {
doc . select ( " div.vc_tta-panels div#Season- $season table.wp-block-table tr:last-child td:first-child " )
. text ( ) to
doc . select ( " div.vc_tta-panels div#Season- $season table.wp-block-table tr a " )
. mapNotNull { ele ->
app . get ( ele . attr ( " href " ) ) . document . select ( " div#text-url a " )
. mapIndexed { index , element ->
element . attr ( " href " ) to element . parent ( ) ?. textNodes ( )
?. getOrNull ( index ) ?. text ( )
} . find { it . second ?. contains ( " Episode $episode " , true ) == true } ?. first
} . lastOrNull ( )
}
}
2022-12-02 13:00:44 +00:00
suspend fun getFilmxyCookies ( imdbId : String ? = null , season : Int ? = null ) : FilmxyCookies ? {
val url = if ( season == null ) {
2022-12-07 19:17:24 +00:00
" ${filmxyAPI} /movie/ $imdbId "
2022-12-02 13:00:44 +00:00
} else {
2022-12-07 19:17:24 +00:00
" ${filmxyAPI} /tv/ $imdbId "
2022-12-02 13:00:44 +00:00
}
2022-12-07 19:17:24 +00:00
val cookieUrl = " ${filmxyAPI} /wp-admin/admin-ajax.php "
2022-12-02 13:00:44 +00:00
val res = session . get (
url ,
headers = mapOf (
" Accept " to " text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8 "
) ,
)
if ( ! res . isSuccessful ) return FilmxyCookies ( )
val userNonce =
res . document . select ( " script " ) . find { it . data ( ) . contains ( " var userNonce " ) } ?. data ( ) ?. let {
Regex ( " var \\ suserNonce.*? \" ( \\ S+?) \" ; " ) . find ( it ) ?. groupValues ?. get ( 1 )
}
var phpsessid = session . baseClient . cookieJar . loadForRequest ( url . toHttpUrl ( ) )
. first { it . name == " PHPSESSID " } . value
session . post (
cookieUrl ,
data = mapOf (
" action " to " guest_login " ,
" nonce " to " $userNonce " ,
) ,
headers = mapOf (
" Cookie " to " PHPSESSID= $phpsessid ; G_ENABLED_IDPS=google " ,
" X-Requested-With " to " XMLHttpRequest " ,
)
)
val cookieJar = session . baseClient . cookieJar . loadForRequest ( cookieUrl . toHttpUrl ( ) )
phpsessid = cookieJar . first { it . name == " PHPSESSID " } . value
val wLog =
cookieJar . first { it . name == " wordpress_logged_in_8bf9d5433ac88cc9a3a396d6b154cd01 " } . value
val wSec = cookieJar . first { it . name == " wordpress_sec_8bf9d5433ac88cc9a3a396d6b154cd01 " } . value
return FilmxyCookies ( phpsessid , wLog , wSec )
}
2022-12-10 12:25:28 +00:00
fun Document . findTvMoviesIframe ( ) : String ? {
return this . selectFirst ( " script:containsData(var seconds) " ) ?. data ( ) ?. substringAfter ( " href=' " )
?. substringBefore ( " '> " )
}
2023-01-20 00:33:01 +00:00
suspend fun searchCrunchyrollAnimeId ( title : String ) : String ? {
val res = app . get ( " ${consumetCrunchyrollAPI} / $title " )
. parsedSafe < ConsumetSearchResponse > ( ) ?. results
return ( if ( res ?. size == 1 ) {
res . firstOrNull ( )
} else {
res ?. find {
( it . title ?. contains (
title ,
true
2023-02-06 04:55:42 +00:00
) == true || it . title . createSlug ( )
?. contains ( " ${title.createSlug()} " , true ) == true ) && it . type . equals ( " series " )
2023-01-20 00:33:01 +00:00
}
} ) ?. id
}
2023-01-19 02:51:04 +00:00
fun CrunchyrollDetails . findCrunchyrollId (
title : String ? ,
season : Int ? ,
episode : Int ? ,
epsTitle : String ?
) : List < Pair < String ? , String ? > ? > {
val sub = when ( title ) {
" One Piece " -> this . episodes ?. get ( " subbed13 " ) ?. matchingEpisode ( episode ) to " Raw "
" Hunter x Hunter " -> this . episodes ?. get ( " subbed5 " ) ?. matchingEpisode ( episode ) to " Raw "
else -> this . episodes ?. get ( " subbed $season " ) ?. matchingEpisode ( episode ) to " Raw "
}
val dub = this . episodes ?. get ( " English Dub $season " ) ?. matchingEpisode ( episode ) to " English Dub "
return listOf ( sub , dub )
}
fun List < HashMap < String , String > > ?. matchingEpisode ( episode : Int ? ) : String ? {
return this ?. find {
2023-02-01 04:58:36 +00:00
it [ " episode_number " ] == " $episode " || indexOf ( it ) . plus ( 1 ) == episode
2023-01-19 02:51:04 +00:00
} ?. get ( " id " )
}
2023-01-30 03:42:55 +00:00
fun getEpisodeSlug (
season : Int ? = null ,
episode : Int ? = null ,
) : Pair < String , String > {
return if ( season == null && episode == null ) {
" " to " "
} else {
( if ( season !! < 10 ) " 0 $season " else " $season " ) to ( if ( episode !! < 10 ) " 0 $episode " else " $episode " )
}
}
fun getTitleSlug ( title : String ? = null ) : Pair < String ? , String ? > {
2023-02-06 04:55:42 +00:00
return title . createSlug ( ) ?. replace ( " - " , " . " ) to title . createSlug ( ) ?. replace ( " - " , " " )
2023-01-30 03:42:55 +00:00
}
fun getIndexQuery (
title : String ? = null ,
year : Int ? = null ,
season : Int ? = null ,
episode : Int ? = null
) : String {
val ( seasonSlug , episodeSlug ) = getEpisodeSlug ( season , episode )
return if ( season == null ) {
" $title $year "
} else {
" $title S ${seasonSlug} E ${episodeSlug} "
}
}
fun searchIndex (
title : String ? = null ,
season : Int ? = null ,
episode : Int ? = null ,
year : Int ? = null ,
2023-02-01 03:10:02 +00:00
response : String
2023-01-30 03:42:55 +00:00
) : List < IndexMedia > ? {
val ( dotSlug , spaceSlug ) = getTitleSlug ( title )
val ( seasonSlug , episodeSlug ) = getEpisodeSlug ( season , episode )
val mimeType = arrayOf (
" video/x-matroska " ,
" video/mp4 " ,
" video/x-msvideo "
)
2023-02-02 05:17:58 +00:00
val files = tryParseJson < IndexSearch > ( response ) ?. data ?. files ?. filter { media ->
2023-01-30 03:42:55 +00:00
( if ( season == null ) {
media . name ?. contains ( " $year " ) == true
} else {
media . name ?. contains ( Regex ( " (?i)S ${seasonSlug} .?E ${episodeSlug} " ) ) == true
} ) && media . name ?. contains (
2023-02-01 17:27:45 +00:00
Regex ( " (?i)(2160p|1080p) " )
) == true && ( media . mimeType in mimeType ) && ( media . name . replace (
2023-01-30 03:42:55 +00:00
" - " ,
" . "
) . contains (
" $dotSlug " ,
true
) || media . name . replace (
" - " ,
" "
) . contains ( " $spaceSlug " , true ) )
2023-02-02 05:17:58 +00:00
} ?. distinctBy { it . name } ?. sortedByDescending { it . size ?. toLongOrNull ( ) ?: 0 } ?: return null
return files . let { file ->
listOfNotNull (
file . find { it . name ?. contains ( " 2160p " , true ) == true } ,
file . find { it . name ?. contains ( " 1080p " , true ) == true }
)
}
2023-01-30 03:42:55 +00:00
}
2023-01-29 03:29:15 +00:00
suspend fun getConfig ( ) : BaymoviesConfig {
val regex = """ const country = "(.*?)";
const downloadtime = " (.*?) " ;
var arrayofworkers = ( . * ) """ .toRegex()
val js = app . get (
" https://geolocation.zindex.eu.org/api.js " ,
referer = " $baymovies / " ,
) . text
val match = regex . find ( js ) ?: throw ErrorLoadingException ( )
val country = match . groupValues [ 1 ]
val downloadTime = match . groupValues [ 2 ]
val workers = tryParseJson < List < String > > ( match . groupValues [ 3 ] )
?: throw ErrorLoadingException ( )
return BaymoviesConfig ( country , downloadTime , workers )
}
2023-02-01 03:10:02 +00:00
// taken from https://github.com/821938089/cloudstream-extensions/blob/6e41697cbf816d2f57d9922d813c538e3192f708/PiousIndexProvider/src/main/kotlin/com/horis/cloudstreamplugins/PiousIndexProvider.kt#L175-L179
fun decodeIndexJson ( json : String ) : String {
val slug = json . reversed ( ) . substring ( 24 )
return base64Decode ( slug . substring ( 0 , slug . length - 20 ) )
}
2023-02-06 04:55:42 +00:00
fun String ?. createSlug ( ) : String ? {
2023-01-20 00:33:01 +00:00
return this ?. replace ( Regex ( " [!%:'?,]|( &) " ) , " " ) ?. replace ( " " , " - " ) ?. lowercase ( )
2022-12-02 13:00:44 +00:00
?. replace ( " -– - " , " - " )
}
fun getLanguage ( str : String ) : String {
return if ( str . contains ( " (in_ID) " ) ) " Indonesian " else str
}
2023-01-29 03:29:15 +00:00
fun bytesToGigaBytes ( number : Double ) : Double = number / 1024000000
2022-12-02 13:00:44 +00:00
fun getKisskhTitle ( str : String ? ) : String ? {
2023-02-07 14:44:14 +00:00
return str ?. replace ( Regex ( " [^a-zA-Z \\ d] " ) , " - " )
2022-12-02 13:00:44 +00:00
}
fun getQuality ( str : String ) : Int {
return when ( str ) {
" 360p " -> Qualities . P240 . value
" 480p " -> Qualities . P360 . value
" 720p " -> Qualities . P480 . value
" 1080p " -> Qualities . P720 . value
" 1080p Ultra " -> Qualities . P1080 . value
else -> getQualityFromName ( str )
}
}
2022-12-02 16:50:56 +00:00
fun getGMoviesQuality ( str : String ) : Int {
return when {
str . contains ( " 480P " , true ) -> Qualities . P480 . value
str . contains ( " 720P " , true ) -> Qualities . P720 . value
2022-12-12 13:24:46 +00:00
str . contains ( " 1080P " , true ) -> Qualities . P1080 . value
2022-12-02 16:50:56 +00:00
str . contains ( " 4K " , true ) -> Qualities . P2160 . value
else -> Qualities . Unknown . value
}
}
2022-12-12 13:24:46 +00:00
fun getFDoviesQuality ( str : String ) : String {
return when {
str . contains ( " 1080P " , true ) -> " 1080P "
str . contains ( " 4K " , true ) -> " 4K "
else -> " "
}
}
2023-01-03 23:01:24 +00:00
fun getVipLanguage ( str : String ) : String {
return when ( str ) {
" in_ID " -> " Indonesian "
" pt " -> " Portuguese "
else -> str . split ( " _ " ) . first ( ) . let {
SubtitleHelper . fromTwoLettersToLanguage ( it ) . toString ( )
}
}
}
2023-01-20 22:06:45 +00:00
fun getDbgoLanguage ( str : String ) : String {
return when ( str ) {
" Русский " -> " Russian "
" Українська " -> " Ukrainian "
else -> str
}
}
2023-01-30 03:42:55 +00:00
fun String . encodeUrl ( ) : String {
val url = URL ( this )
val uri = URI ( url . protocol , url . userInfo , url . host , url . port , url . path , url . query , url . ref )
return uri . toURL ( ) . toString ( )
}
2022-12-02 13:00:44 +00:00
fun getBaseUrl ( url : String ) : String {
return URI ( url ) . let {
" ${it.scheme} :// ${it.host} "
}
}
fun decryptStreamUrl ( data : String ) : String {
fun getTrash ( arr : List < String > , item : Int ) : List < String > {
val trash = ArrayList < List < String > > ( )
for ( i in 1. . item ) {
trash . add ( arr )
}
return trash . reduce { acc , list ->
val temp = ArrayList < String > ( )
acc . forEach { ac ->
list . forEach { li ->
temp . add ( ac . plus ( li ) )
}
}
return @reduce temp
}
}
val trashList = listOf ( " @ " , " # " , " ! " , " ^ " , " $ " )
val trashSet = getTrash ( trashList , 2 ) + getTrash ( trashList , 3 )
var trashString = data . replace ( " #2 " , " " ) . split ( " //_// " ) . joinToString ( " " )
trashSet . forEach {
val temp = base64Encode ( it . toByteArray ( ) )
trashString = trashString . replace ( temp , " " )
}
return base64Decode ( trashString )
}
fun fixUrl ( url : String , domain : String ) : String {
if ( url . startsWith ( " http " ) ) {
return url
}
if ( url . isEmpty ( ) ) {
return " "
}
val startsWithNoHttp = url . startsWith ( " // " )
if ( startsWithNoHttp ) {
return " https: $url "
} else {
if ( url . startsWith ( '/' ) ) {
return domain + url
}
return " $domain / $url "
}
}
suspend fun loadLinksWithWebView (
url : String ,
callback : ( ExtractorLink ) -> Unit
) {
val foundVideo = WebViewResolver (
Regex ( """ \.m3u8|i7njdjvszykaieynzsogaysdgb0hm8u1mzubmush4maopa4wde\.com """ )
) . resolveUsingWebView (
requestCreator (
" GET " , url , referer = " https://olgply.com/ "
)
) . first ?: return
callback . invoke (
ExtractorLink (
" Olgply " ,
" Olgply " ,
foundVideo . url . toString ( ) ,
" " ,
Qualities . P1080 . value ,
true
)
)
2023-02-02 08:28:22 +00:00
}
fun Int . toRomanNumeral ( ) : String = Symbol . closestBelow ( this )
. let { symbol ->
if ( symbol != null ) {
" $symbol ${(this - symbol.decimalValue).toRomanNumeral()} "
} else {
" "
}
}
private enum class Symbol ( val decimalValue : Int ) {
I ( 1 ) ,
IV ( 4 ) ,
V ( 5 ) ,
IX ( 9 ) ,
X ( 10 ) ;
companion object {
fun closestBelow ( value : Int ) =
values ( )
. sortedByDescending { it . decimalValue }
. firstOrNull { value >= it . decimalValue }
}
2023-02-04 10:58:06 +00:00
}
// code found on https://stackoverflow.com/a/63701411
/ * *
* Conforming with CryptoJS AES method
* /
// see https://gist.github.com/thackerronak/554c985c3001b16810af5fc0eb5c358f
@Suppress ( " unused " , " FunctionName " , " SameParameterValue " )
object CryptoAES {
private const val KEY _SIZE = 256
private const val IV _SIZE = 128
private const val HASH _CIPHER = " AES/CBC/PKCS5Padding "
private const val AES = " AES "
private const val KDF _DIGEST = " MD5 "
// Seriously crypto-js, what's wrong with you?
private const val APPEND = " Salted__ "
/ * *
* Encrypt
* @param password passphrase
* @param plainText plain string
* /
fun encrypt ( password : String , plainText : String ) : String {
val saltBytes = generateSalt ( 8 )
val key = ByteArray ( KEY _SIZE / 8 )
val iv = ByteArray ( IV _SIZE / 8 )
EvpKDF ( password . toByteArray ( ) , KEY _SIZE , IV _SIZE , saltBytes , key , iv )
val keyS = SecretKeySpec ( key , AES )
val cipher = Cipher . getInstance ( HASH _CIPHER )
val ivSpec = IvParameterSpec ( iv )
cipher . init ( Cipher . ENCRYPT _MODE , keyS , ivSpec )
val cipherText = cipher . doFinal ( plainText . toByteArray ( ) )
// Thanks kientux for this: https://gist.github.com/kientux/bb48259c6f2133e628ad
// Create CryptoJS-like encrypted!
val sBytes = APPEND . toByteArray ( )
val b = ByteArray ( sBytes . size + saltBytes . size + cipherText . size )
System . arraycopy ( sBytes , 0 , b , 0 , sBytes . size )
System . arraycopy ( saltBytes , 0 , b , sBytes . size , saltBytes . size )
System . arraycopy ( cipherText , 0 , b , sBytes . size + saltBytes . size , cipherText . size )
val bEncode = Base64 . encode ( b , Base64 . NO _WRAP )
return String ( bEncode )
}
/ * *
* Decrypt
* Thanks Artjom B . for this : http : //stackoverflow.com/a/29152379/4405051
* @param password passphrase
* @param cipherText encrypted string
* /
fun decrypt ( password : String , cipherText : String ) : String {
val ctBytes = Base64 . decode ( cipherText . toByteArray ( ) , Base64 . NO _WRAP )
val saltBytes = Arrays . copyOfRange ( ctBytes , 8 , 16 )
val cipherTextBytes = Arrays . copyOfRange ( ctBytes , 16 , ctBytes . size )
val key = ByteArray ( KEY _SIZE / 8 )
val iv = ByteArray ( IV _SIZE / 8 )
EvpKDF ( password . toByteArray ( ) , KEY _SIZE , IV _SIZE , saltBytes , key , iv )
val cipher = Cipher . getInstance ( HASH _CIPHER )
val keyS = SecretKeySpec ( key , AES )
cipher . init ( Cipher . DECRYPT _MODE , keyS , IvParameterSpec ( iv ) )
val plainText = cipher . doFinal ( cipherTextBytes )
return String ( plainText )
}
private fun EvpKDF (
password : ByteArray ,
keySize : Int ,
ivSize : Int ,
salt : ByteArray ,
resultKey : ByteArray ,
resultIv : ByteArray
) : ByteArray {
return EvpKDF ( password , keySize , ivSize , salt , 1 , KDF _DIGEST , resultKey , resultIv )
}
@Suppress ( " NAME_SHADOWING " )
private fun EvpKDF (
password : ByteArray ,
keySize : Int ,
ivSize : Int ,
salt : ByteArray ,
iterations : Int ,
hashAlgorithm : String ,
resultKey : ByteArray ,
resultIv : ByteArray
) : ByteArray {
val keySize = keySize / 32
val ivSize = ivSize / 32
val targetKeySize = keySize + ivSize
val derivedBytes = ByteArray ( targetKeySize * 4 )
var numberOfDerivedWords = 0
var block : ByteArray ? = null
val hash = MessageDigest . getInstance ( hashAlgorithm )
while ( numberOfDerivedWords < targetKeySize ) {
if ( block != null ) {
hash . update ( block )
}
hash . update ( password )
block = hash . digest ( salt )
hash . reset ( )
// Iterations
for ( i in 1 until iterations ) {
block = hash . digest ( block !! )
hash . reset ( )
}
System . arraycopy (
block !! , 0 , derivedBytes , numberOfDerivedWords * 4 ,
min ( block . size , ( targetKeySize - numberOfDerivedWords ) * 4 )
)
numberOfDerivedWords += block . size / 4
}
System . arraycopy ( derivedBytes , 0 , resultKey , 0 , keySize * 4 )
System . arraycopy ( derivedBytes , keySize * 4 , resultIv , 0 , ivSize * 4 )
return derivedBytes // key + iv
}
private fun generateSalt ( length : Int ) : ByteArray {
return ByteArray ( length ) . apply {
SecureRandom ( ) . nextBytes ( this )
}
}
2022-12-02 13:00:44 +00:00
}