forked from recloudstream/cloudstream
copy paste extractors from shiro
This commit is contained in:
parent
d0fbf5a782
commit
68605fb563
11 changed files with 641 additions and 5 deletions
124
.idea/uiDesigner.xml
Normal file
124
.idea/uiDesigner.xml
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Palette2">
|
||||||
|
<group name="Swing">
|
||||||
|
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Button" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="RadioButton" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="CheckBox" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
|
||||||
|
<initial-values>
|
||||||
|
<property name="text" value="Label" />
|
||||||
|
</initial-values>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
|
||||||
|
<preferred-size width="150" height="-1" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
|
||||||
|
<preferred-size width="150" height="50" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
|
||||||
|
<preferred-size width="200" height="200" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
|
||||||
|
<preferred-size width="-1" height="20" />
|
||||||
|
</default-constraints>
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
|
||||||
|
</item>
|
||||||
|
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
|
||||||
|
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
|
||||||
|
</item>
|
||||||
|
</group>
|
||||||
|
</component>
|
||||||
|
</project>
|
|
@ -73,11 +73,6 @@ data class Link(
|
||||||
val referer: String?,
|
val referer: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
interface LinkExtractor {
|
|
||||||
val linkStart: String // THIS IS USED TO AUTO-EXTRACT LINKS FROM URL
|
|
||||||
fun extract(link: String, referer: String): ArrayList<Link>
|
|
||||||
}
|
|
||||||
|
|
||||||
enum class ShowStatus {
|
enum class ShowStatus {
|
||||||
Completed,
|
Completed,
|
||||||
Ongoing,
|
Ongoing,
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.MixDrop
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.Mp4Upload
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.Shiro
|
||||||
|
import com.lagradost.cloudstream3.cloudstream3.extractors.StreamTape
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.XStreamCdn
|
||||||
|
|
||||||
|
data class ExtractorLink(
|
||||||
|
val name: String,
|
||||||
|
val url: String,
|
||||||
|
val referer: String,
|
||||||
|
val quality: Int,
|
||||||
|
val isM3u8: Boolean = false,
|
||||||
|
)
|
||||||
|
|
||||||
|
enum class Qualities(var value: Int) {
|
||||||
|
Unknown(0),
|
||||||
|
SD(-1), // 360p - 480p
|
||||||
|
HD(1), // 720p
|
||||||
|
FullHd(2), // 1080p
|
||||||
|
UHD(3) // 4k
|
||||||
|
}
|
||||||
|
|
||||||
|
private val packedRegex = Regex("""eval\(function\(p,a,c,k,e,.*\)\)""")
|
||||||
|
fun getPacked(string: String): String? {
|
||||||
|
return packedRegex.find(string)?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getAndUnpack(string: String): String? {
|
||||||
|
val packedText = getPacked(string)
|
||||||
|
return JsUnpacker(packedText).unpack()
|
||||||
|
}
|
||||||
|
|
||||||
|
val APIS: Array<ExtractorApi> = arrayOf(
|
||||||
|
//AllProvider(),
|
||||||
|
Shiro(),
|
||||||
|
Mp4Upload(),
|
||||||
|
StreamTape(),
|
||||||
|
MixDrop(),
|
||||||
|
XStreamCdn()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun httpsify(url: String): String {
|
||||||
|
return if (url.startsWith("//")) "https:$url" else url
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class ExtractorApi {
|
||||||
|
abstract val name: String
|
||||||
|
abstract val mainUrl: String
|
||||||
|
abstract val requiresReferer: Boolean
|
||||||
|
|
||||||
|
abstract fun getUrl(url: String, referer: String? = null): List<ExtractorLink>?
|
||||||
|
|
||||||
|
open fun getExtractorUrl(id: String): String{
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
}
|
125
app/src/main/java/com/lagradost/cloudstream3/utils/JsUnpacker.kt
Normal file
125
app/src/main/java/com/lagradost/cloudstream3/utils/JsUnpacker.kt
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.lang.StringBuilder
|
||||||
|
import java.util.HashMap
|
||||||
|
import java.util.regex.Pattern
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
|
// https://github.com/cylonu87/JsUnpacker
|
||||||
|
class JsUnpacker(packedJS: String?) {
|
||||||
|
private var packedJS: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects whether the javascript is P.A.C.K.E.R. coded.
|
||||||
|
*
|
||||||
|
* @return true if it's P.A.C.K.E.R. coded.
|
||||||
|
*/
|
||||||
|
fun detect(): Boolean {
|
||||||
|
val js = packedJS!!.replace(" ", "")
|
||||||
|
val p = Pattern.compile("eval\\(function\\(p,a,c,k,e,[rd]")
|
||||||
|
val m = p.matcher(js)
|
||||||
|
return m.find()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unpack the javascript
|
||||||
|
*
|
||||||
|
* @return the javascript unpacked or null.
|
||||||
|
*/
|
||||||
|
fun unpack(): String? {
|
||||||
|
val js = packedJS
|
||||||
|
try {
|
||||||
|
var p =
|
||||||
|
Pattern.compile("""\}\s*\('(.*)',\s*(.*?),\s*(\d+),\s*'(.*?)'\.split\('\|'\)""", Pattern.DOTALL)
|
||||||
|
var m = p.matcher(js)
|
||||||
|
if (m.find() && m.groupCount() == 4) {
|
||||||
|
val payload = m.group(1).replace("\\'", "'")
|
||||||
|
val radixStr = m.group(2)
|
||||||
|
val countStr = m.group(3)
|
||||||
|
val symtab = m.group(4).split("\\|".toRegex()).toTypedArray()
|
||||||
|
var radix = 36
|
||||||
|
var count = 0
|
||||||
|
try {
|
||||||
|
radix = radixStr.toInt()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
count = countStr.toInt()
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
if (symtab.size != count) {
|
||||||
|
throw Exception("Unknown p.a.c.k.e.r. encoding")
|
||||||
|
}
|
||||||
|
val unbase = Unbase(radix)
|
||||||
|
p = Pattern.compile("\\b\\w+\\b")
|
||||||
|
m = p.matcher(payload)
|
||||||
|
val decoded = StringBuilder(payload)
|
||||||
|
var replaceOffset = 0
|
||||||
|
while (m.find()) {
|
||||||
|
val word = m.group(0)
|
||||||
|
val x = unbase.unbase(word)
|
||||||
|
var value: String? = null
|
||||||
|
if (x < symtab.size) {
|
||||||
|
value = symtab[x]
|
||||||
|
}
|
||||||
|
if (value != null && value.isNotEmpty()) {
|
||||||
|
decoded.replace(m.start() + replaceOffset, m.end() + replaceOffset, value)
|
||||||
|
replaceOffset += value.length - word.length
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return decoded.toString()
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
private inner class Unbase(private val radix: Int) {
|
||||||
|
private val ALPHABET_62 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
|
private val ALPHABET_95 =
|
||||||
|
" !\"#$%&\\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
|
||||||
|
private var alphabet: String? = null
|
||||||
|
private var dictionary: HashMap<String, Int>? = null
|
||||||
|
fun unbase(str: String): Int {
|
||||||
|
var ret = 0
|
||||||
|
if (alphabet == null) {
|
||||||
|
ret = str.toInt(radix)
|
||||||
|
} else {
|
||||||
|
val tmp = StringBuilder(str).reverse().toString()
|
||||||
|
for (i in tmp.indices) {
|
||||||
|
ret += (radix.toDouble().pow(i.toDouble()) * dictionary!![tmp.substring(i, i + 1)]!!).toInt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
init {
|
||||||
|
if (radix > 36) {
|
||||||
|
when {
|
||||||
|
radix < 62 -> {
|
||||||
|
alphabet = ALPHABET_62.substring(0, radix)
|
||||||
|
}
|
||||||
|
radix in 63..94 -> {
|
||||||
|
alphabet = ALPHABET_95.substring(0, radix)
|
||||||
|
}
|
||||||
|
radix == 62 -> {
|
||||||
|
alphabet = ALPHABET_62
|
||||||
|
}
|
||||||
|
radix == 95 -> {
|
||||||
|
alphabet = ALPHABET_95
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dictionary = HashMap(95)
|
||||||
|
for (i in 0 until alphabet!!.length) {
|
||||||
|
dictionary!![alphabet!!.substring(i, i + 1)] = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @param packedJS javascript P.A.C.K.E.R. coded.
|
||||||
|
*/
|
||||||
|
init {
|
||||||
|
this.packedJS = packedJS
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
|
||||||
|
class MixDrop : ExtractorApi() {
|
||||||
|
override val name: String = "MixDrop"
|
||||||
|
override val mainUrl: String = "https://mixdrop.co"
|
||||||
|
private val srcRegex = Regex("""wurl.*?=.*?"(.*?)";""")
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
override fun getExtractorUrl(id: String): String {
|
||||||
|
return "$mainUrl/e/$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
try {
|
||||||
|
with(khttp.get(url)) {
|
||||||
|
getAndUnpack(this.text)?.let { unpackedText ->
|
||||||
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
|
return listOf(
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
httpsify(link),
|
||||||
|
url,
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.*
|
||||||
|
|
||||||
|
class Mp4Upload : ExtractorApi() {
|
||||||
|
override val name: String = "Mp4Upload"
|
||||||
|
override val mainUrl: String = "https://www.mp4upload.com"
|
||||||
|
private val srcRegex = Regex("""player\.src\("(.*?)"""")
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
try {
|
||||||
|
with(khttp.get(url)) {
|
||||||
|
getAndUnpack(this.text)?.let { unpackedText ->
|
||||||
|
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||||
|
return listOf(
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
link,
|
||||||
|
url,
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,69 @@
|
||||||
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
|
||||||
|
class MultiQuality : ExtractorApi() {
|
||||||
|
override val name: String = "MultiQuality"
|
||||||
|
override val mainUrl: String = "https://gogo-play.net"
|
||||||
|
private val sourceRegex = Regex("""file:\s*'(.*?)',label:\s*'(.*?)'""")
|
||||||
|
private val m3u8Regex = Regex(""".*?(\d*).m3u8""")
|
||||||
|
private val urlRegex = Regex("""(.*?)([^/]+$)""")
|
||||||
|
override val requiresReferer = false
|
||||||
|
|
||||||
|
override fun getExtractorUrl(id: String): String {
|
||||||
|
return "$mainUrl/loadserver.php?id=$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getQuality(string: String): Int {
|
||||||
|
return when (string) {
|
||||||
|
"360" -> Qualities.SD.value
|
||||||
|
"480" -> Qualities.SD.value
|
||||||
|
"720" -> Qualities.HD.value
|
||||||
|
"1080" -> Qualities.FullHd.value
|
||||||
|
else -> Qualities.Unknown.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
try {
|
||||||
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
|
with(khttp.get(url)) {
|
||||||
|
sourceRegex.findAll(this.text).forEach { sourceMatch ->
|
||||||
|
val extractedUrl = sourceMatch.groupValues[1]
|
||||||
|
// Trusting this isn't mp4, may fuck up stuff
|
||||||
|
if (extractedUrl.endsWith(".m3u8")) {
|
||||||
|
with(khttp.get(extractedUrl)) {
|
||||||
|
m3u8Regex.findAll(this.text).forEach { match ->
|
||||||
|
extractedLinksList.add(
|
||||||
|
ExtractorLink(
|
||||||
|
"$name ${match.groupValues[1]}p",
|
||||||
|
urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0],
|
||||||
|
url,
|
||||||
|
getQuality(match.groupValues[1]),
|
||||||
|
isM3u8 = true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
} else if (extractedUrl.endsWith(".mp4")) {
|
||||||
|
extractedLinksList.add(
|
||||||
|
ExtractorLink(
|
||||||
|
"$name ${sourceMatch.groupValues[2]}",
|
||||||
|
extractedUrl,
|
||||||
|
url.replace(" ", "%20"),
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractedLinksList
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
|
class Shiro : ExtractorApi() {
|
||||||
|
override val name: String = "Shiro"
|
||||||
|
override val mainUrl: String = "https://cherry.subsplea.se"
|
||||||
|
override val requiresReferer = false
|
||||||
|
|
||||||
|
override fun getExtractorUrl(id: String): String {
|
||||||
|
return "$mainUrl/$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
val headers = mapOf("Referer" to "https://shiro.is/")
|
||||||
|
val res = khttp.get(url, headers = headers).text
|
||||||
|
Jsoup.parse(res).select("source").firstOrNull()?.attr("src")?.replace("&", "?")?.let {
|
||||||
|
return listOf(
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
it.replace(" ", "%20"),
|
||||||
|
"https://cherry.subsplea.se/",
|
||||||
|
// UHD to give top priority
|
||||||
|
Qualities.UHD.value
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
package com.lagradost.cloudstream3.cloudstream3.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
|
||||||
|
class StreamTape : ExtractorApi() {
|
||||||
|
override val name: String = "StreamTape"
|
||||||
|
override val mainUrl: String = "https://streamtape.com"
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
// Because they add concatenation to fuck up scrapers
|
||||||
|
private val linkRegex =
|
||||||
|
Regex("""(i(|" \+ ')d(|" \+ ')=.*?&(|" \+ ')e(|" \+ ')x(|" \+ ')p(|" \+ ')i(|" \+ ')r(|" \+ ')e(|" \+ ')s(|" \+ ')=.*?&(|" \+ ')i(|" \+ ')p(|" \+ ')=.*?&(|" \+ ')t(|" \+ ')o(|" \+ ')k(|" \+ ')e(|" \+ ')n(|" \+ ')=.*)'""")
|
||||||
|
|
||||||
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
try {
|
||||||
|
with(khttp.get(url)) {
|
||||||
|
linkRegex.find(this.text)?.let {
|
||||||
|
val extractedUrl = "https://streamtape.com/get_video?${it.groupValues[1]}".replace("""" + '""", "")
|
||||||
|
return listOf(
|
||||||
|
ExtractorLink(
|
||||||
|
name,
|
||||||
|
extractedUrl,
|
||||||
|
url,
|
||||||
|
Qualities.Unknown.value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.APIS
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.MultiQuality
|
||||||
|
import com.lagradost.cloudstream3.utils.extractors.Shiro
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
|
||||||
|
class Vidstream {
|
||||||
|
val name: String = "Vidstream"
|
||||||
|
private val mainUrl: String = "https://gogo-stream.com"
|
||||||
|
|
||||||
|
private fun getExtractorUrl(id: String): String {
|
||||||
|
return "$mainUrl/streaming.php?id=$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
||||||
|
fun getUrl(id: String, isCasting: Boolean = false): List<ExtractorLink> {
|
||||||
|
try {
|
||||||
|
val url = getExtractorUrl(id)
|
||||||
|
with(khttp.get(url)) {
|
||||||
|
val document = Jsoup.parse(this.text)
|
||||||
|
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||||
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
|
|
||||||
|
// --- Shiro ---
|
||||||
|
val shiroUrl = Shiro().getExtractorUrl(id)
|
||||||
|
val shiroSource = Shiro().getUrl(shiroUrl)
|
||||||
|
shiroSource?.forEach { extractedLinksList.add(it) }
|
||||||
|
// --- MultiQuality ---
|
||||||
|
val multiQualityUrl = MultiQuality().getExtractorUrl(id)
|
||||||
|
val multiQualitySource = MultiQuality().getUrl(multiQualityUrl)
|
||||||
|
multiQualitySource?.forEach { extractedLinksList.add(it) }
|
||||||
|
// --------------------
|
||||||
|
|
||||||
|
// All vidstream links passed to extractors
|
||||||
|
primaryLinks.forEach { element ->
|
||||||
|
val link = element.attr("data-video")
|
||||||
|
//val name = element.text()
|
||||||
|
|
||||||
|
// Matches vidstream links with extractors
|
||||||
|
APIS.filter { !it.requiresReferer || !isCasting}.forEach { api ->
|
||||||
|
if (link.startsWith(api.mainUrl)) {
|
||||||
|
val extractedLinks = api.getUrl(link, url)
|
||||||
|
if (extractedLinks?.isNotEmpty() == true) {
|
||||||
|
extractedLinks.forEach {
|
||||||
|
extractedLinksList.add(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractedLinksList
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return listOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
package com.lagradost.cloudstream3.utils.extractors
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.fasterxml.jackson.module.kotlin.readValue
|
||||||
|
import com.lagradost.cloudstream3.mapper
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||||
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
|
import com.lagradost.cloudstream3.utils.Qualities
|
||||||
|
|
||||||
|
class XStreamCdn : ExtractorApi() {
|
||||||
|
override val name: String = "XStreamCdn"
|
||||||
|
override val mainUrl: String = "https://fcdn.stream"
|
||||||
|
override val requiresReferer = true
|
||||||
|
|
||||||
|
private data class ResponseData(
|
||||||
|
@JsonProperty("file") val file: String,
|
||||||
|
@JsonProperty("label") val label: String,
|
||||||
|
//val type: String // Mp4
|
||||||
|
)
|
||||||
|
|
||||||
|
private data class ResponseJson(
|
||||||
|
@JsonProperty("success") val success: Boolean,
|
||||||
|
@JsonProperty("data") val data: List<ResponseData>?
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun getExtractorUrl(id: String): String {
|
||||||
|
return "$mainUrl/api/source/$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getQuality(string: String): Int {
|
||||||
|
return when (string) {
|
||||||
|
"360p" -> Qualities.SD.value
|
||||||
|
"480p" -> Qualities.SD.value
|
||||||
|
"720p" -> Qualities.HD.value
|
||||||
|
"1080p" -> Qualities.FullHd.value
|
||||||
|
else -> Qualities.Unknown.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||||
|
try {
|
||||||
|
val headers = mapOf(
|
||||||
|
"Referer" to url,
|
||||||
|
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0",
|
||||||
|
)
|
||||||
|
val newUrl = url.replace("$mainUrl/v/", "$mainUrl/api/source/")
|
||||||
|
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||||
|
with(khttp.post(newUrl, headers = headers)) {
|
||||||
|
mapper.readValue<ResponseJson?>(this.text)?.let {
|
||||||
|
if (it.success && it.data != null) {
|
||||||
|
it.data.forEach { data ->
|
||||||
|
extractedLinksList.add(
|
||||||
|
ExtractorLink(
|
||||||
|
"$name ${data.label}",
|
||||||
|
data.file,
|
||||||
|
url,
|
||||||
|
getQuality(data.label),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return extractedLinksList
|
||||||
|
} catch (e: Exception) {
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue