Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ qrcodeKotlin = "4.5.0"
rhino = { strictly = "1.8.1" } # Requires minSdk 26 or later beginning at version 1.9.0
safefile = "0.0.8"
shimmer = "0.5.0"
tmdbJava = "2.13.0"
torrentserver = "7861970"
tvprovider = "1.1.0"
video = "1.0.0"
Expand Down Expand Up @@ -110,7 +109,6 @@ qrcode-kotlin = { module = "io.github.g0dkar:qrcode-kotlin", version.ref = "qrco
rhino = { module = "org.mozilla:rhino", version.ref = "rhino" }
safefile = { module = "com.github.LagradOst:SafeFile", version.ref = "safefile" }
shimmer = { module = "com.facebook.shimmer:shimmer", version.ref = "shimmer" }
tmdb-java = { module = "com.uwetrottmann.tmdb2:tmdb-java", version.ref = "tmdbJava" }
torrentserver = { module = "com.github.recloudstream:torrentserver", version.ref = "torrentserver" }
tvprovider = { module = "androidx.tvprovider:tvprovider", version.ref = "tvprovider" }
video = { module = "com.google.android.mediahome:video", version.ref = "video" }
Expand Down
1 change: 0 additions & 1 deletion library/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ kotlin {
implementation(libs.jsoup) // HTML Parser
implementation(libs.rhino) // Run JavaScript
implementation(libs.newpipeextractor)
implementation(libs.tmdb.java) // TMDB API v3 Wrapper Made with RetroFit
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package com.lagradost.cloudstream3.extractors

import com.google.gson.Gson
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.newSubtitleFile
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import java.net.URI



class Geodailymotion : Dailymotion() {
override val name = "GeoDailymotion"
override val mainUrl = "https://geo.dailymotion.com"
Expand All @@ -35,8 +33,7 @@ open class Dailymotion : ExtractorApi() {
val metaDataUrl = "$baseUrl/player/metadata/video/$id"

val response = app.get(metaDataUrl, referer = embedUrl).text
val gson = Gson()
val meta = gson.fromJson(response, MetaData::class.java)
val meta = parseJson<MetaData>(response)

meta.qualities?.get("auto")?.forEach { quality ->
val videoUrl = quality.url
Expand All @@ -57,7 +54,6 @@ open class Dailymotion : ExtractorApi() {
}
}


private fun getEmbedUrl(url: String): String? {
if (url.contains("/embed/") || url.contains("/video/")) return url
if (url.contains("geo.dailymotion.com")) {
Expand All @@ -67,7 +63,6 @@ open class Dailymotion : ExtractorApi() {
return null
}


private fun getVideoId(url: String): String? {
val path = URI(url).path
val id = path.substringAfter("/video/")
Expand All @@ -82,7 +77,6 @@ open class Dailymotion : ExtractorApi() {
return generateM3u8(name, streamLink, "").forEach(callback)
}


data class MetaData(
val qualities: Map<String, List<Quality>>?,
val subtitles: SubtitlesWrapper?
Expand All @@ -102,5 +96,4 @@ open class Dailymotion : ExtractorApi() {
val label: String,
val urls: List<String>
)

}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
package com.lagradost.cloudstream3.extractors

import com.google.gson.JsonParser
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.api.Log
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor
import java.net.URI

class Techinmind: GDMirrorbot() {
class Techinmind : GDMirrorbot() {
override var name = "Techinmind Cloud AIO"
override var mainUrl = "https://stream.techinmind.space"
override var requiresReferer = true
Expand All @@ -21,6 +22,20 @@ open class GDMirrorbot : ExtractorApi() {
override var mainUrl = "https://gdmirrorbot.nl"
override val requiresReferer = true

private data class EmbedData(
@JsonProperty("data") val data: List<FileSlug>? = null,
)

private data class FileSlug(
@JsonProperty("fileslug") val fileslug: String? = null,
)

private data class EmbedHelper(
@JsonProperty("siteUrls") val siteUrls: Map<String, String>? = null,
@JsonProperty("siteFriendlyNames") val siteFriendlyNames: Map<String, String>? = null,
@JsonProperty("mresult") val mresult: Any? = null,
)

override suspend fun getUrl(
url: String,
referer: String?,
Expand Down Expand Up @@ -48,15 +63,9 @@ open class GDMirrorbot : ExtractorApi() {
pageText = app.get(apiUrl).text
}

val jsonElement = JsonParser.parseString(pageText)
if (!jsonElement.isJsonObject) return
val jsonObject = jsonElement.asJsonObject

val embedData = tryParseJson<EmbedData>(pageText)
val embedId = url.substringAfterLast("/")
val sidValue = jsonObject["data"]?.asJsonArray
?.takeIf { it.size() > 0 }
?.get(0)?.asJsonObject
?.get("fileslug")?.asString
val sidValue = embedData?.data?.firstOrNull()?.fileslug
?.takeIf { it.isNotBlank() } ?: embedId

Pair(sidValue, hostUrl)
Expand All @@ -65,34 +74,40 @@ open class GDMirrorbot : ExtractorApi() {
val postData = mapOf("sid" to sid)
val responseText = app.post("$host/embedhelper.php", data = postData).text

val rootElement = JsonParser.parseString(responseText)
if (!rootElement.isJsonObject) return
val root = rootElement.asJsonObject

val siteUrls = root["siteUrls"]?.asJsonObject ?: return
val siteFriendlyNames = root["siteFriendlyNames"]?.asJsonObject

val decodedMresult = when {
root["mresult"]?.isJsonObject == true -> root["mresult"]!!.asJsonObject
root["mresult"]?.isJsonPrimitive == true -> try {
base64Decode(root["mresult"]!!.asString)
.let { JsonParser.parseString(it).asJsonObject }
} catch (e: Exception) {
Log.e("GDMirrorbot", "Failed to decode mresult: $e")
return
val root = tryParseJson<EmbedHelper>(responseText) ?: return
val siteUrls = root.siteUrls ?: return
val siteFriendlyNames = root.siteFriendlyNames

// mresult can arrive as a JSON object or a base64-encoded string
val mresult: Map<String, String>? = run {
val raw = responseText
.substringAfter("\"mresult\":")
.trimStart()
when {
raw.startsWith("\"") -> {
// base64-encoded string
tryParseJson<Map<String, String>>(
try { base64Decode(raw.trim('"')) } catch (_: Exception) { return }
)
}
raw.startsWith("{") -> tryParseJson<Map<String, String>>(
raw.substringBefore("\n}").substringBefore(",\n\"").let { "{$it}" }
.let { responseText.substringAfter("\"mresult\":").trimStart() }
)
else -> null
}
else -> return
}
if (mresult == null) return

siteUrls.keySet().intersect(decodedMresult.keySet()).forEach { key ->
val base = siteUrls[key]?.asString?.trimEnd('/') ?: return@forEach
val path = decodedMresult[key]?.asString?.trimStart('/') ?: return@forEach
siteUrls.keys.intersect(mresult.keys).forEach { key ->
val base = siteUrls[key]?.trimEnd('/') ?: return@forEach
val path = mresult[key]?.trimStart('/') ?: return@forEach
val fullUrl = "$base/$path"
val friendlyName = siteFriendlyNames?.get(key)?.asString ?: key
val friendlyName = siteFriendlyNames?.get(key) ?: key

try {
when (friendlyName) {
"StreamHG","EarnVids" -> VidHidePro().getUrl(fullUrl, referer, subtitleCallback, callback)
"StreamHG", "EarnVids" -> VidHidePro().getUrl(fullUrl, referer, subtitleCallback, callback)
"RpmShare", "UpnShare", "StreamP2p" -> VidStack().getUrl(fullUrl, referer, subtitleCallback, callback)
else -> loadExtractor(fullUrl, referer ?: mainUrl, subtitleCallback, callback)
}
Expand All @@ -106,4 +121,3 @@ open class GDMirrorbot : ExtractorApi() {
return URI(url).let { "${it.scheme}://${it.host}" }
}
}

Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package com.lagradost.cloudstream3.extractors

import com.google.gson.JsonObject
import com.google.gson.JsonParser
import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.base64Decode
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.INFER_TYPE
Expand Down Expand Up @@ -66,14 +65,17 @@ open class Voe : ExtractorApi() {
if (redirectUrl != null) {
res = app.get(redirectUrl, referer = referer)
}
val encodedString = res.document.selectFirst("script[type=application/json]")?.data()?.trim()?.substringAfter("[\"")?.substringBeforeLast("\"]")
val encodedString = res.document.selectFirst("script[type=application/json]")
?.data()?.trim()
?.substringAfter("[\"")
?.substringBeforeLast("\"]")
if (encodedString == null) {
println("encoded string not found.")
return
}
val decryptedJson = decryptF7(encodedString)
val m3u8 = decryptedJson.get("source")?.asString
val mp4 = decryptedJson.get("direct_access_url")?.asString
val m3u8 = decryptedJson?.source
val mp4 = decryptedJson?.directAccessUrl

if (m3u8 != null) {
M3u8Helper.generateM3u8(
Expand All @@ -83,8 +85,7 @@ open class Voe : ExtractorApi() {
headers = mapOf("Origin" to "$mainUrl/")
).forEach(callback)
}
if (mp4!=null)
{
if (mp4 != null) {
callback.invoke(
newExtractorLink(
source = "$name MP4",
Expand All @@ -99,7 +100,12 @@ open class Voe : ExtractorApi() {
}
}

private fun decryptF7(p8: String): JsonObject {
private data class VoeDecrypted(
val source: String? = null,
val directAccessUrl: String? = null,
)

private fun decryptF7(p8: String): VoeDecrypted? {
return try {
val vF = rot13(p8)
val vF2 = replacePatterns(vF)
Expand All @@ -108,11 +114,10 @@ open class Voe : ExtractorApi() {
val vF5 = charShift(vF4, 3)
val vF6 = reverse(vF5)
val vAtob = base64Decode(vF6)

JsonParser.parseString(vAtob).asJsonObject
tryParseJson<VoeDecrypted>(vAtob)
} catch (e: Exception) {
println("Decryption error: ${e.message}")
JsonObject()
null
}
}

Expand Down Expand Up @@ -140,5 +145,4 @@ open class Voe : ExtractorApi() {
}

private fun reverse(input: String): String = input.reversed()

}
Loading