Spanish extension updates (#829)
* choose best quality video Automatically choose a server that contains the best quality video. * Extractor standardization * bugs resolved
This commit is contained in:
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Animefenix'
|
||||
pkgNameSuffix = 'es.animefenix'
|
||||
extClass = '.Animefenix'
|
||||
extVersionCode = 5
|
||||
extVersionCode = 6
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.FembedExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.OkruExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.StreamSBExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.StreamTapeExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
@ -23,6 +24,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.net.URLDecoder
|
||||
|
||||
class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -90,18 +92,15 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
when {
|
||||
realUrl.contains("ok.ru") -> {
|
||||
val video = OkruExtractor(client).videosFromUrl(realUrl)
|
||||
videoList.addAll(video)
|
||||
OkruExtractor(client).videosFromUrl(realUrl).map { videoList.add(it) }
|
||||
}
|
||||
realUrl.contains("fembed") -> {
|
||||
val video = FembedExtractor().videosFromUrl(realUrl)
|
||||
videoList.addAll(video)
|
||||
FembedExtractor().videosFromUrl(realUrl).map { videoList.add(it) }
|
||||
}
|
||||
realUrl.contains("/stream/amz.php?") -> {
|
||||
val video = amazonExtractor(baseUrl + realUrl.substringAfter(".."))
|
||||
if (video.isNotBlank()) {
|
||||
if (realUrl.contains("&ext=es")) {
|
||||
|
||||
videoList.add(Video(video, "Amazon ES", video))
|
||||
} else {
|
||||
videoList.add(Video(video, "Amazon", video))
|
||||
@ -117,14 +116,26 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
}
|
||||
realUrl.contains("streamtape") -> {
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(realUrl, "Streamtape")
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(realUrl, "StreamTape")
|
||||
if (video != null) {
|
||||
videoList.add(video)
|
||||
}
|
||||
}
|
||||
realUrl.contains("sbthe") -> {
|
||||
val headers = headers.newBuilder()
|
||||
.set("referer", realUrl)
|
||||
.set(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36"
|
||||
)
|
||||
.set("Accept-Language", "es-MX,es-419;q=0.9,es;q=0.8,en;q=0.7")
|
||||
.set("watchsb", "streamsb")
|
||||
.set("authority", "embedsb.com")
|
||||
.build()
|
||||
StreamSBExtractor(client).videosFromUrl(realUrl, headers).map { videoList.add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return videoList
|
||||
}
|
||||
|
||||
@ -134,6 +145,27 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Amazon")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
|
||||
@ -175,6 +207,14 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
override fun latestUpdatesSelector() = popularAnimeSelector()
|
||||
|
||||
private fun amazonExtractor(url: String): String {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val videoURl = document.selectFirst("script:containsData(sources: [)").data()
|
||||
.substringAfter("[{\"file\":\"")
|
||||
.substringBefore("\",").replace("\\", "")
|
||||
return if (client.newCall(GET(videoURl)).execute().code == 200) videoURl else ""
|
||||
}
|
||||
|
||||
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
|
||||
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
|
||||
GenreFilter()
|
||||
@ -238,31 +278,23 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Amazon")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
}
|
||||
return newList
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Servidor Preferido"
|
||||
entries = arrayOf("Amazon", "Fembed:480p", "Fembed:720p", "Amazon", "AmazonES", "FireLoad")
|
||||
entryValues = arrayOf("Amazon", "Fembed:480p", "Fembed:720p", "Amazon", "AmazonES", "FireLoad")
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf(
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
|
||||
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p", "StreamSB:144p", // StreamSB
|
||||
"Amazon", "AmazonES", "StreamTape"
|
||||
) // video servers without resolution
|
||||
entryValues = arrayOf(
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
|
||||
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p", "StreamSB:144p", // StreamSB
|
||||
"Amazon", "AmazonES", "StreamTape"
|
||||
) // video servers without resolution
|
||||
setDefaultValue("Amazon")
|
||||
summary = "%s"
|
||||
|
||||
@ -275,12 +307,4 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
screen.addPreference(videoQualityPref)
|
||||
}
|
||||
|
||||
private fun amazonExtractor(url: String): String {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val videoURl = document.selectFirst("script:containsData(sources: [)").data()
|
||||
.substringAfter("[{\"file\":\"")
|
||||
.substringBefore("\",").replace("\\", "")
|
||||
return if (client.newCall(GET(videoURl)).execute().code == 200) videoURl else ""
|
||||
}
|
||||
}
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class SolidFilesExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,54 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.animefenix.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
val hexChars = CharArray(bytes.size * 2)
|
||||
for (j in bytes.indices) {
|
||||
val v = bytes[j].toInt() and 0xFF
|
||||
|
||||
hexChars[j * 2] = hexArray[v ushr 4]
|
||||
hexChars[j * 2 + 1] = hexArray[v and 0x0F]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
return try {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
}
|
||||
}
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'AnimeFLV'
|
||||
pkgNameSuffix = 'es.animeflv'
|
||||
extClass = '.AnimeFlv'
|
||||
extVersionCode = 25
|
||||
extVersionCode = 26
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@ import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -104,10 +105,6 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
override fun episodeFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
private fun getNumberFromEpsString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }
|
||||
}
|
||||
|
||||
override fun videoListParse(response: Response): List<Video> {
|
||||
val document = response.asJsoup()
|
||||
val videoList = mutableListOf<Video>()
|
||||
@ -119,7 +116,6 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val json = servers!!.jsonObject
|
||||
val quality = json!!["title"]!!.jsonPrimitive!!.content
|
||||
var url = json!!["code"]!!.jsonPrimitive!!.content
|
||||
|
||||
if (quality == "SB") {
|
||||
val headers = headers.newBuilder()
|
||||
.set("referer", url)
|
||||
@ -131,29 +127,19 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
.set("watchsb", "streamsb")
|
||||
.set("authority", "embedsb.com")
|
||||
.build()
|
||||
val videos = StreamSBExtractor(client).videosFromUrl(url, headers)
|
||||
videoList.addAll(videos)
|
||||
StreamSBExtractor(client).videosFromUrl(url, headers).map { videoList.add(it) }
|
||||
}
|
||||
if (quality == "Fembed") {
|
||||
val videos = FembedExtractor().videosFromUrl(url)
|
||||
videoList.addAll(videos)
|
||||
FembedExtractor().videosFromUrl(url).map { videoList.add(it) }
|
||||
}
|
||||
if (quality == "Stape") {
|
||||
val url1 = json!!["url"]!!.jsonPrimitive!!.content
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(url1, quality)
|
||||
if (video != null) {
|
||||
videoList.add(video)
|
||||
}
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(url1, "StreamTape")
|
||||
if (video != null) videoList.add(video)
|
||||
}
|
||||
if (quality == "Doodstream") {
|
||||
val video = try {
|
||||
DoodExtractor(client).videoFromUrl(url, "DoodStream")
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
if (video != null) {
|
||||
videoList.add(video)
|
||||
}
|
||||
val video = DoodExtractor(client).videoFromUrl(url, "DoodStream")
|
||||
if (video != null) videoList.add(video)
|
||||
}
|
||||
if (quality == "Okru") {
|
||||
val videos = OkruExtractor(client).videosFromUrl(url)
|
||||
@ -161,8 +147,7 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
if (quality == "YourUpload") {
|
||||
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
|
||||
val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers)
|
||||
if (!videos.isEmpty()) videoList.addAll(videos)
|
||||
YourUploadExtractor(client).videoFromUrl(url, headers = headers).map { videoList.add(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,21 +162,24 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Stape")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -304,8 +292,18 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile")
|
||||
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile")
|
||||
entries = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
|
||||
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p", "StreamSB:144p", // StreamSB
|
||||
"YourUpload", "DoodStream", "StreamTape"
|
||||
) // video servers without resolution
|
||||
entryValues = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
|
||||
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p", "StreamSB:144p", // StreamSB
|
||||
"YourUpload", "DoodStream", "StreamTape"
|
||||
) // video servers without resolution
|
||||
setDefaultValue("Fembed:720p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class DoodExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
|
||||
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
return try {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRandomString(length: Int = 10): String {
|
||||
|
@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val prefix = qualityPrefix
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = prefix + "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = qualityPrefix + "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.animeflv.extractors
|
||||
|
||||
import android.util.Log
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import kotlinx.serialization.decodeFromString
|
||||
@ -9,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
@ -25,27 +24,31 @@ class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
Log.i("bruh sb", master)
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
return try {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import java.io.IOException
|
||||
class YourUploadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
try {
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute()
|
||||
if (document.isSuccessful) {
|
||||
val content = document.asJsoup()
|
||||
@ -21,8 +21,9 @@ class YourUploadExtractor(private val client: OkHttpClient) {
|
||||
videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'AnimeID'
|
||||
pkgNameSuffix = 'es.animeid'
|
||||
extClass = '.AnimeID'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.animeextension.es.animeid
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.animeid.extractors.StreamTapeExtractor
|
||||
@ -29,6 +28,7 @@ import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.net.URI
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
@ -130,9 +130,7 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
var jsonString = script.attr("data")
|
||||
val jsonUnescape = unescapeJava(jsonString)!!.replace("\\", "")
|
||||
val url = jsonUnescape!!.substringAfter("src=\"").substringBefore("\"").replace("\\\\", "\\")
|
||||
Log.i("bruh url", url)
|
||||
val quality = getDomainName(url)
|
||||
Log.i("bruh domain", quality.toString())
|
||||
if (quality == "streamtape") {
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(url, "Streamtape")
|
||||
if (video != null) {
|
||||
@ -185,21 +183,24 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Streamtape")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "StreamTape")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -211,7 +212,6 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
genreFilter.state != 0 -> GET("$baseUrl/genero/${genreFilter.toUriPart()}?pag=$page&sort=newest")
|
||||
else -> GET("$baseUrl/series?sort=newest&pag=$page")
|
||||
}
|
||||
Log.i("genero", request.url.toString())
|
||||
return request
|
||||
}
|
||||
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'AnimeLatinoHD'
|
||||
pkgNameSuffix = 'es.animelatinohd'
|
||||
extClass = '.AnimeLatinoHD'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,7 @@ import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
|
||||
class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
@ -221,21 +222,24 @@ class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "[Sub] Fembed:720p")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "[Sub] Fembed:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -365,11 +369,24 @@ class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector()
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val options = arrayOf(
|
||||
"[Sub] Fembed:1080p", "[Sub] Fembed:720p", "[Sub] Fembed:480p", "[Sub] Fembed:360p", "[Sub] Fembed:240p", // Fembed [Sub]
|
||||
"[Lat] Fembed:1080p", "[Lat] Fembed:720p", "[Lat] Fembed:480p", "[Lat] Fembed:360p", "[Lat] Fembed:240p", // Fembed [Lat]
|
||||
"[Sub] Okru:1080p", "[Sub] Okru:720p", "[Sub] Okru:480p", "[Sub] Okru:360p", "[Sub] Okru:240p", // Okru [Sub]
|
||||
"[Lat] Okru:1080p", "[Lat] Okru:720p", "[Lat] Okru:480p", "[Lat] Okru:360p", "[Lat] Okru:240p", // Okru [Lat]
|
||||
"[Sub] StreamSB:1080p", "[Sub] StreamSB:720p", "[Sub] StreamSB:480p", "[Sub] StreamSB:360p", "[Sub] StreamSB:240p", // StreamSB [Sub]
|
||||
"[Lat] StreamSB:1080p", "[Lat] StreamSB:720p", "[Lat] StreamSB:480p", "[Lat] StreamSB:360p", "[Lat] StreamSB:240p", // StreamSB [Lat]
|
||||
"[Sub] StreamTape", "[Lat] StreamTape", // video servers without resolution
|
||||
"[Sub] DoodStream", "[Lat] DoodStream", // video servers without resolution
|
||||
"[Sub] SolidFiles", "[Lat] SolidFiles", // video servers without resolution
|
||||
"[Sub] Od.lk", "[Lat] Od.lk", // video servers without resolution
|
||||
"[Sub] CldUp", "[Lat] CldUp"
|
||||
) // video servers without resolution
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("[Sub] Od.lk", "[Sub] CldUp", "[Sub] SolidFiles", "[Sub] Fembed:720p", "[Sub] Fembed:480p", "[Lat] Od.lk", "[Lat] CldUp", "[Lat] SolidFiles", "[Lat] Fembed:720p", "[Lat] Fembed:480p")
|
||||
entryValues = arrayOf("[Sub] Od.lk", "[Sub] CldUp", "[Sub] SolidFiles", "[Sub] Fembed:720p", "[Sub] Fembed:480p", "[Lat] Od.lk", "[Lat] CldUp", "[Lat] SolidFiles", "[Lat] Fembed:720p", "[Lat] Fembed:480p")
|
||||
entries = options
|
||||
entryValues = options
|
||||
setDefaultValue("[Sub] Fembed:720p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class DoodExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
|
||||
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
return try {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRandomString(length: Int = 10): String {
|
||||
|
@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val prefix = qualityPrefix
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = prefix + "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = qualityPrefix + "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class SolidFilesExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
@ -25,25 +25,30 @@ class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): List<Video> {
|
||||
val sbUrl = url.substringBefore("/e")
|
||||
val id = url.substringAfter("e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
val videoList = mutableListOf<Video>()
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
return try {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'AnimeonlineNinja'
|
||||
pkgNameSuffix = 'es.animeonlineninja'
|
||||
extClass = '.AnimeonlineNinja'
|
||||
extVersionCode = 7
|
||||
extVersionCode = 8
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.FembedE
|
||||
import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.JsUnpacker
|
||||
import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.StreamSBExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.StreamTapeExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.uploadExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.UploadExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
@ -27,6 +27,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -102,7 +103,7 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val iframeLink = apiCall.toString().substringAfter("{\"embed_url\":\"").substringBefore("\"")
|
||||
val sDocument = client.newCall(GET(iframeLink)).execute().asJsoup()
|
||||
sDocument.select("div.ODDIV div").forEach {
|
||||
val lang = it.attr("class").toString().substringAfter("OD OD_").replace("REactiv", "")
|
||||
val lang = it.attr("class").toString().substringAfter("OD OD_").replace("REactiv", "").trim()
|
||||
it.select("li").forEach { source ->
|
||||
val sourceUrl = source.attr("onclick").toString().substringAfter("go_to_player('").substringBefore("')")
|
||||
serverslangParse(sourceUrl, lang).map { video -> videoList.add(video) }
|
||||
@ -116,7 +117,7 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val apiCall = client.newCall(GET("https://www1.animeonline.ninja/wp-json/dooplayer/v1/post/$datapost?type=$datatype&source=$sourceId")).execute().asJsoup().body()
|
||||
val sourceUrl = apiCall.toString().substringAfter("{\"embed_url\":\"").substringBefore("\"").replace("\\/", "/")
|
||||
|
||||
val lang2 = preferences.getString("preferred_lang", "SUB").toString()
|
||||
val lang2 = preferences.getString("preferred_lang", "SUB").toString().trim()
|
||||
serverslangParse(sourceUrl, lang2).map { video -> videoList.add(video) }
|
||||
}
|
||||
}
|
||||
@ -184,8 +185,8 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
serverUrl.contains("uqload") && lang.contains(langSelect) -> {
|
||||
val headers = headers.newBuilder().add("referer", "https://uqload.com/").build()
|
||||
val video = uploadExtractor(client).videofromurl(serverUrl, headers, lang)
|
||||
videos.add(video)
|
||||
val video = UploadExtractor(client).videoFromUrl(serverUrl, headers, lang)
|
||||
if (video != null) videos.add(video)
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,21 +200,24 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Mixdrop")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "SUB Fembed:1080p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -337,7 +341,7 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("SUB Fembed:480p", "SUB Fembed:720p", "SUB Fembed:1080p")
|
||||
entryValues = arrayOf("SUB Fembed:480p", "SUB Fembed:720p", "SUB Fembed:1080p")
|
||||
setDefaultValue("SUB Fembed:720p")
|
||||
setDefaultValue("SUB Fembed:1080p")
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
|
@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class DoodExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
|
||||
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
return try {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRandomString(length: Int = 10): String {
|
||||
|
@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val prefix = qualityPrefix
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = prefix + "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class SolidFilesExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
@ -24,27 +24,31 @@ class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
return try {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class UploadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers, quality: String): Video? {
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val basicUrl = document.selectFirst("script:containsData(var player =)").data().substringAfter("sources: [\"").substringBefore("\"],")
|
||||
return Video(basicUrl, "$quality Uqload", basicUrl, headers = headers)
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
class uploadExtractor(private val client: OkHttpClient) {
|
||||
fun videofromurl(url: String, headers: Headers, quality: String): Video {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val basicUrl = document.selectFirst("script:containsData(var player =)").data().substringAfter("sources: [\"").substringBefore("\"],")
|
||||
return Video(basicUrl, "$quality Uqload", basicUrl, headers = headers)
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Animeyt'
|
||||
pkgNameSuffix = 'es.animeyt'
|
||||
extClass = '.Animeyt'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class Animeyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -98,21 +99,24 @@ class Animeyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "fastream")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fastream:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = GET("$baseUrl/search?q=$query&page=$page")
|
||||
@ -155,9 +159,9 @@ class Animeyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile")
|
||||
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile")
|
||||
setDefaultValue("fastream")
|
||||
entries = arrayOf("Fastream:720p", "Fastream:480p", "Fastream:360p")
|
||||
entryValues = arrayOf("Fastream:720p", "Fastream:480p", "Fastream:360p")
|
||||
setDefaultValue("Fastream:720p")
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
|
@ -1,12 +1,19 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.animeyt.extractors
|
||||
|
||||
import android.util.Log
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.OkHttpClient
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
|
||||
class FastreamExtractor(private val client: OkHttpClient) {
|
||||
private val json: Json by injectLazy()
|
||||
private fun fetchUrls(text: String?): List<String> {
|
||||
if (text.isNullOrEmpty()) return listOf()
|
||||
val linkRegex = "(http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\\/~+#-]*[\\w@?^=%&\\/~+#-])".toRegex()
|
||||
@ -25,12 +32,38 @@ class FastreamExtractor(private val client: OkHttpClient) {
|
||||
videoList.add(Video(basicUrl, server, basicUrl, headers = null))
|
||||
} else {
|
||||
val packedRegex = Regex("eval\\(function\\(p,a,c,k,e,.*\\)\\)")
|
||||
val qualities = listOf(
|
||||
Pair("Low", "360p"),
|
||||
Pair("Normal", "480p"),
|
||||
Pair("HD", "720p"),
|
||||
Pair("Full", "1080p"),
|
||||
)
|
||||
packedRegex.findAll(it!!.data()).map { packed -> packed.value }.toList().map { eval ->
|
||||
val fastreamRegex = "fastream.*?\\.m3u8([^&\">]?)".toRegex()
|
||||
val unpack = JsUnpacker.unpack(eval)
|
||||
fetchUrls(unpack!!.first()).map { url ->
|
||||
val fastreamRegex = "fastream.*?\\.m3u8([^&\">]?)".toRegex()
|
||||
if (fastreamRegex.containsMatchIn(url)) {
|
||||
videoList.add(Video(url, server, url, headers = null))
|
||||
val urlQualities = url.split(",").filter { p -> !p.contains("m3u8") }
|
||||
val baseUrl = urlQualities.first()
|
||||
val jsonQualities = "{ \"qualityLabels\": { ${unpack.first().substringAfter("\\'qualityLabels\\':{").substringBefore("},")} }}"
|
||||
val jObject = json.decodeFromString<JsonObject>(jsonQualities)
|
||||
val jQualities = jObject["qualityLabels"]!!.jsonObject.map { jsonElement ->
|
||||
val jQuality = jsonElement.value.toString().replace("\"", "")
|
||||
qualities.find { q -> q.first.contains(jQuality) }?.second
|
||||
}.toTypedArray()
|
||||
Log.i("bruh jQuality join", jQualities.joinToString())
|
||||
var qualityIdx = 0
|
||||
urlQualities.map { _url ->
|
||||
if (!_url.contains("http")) {
|
||||
Log.i("bruh _url", "$_url $qualityIdx")
|
||||
val quality = "$server:${jQualities[qualityIdx]}"
|
||||
Log.i("bruh quality", quality)
|
||||
val videoUrl = "$baseUrl$_url/master.m3u8"
|
||||
Log.i("bruh videoUrl", videoUrl)
|
||||
qualityIdx++
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'AsiaLiveAction'
|
||||
pkgNameSuffix = 'es.asialiveaction'
|
||||
extClass = '.AsiaLiveAction'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
import java.util.Calendar
|
||||
|
||||
@ -59,10 +60,10 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun animeDetailsParse(document: Document): SAnime {
|
||||
val anime = SAnime.create()
|
||||
anime.thumbnail_url = document.selectFirst("header div.Image figure img").attr("src").trim().replace("//", "https://")
|
||||
anime.title = document.selectFirst("header div.asia-post-header div h1.Title").text()
|
||||
anime.title = document.selectFirst("header div.asia-post-header h1.Title").text()
|
||||
anime.description = document.selectFirst("header div.asia-post-main div.Description p:nth-child(2)").text().removeSurrounding("\"")
|
||||
anime.genre = document.select("div.asia-post-header div:nth-child(2) p.Info span.tags a").joinToString { it.text() }
|
||||
val year = document.select("div.asia-post-header div:nth-child(2) p.Info span.Date a").text().toInt()
|
||||
anime.genre = document.select("div.asia-post-main p.Info span.tags a").joinToString { it.text() }
|
||||
val year = document.select("header div.asia-post-main p.Info span.Date a").text().toInt()
|
||||
val currentYear = Calendar.getInstance().get(Calendar.YEAR)
|
||||
anime.status = when {
|
||||
(year < currentYear) -> SAnime.COMPLETED
|
||||
@ -80,13 +81,13 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
override fun episodeFromElement(element: Element): SEpisode {
|
||||
val episode = SEpisode.create()
|
||||
val epNum = getNumberFromEpsString(element.select("div.flex-grow-1 p span").text())
|
||||
val epNum = getNumberFromEpsString(element.select("div.flex-grow-1 p").text())
|
||||
episode.setUrlWithoutDomain(element.attr("href"))
|
||||
episode.episode_number = when {
|
||||
(epNum.isNotEmpty()) -> epNum.toFloat()
|
||||
else -> 1F
|
||||
}
|
||||
episode.name = element.select("div.flex-grow-1 p span").text().trim()
|
||||
episode.name = element.select("div.flex-grow-1 p").text().trim()
|
||||
return episode
|
||||
}
|
||||
|
||||
@ -98,9 +99,10 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val document = response.asJsoup()
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("var videosJap = [")) {
|
||||
if (script.data().contains("var videosJap = [") || script.data().contains("var videosCor = [")) {
|
||||
val content = script.data()
|
||||
if (content.contains("sbfull")) {
|
||||
val sbDomains = arrayOf("sbfull", "sbplay", "cloudemb", "sbplay", "embedsb", "pelistop", "streamsb", "sbplay", "sbspeed")
|
||||
if (sbDomains.any { s -> content.contains(s) }) {
|
||||
val url = content.substringAfter(",['SB','").substringBefore("',0,0]")
|
||||
val headers = headers.newBuilder()
|
||||
.set("Referer", url)
|
||||
@ -136,21 +138,24 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Fembed:1080p")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:1080p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -218,11 +223,16 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun latestUpdatesSelector() = popularAnimeSelector()
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", // Okru
|
||||
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p" // StreamSB
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile")
|
||||
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:1080p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
@ -24,26 +24,30 @@ class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val sbUrl = url.substringBefore("/e")
|
||||
val id = url.substringAfter("e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
return try {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master = "$sbUrl/sources43/674a44656e7654507975614b7c7c${bytesToHex}7c7c4a6d665478704f786e5a464f7c7c73747265616d7362/384c6d46545332726b3171787c7c373637333438343737393661363735343538366434353730376337633734353037393332353734333638363436643730363637373763376336363631346634353732366333323635343933343537346637633763373337343732363536313664373336327c7c5154416f774c34306d4877387c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Doramasyt'
|
||||
pkgNameSuffix = 'es.doramasyt'
|
||||
extClass = '.Doramasyt'
|
||||
extVersionCode = 2
|
||||
extVersionCode = 3
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.FembedExtracto
|
||||
import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.OkruExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.SolidFilesExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.StreamTapeExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.UqloadExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
@ -25,6 +26,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
|
||||
class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
|
||||
@ -91,26 +93,33 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val server = players.text()
|
||||
val urlEncoded = players.attr("data-player")
|
||||
val byte = android.util.Base64.decode(urlEncoded, android.util.Base64.DEFAULT)
|
||||
val url = String(byte, charset("UTF-8")).replace("https://doramasyt.com/reproductor?url=", "")
|
||||
Log.i("bruh server", url)
|
||||
if (server == "fembed") {
|
||||
val url = String(byte, charset("UTF-8")).substringAfter("?url=")
|
||||
if (server.contains("fembed")) {
|
||||
val videos = FembedExtractor().videosFromUrl(url)
|
||||
videoList.addAll(videos)
|
||||
}
|
||||
if (server == "streamtape") {
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(url, "Streamtape")
|
||||
if (server.contains("streamtape")) {
|
||||
val video = StreamTapeExtractor(client).videoFromUrl(url)
|
||||
if (video != null) {
|
||||
videoList.add(video)
|
||||
}
|
||||
}
|
||||
if (server == "ok") {
|
||||
if (server.contains("ok")) {
|
||||
val videos = OkruExtractor(client).videosFromUrl(url)
|
||||
videoList.addAll(videos)
|
||||
}
|
||||
if (server == "zeus") {
|
||||
if (server.contains("zeus")) {
|
||||
val videos = SolidFilesExtractor(client).videosFromUrl(url)
|
||||
videoList.addAll(videos)
|
||||
}
|
||||
if (server.contains("uqload")) {
|
||||
val headers = headers.newBuilder().add("referer", "https://uqload.com/").build()
|
||||
UqloadExtractor(client).videoFromUrl(url, headers, "Uqload").map { videoList.add(it) }
|
||||
}
|
||||
if (server.contains("upload")) {
|
||||
val headers = headers.newBuilder().add("referer", "https://upload.com/").build()
|
||||
UqloadExtractor(client).videoFromUrl(url, headers, "Upload").map { videoList.add(it) }
|
||||
}
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
@ -122,21 +131,24 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "fembed")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -148,7 +160,6 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
genreFilter.state != 0 -> GET("$baseUrl/doramas?categoria=false&genero=${genreFilter.toUriPart()}&fecha=false&letra=false&p=$page")
|
||||
else -> GET("$baseUrl/doramas/?p=$page")
|
||||
}
|
||||
// GET("$baseUrl/buscar?q=$query&p=$page")
|
||||
}
|
||||
|
||||
override fun searchAnimeFromElement(element: Element): SAnime {
|
||||
@ -267,11 +278,16 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
|
||||
"Uqload", "Upload", "SolidFiles", "StreamTape", // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "Streamtape", "SolidFiles", "Okru: mobile", "Okru: lowest", "Okru: low", "Okru: sd", "Okru: hd")
|
||||
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "Streamtape", "SolidFiles", "Okru: mobile", "Okru: lowest", "Okru: low", "Okru: sd", "Okru: hd")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:720p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,19 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class SolidFilesExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val videoUrl = data.replace("\"", "")
|
||||
val quality = "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class UqloadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers, quality: String): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute()
|
||||
if (document.isSuccessful) {
|
||||
val response = document.asJsoup()
|
||||
response.select("script").map {
|
||||
if (it.data().contains("var player =")) {
|
||||
val basicUrl = it.data().substringAfter("sources: [\"").substringBefore("\"],")
|
||||
videoList.add(Video(basicUrl, quality, basicUrl, headers = headers))
|
||||
}
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Hentaijk'
|
||||
pkgNameSuffix = 'es.hentaijk'
|
||||
extClass = '.Hentaijk'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '13'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.animeextension.es.hentaijk
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.hentaijk.extractors.FembedExtractor
|
||||
@ -26,6 +25,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -75,12 +75,10 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
?.replace("#pag", "")
|
||||
val firstPage = pageNumber.first()?.attr("href")
|
||||
?.replace("#pag", "")
|
||||
Log.i("bruh", "ULTIMA: $lastPage")
|
||||
|
||||
if (firstPage != lastPage) {
|
||||
var checkLast = 0
|
||||
for (i in 1 until lastPage?.toInt()!!) {
|
||||
Log.i("bruh", "aaa")
|
||||
for (j in 1..12) {
|
||||
// Log.i("bruh", (j + checkLast).toString())
|
||||
val episode = SEpisode.create().apply {
|
||||
@ -96,7 +94,6 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
Jsoup.connect("https://hentaijk.com/ajax/pagination_episodes/$animeId/$lastPage").get()
|
||||
.body().select("body").text().replace("}]", "").split("}").forEach { json ->
|
||||
val number = json.substringAfter("\"number\":\"").substringBefore("\"")
|
||||
Log.i("bruh", number)
|
||||
val episode = SEpisode.create().apply {
|
||||
episode_number = number.toFloat()
|
||||
name = "Episodio $number"
|
||||
@ -111,7 +108,6 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
Jsoup.connect("https://hentaijk.com/ajax/pagination_episodes/$animeId/$lastPage").get()
|
||||
.body().select("body").text().replace("}]", "").split("}").forEach { json ->
|
||||
val number = json.substringAfter("\"number\":\"").substringBefore("\"")
|
||||
Log.i("bruh", number)
|
||||
val episode = SEpisode.create().apply {
|
||||
episode_number = number.toFloat()
|
||||
name = "Episodio $number"
|
||||
@ -210,21 +206,24 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Sabrosio")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Sabrosio")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -262,7 +261,7 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val animeList = mutableListOf<SAnime>()
|
||||
val document = jsonLine.asJsoup()
|
||||
val hasNextPage = document.select("section.contenido.spad div.container div.navigation a.nav-next").any()
|
||||
var isSearchLayer = document.select(".col-lg-2.col-md-6.col-sm-6").any()
|
||||
val isSearchLayer = document.select(".col-lg-2.col-md-6.col-sm-6").any()
|
||||
val isFilterLayer = document.select(".card.mb-3.custom_item2").any()
|
||||
if (isSearchLayer) {
|
||||
document.select(".col-lg-2.col-md-6.col-sm-6").forEach { animeData ->
|
||||
@ -288,7 +287,6 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
animeList.add(anime)
|
||||
}
|
||||
}
|
||||
Log.i("bruh parseSearchJson", hasNextPage.toString())
|
||||
return AnimesPage(animeList, hasNextPage)
|
||||
}
|
||||
|
||||
@ -443,11 +441,16 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", // Okru
|
||||
"Xtreme S", "HentaiJk", "Nozomi", "Desu" // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Sabrosio", "Desu", "Xtreme S", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entryValues = arrayOf("Sabrosio", "Desu", "Xtreme S", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Sabrosio")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Hentaila'
|
||||
pkgNameSuffix = 'es.hentaila'
|
||||
extClass = '.Hentaila'
|
||||
extVersionCode = 6
|
||||
extVersionCode = 7
|
||||
libVersion = '13'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -120,21 +121,24 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Fembed:480p")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:1080p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
@ -251,12 +255,16 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"Arc" // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Arc", "Fembed:480p", "Fembed:720p", "Fembed:1080p")
|
||||
entryValues = arrayOf("Arc", "Fembed:480p", "Fembed:720p", "Fembed:1080p")
|
||||
setDefaultValue("Fembed:480p")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:1080p")
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Jkanime'
|
||||
pkgNameSuffix = 'es.jkanime'
|
||||
extClass = '.Jkanime'
|
||||
extVersionCode = 4
|
||||
extVersionCode = 5
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -26,6 +26,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -205,21 +206,24 @@ class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Nozomi")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Nozomi")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -437,11 +441,16 @@ class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", // Okru
|
||||
"Xtreme S", "HentaiJk", "Nozomi", "Desu" // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Nozomi", "Desu", "Xtreme S", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entryValues = arrayOf("Nozomi", "Desu", "Xtreme S", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Nozomi")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Jkhentai'
|
||||
pkgNameSuffix = 'es.jkhentai'
|
||||
extClass = '.Jkhentai'
|
||||
extVersionCode = 5
|
||||
extVersionCode = 6
|
||||
libVersion = '13'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import android.content.SharedPreferences
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.jkhentai.extractors.StreamTapeExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.jkhentai.extractors.YourUploadExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
@ -21,6 +22,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -91,6 +93,11 @@ class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
videoList.add(video)
|
||||
}
|
||||
}
|
||||
if (server == "Upload") {
|
||||
val url = it.select("div.player-content iframe").attr("src")
|
||||
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
|
||||
YourUploadExtractor(client).videoFromUrl(url, headers = headers).map { vid -> videoList.add(vid) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return videoList
|
||||
@ -103,21 +110,24 @@ class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "StreamTape")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "StreamTape")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -219,8 +229,8 @@ class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("StreamTape")
|
||||
entryValues = arrayOf("StreamTape")
|
||||
entries = arrayOf("StreamTape", "YourUpload")
|
||||
entryValues = arrayOf("StreamTape", "YourUpload")
|
||||
setDefaultValue("StreamTape")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class SolidFilesExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.jkhentai.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class YourUploadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute()
|
||||
if (document.isSuccessful) {
|
||||
val content = document.asJsoup()
|
||||
val baseData =
|
||||
content!!.selectFirst("script:containsData(jwplayerOptions)")!!.data()
|
||||
if (!baseData.isNullOrEmpty()) {
|
||||
val basicUrl = baseData.substringAfter("file: '").substringBefore("',")
|
||||
videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'MonosChinos'
|
||||
pkgNameSuffix = 'es.monoschinos'
|
||||
extClass = '.MonosChinos'
|
||||
extVersionCode = 12
|
||||
extVersionCode = 13
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors.FembedExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors.OkruExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors.SolidFilesExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors.uploadExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors.UploadExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
@ -25,6 +25,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -52,7 +53,7 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
return SAnime.create().apply {
|
||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
||||
title = element.select("a div.series div.seriesdetails h3").text()
|
||||
thumbnail_url = if(thumbDiv.attr("src").contains("/public/img")){
|
||||
thumbnail_url = if (thumbDiv.attr("src").contains("/public/img")) {
|
||||
thumbDiv.attr("data-src")
|
||||
} else {
|
||||
thumbDiv.attr("src")
|
||||
@ -91,7 +92,10 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
url.contains("fembed") -> videoList.addAll(FembedExtractor().videosFromUrl(url))
|
||||
url.contains("ok") -> if (!url.contains("streamcherry")) videoList.addAll(OkruExtractor(client).videosFromUrl(url))
|
||||
url.contains("solidfiles") -> videoList.addAll(SolidFilesExtractor(client).videosFromUrl(url))
|
||||
url.contains("uqload") -> videoList.add(uploadExtractor(client).videofromurl(url, headers))
|
||||
url.contains("uqload") -> {
|
||||
val video = UploadExtractor(client).videoFromUrl(url, headers)
|
||||
if (video != null) videoList.add(video)
|
||||
}
|
||||
}
|
||||
}
|
||||
return videoList
|
||||
@ -104,21 +108,24 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "SolidFiles")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -139,6 +146,7 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
else -> GET("$baseUrl/animes?categoria=false&genero=${genreFilter.toUriPart()}&fecha=$yearFilter&letra=$letterFilter&p=$page")
|
||||
}
|
||||
}
|
||||
|
||||
override fun searchAnimeFromElement(element: Element): SAnime {
|
||||
return popularAnimeFromElement(element)
|
||||
}
|
||||
@ -242,11 +250,16 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", // Okru
|
||||
"SolidFiles", "Upload" // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:720p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,19 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class SolidFilesExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val videoUrl = data.replace("\"", "")
|
||||
val quality = "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
document.select("script").forEach { script ->
|
||||
if (script.data().contains("\"downloadUrl\":")) {
|
||||
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
|
||||
val url = data.replace("\"", "")
|
||||
val videoUrl = url
|
||||
val quality = prefix + "SolidFiles"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,20 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class UploadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers): Video? {
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val basicUrl = document.selectFirst("script:containsData(var player =)").data().substringAfter("sources: [\"").substringBefore("\"],")
|
||||
return Video(basicUrl, "Uqload", basicUrl, headers = headers)
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
|
||||
class uploadExtractor(private val client: OkHttpClient) {
|
||||
fun videofromurl(url: String, headers: Headers): Video {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val basicUrl = try {
|
||||
document.selectFirst("script:containsData(var player =)").data().substringAfter("sources: [\"").substringBefore("\"],")
|
||||
} catch (e: Exception) {
|
||||
""
|
||||
}
|
||||
return if (basicUrl.isNotEmpty()) Video(basicUrl, "video/mp4", basicUrl, headers) else {
|
||||
Video("not used", "File Deleted", "not used", headers)
|
||||
}
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'MundoDonghua'
|
||||
pkgNameSuffix = 'es.mundodonghua'
|
||||
extClass = '.MundoDonghua'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -113,8 +114,7 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
fetchUrls(unpack!!.first()).map { url ->
|
||||
if (url.contains("diasfem")) {
|
||||
var serverUrl = url.replace("diasfem", "embedsito")
|
||||
var videos = FembedExtractor().videosFromUrl(serverUrl)
|
||||
videoList.addAll(videos)
|
||||
FembedExtractor().videosFromUrl(serverUrl).map { vid -> videoList.add(vid) }
|
||||
}
|
||||
}
|
||||
if (unpack!!.first()!!.contains("protea_tab")) {
|
||||
@ -138,9 +138,7 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
.set("referer", response!!.request!!.url!!.toString())
|
||||
.set("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36")
|
||||
.build()
|
||||
ProteaExtractor().videosFromUrl(requestlink, "Protea", headers = headers, baseUrl).forEach {
|
||||
videoList.add(it)
|
||||
}
|
||||
ProteaExtractor().videosFromUrl(requestlink, "Protea", headers = headers).map { vid -> videoList.add(vid) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,23 +153,24 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
var quality = preferences.getString("preferred_quality", "Protea:720p")
|
||||
if (quality == null) quality = preferences.getString("preferred_quality", "Fembed:720p")
|
||||
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -271,11 +270,15 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun latestUpdatesSelector() = popularAnimeSelector()
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Protea:1080p", "Protea:720p", "Protea:480p", "Protea:380p", "Protea:360p",
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:380p", "Fembed:360p"
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Protea:1080p", "Protea:720p", "Protea:480p", "Protea:380p", "Protea:360p", "Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:380p", "Fembed:360p")
|
||||
entryValues = arrayOf("Protea:1080p", "Protea:720p", "Protea:480p", "Protea:380p", "Protea:360p", "Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:380p", "Fembed:360p")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:720p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
var videoApi = url.replace("/v/", "/api/source/")
|
||||
var json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val prefix = qualityPrefix
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = prefix + "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ import java.io.IOException
|
||||
|
||||
class ProteaExtractor() {
|
||||
private val json: Json by injectLazy()
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = "Protea", headers: Headers, baseUrl: String): List<Video> {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = "Protea", headers: Headers): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
try {
|
||||
val document = Jsoup.connect(url).headers(headers.toMap()).ignoreContentType(true).method(Connection.Method.POST).execute()
|
||||
@ -49,15 +49,4 @@ class ProteaExtractor() {
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
|
||||
private fun fixUrl(url: String, baseUrl: 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 baseUrl + url
|
||||
return "$baseUrl/$url"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Pelisflix'
|
||||
pkgNameSuffix = 'es.pelisflix'
|
||||
extClass = '.PelisflixFactory'
|
||||
extVersionCode = 1
|
||||
extVersionCode = 2
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -154,21 +154,24 @@ open class Pelisflix(override val name: String, override val baseUrl: String) :
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "LAT Nupload")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "LAT Nupload")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
|
@ -1,5 +1,9 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.pelisflix
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.DoodExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.FembedExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.StreamTapeExtractor
|
||||
@ -18,6 +22,9 @@ import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
|
||||
class PelisflixFactory : AnimeSourceFactory {
|
||||
override fun createSources(): List<AnimeSource> = listOf(PelisflixClass(), SeriesflixClass())
|
||||
@ -30,6 +37,10 @@ class SeriesflixClass : Pelisflix("Seriesflix", "https://seriesflix.video") {
|
||||
|
||||
override fun popularAnimeSelector() = "li[id*=post-] > article"
|
||||
|
||||
private val preferences: SharedPreferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
override fun popularAnimeFromElement(element: Element): SAnime {
|
||||
val anime = SAnime.create()
|
||||
anime.setUrlWithoutDomain(element.select("a").attr("href"))
|
||||
@ -168,4 +179,48 @@ class SeriesflixClass : Pelisflix("Seriesflix", "https://seriesflix.video") {
|
||||
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:1080p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", // Fembed
|
||||
"DoodStream", "StreamTape" // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:1080p")
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val selected = newValue as String
|
||||
val index = findIndexOfValue(selected)
|
||||
val entry = entryValues[index] as String
|
||||
preferences.edit().putString(key, entry).commit()
|
||||
}
|
||||
}
|
||||
screen.addPreference(videoQualityPref)
|
||||
}
|
||||
}
|
||||
|
@ -7,24 +7,27 @@ import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class DoodExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, qualityPrefix: String = ""): Video? {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val quality = try { "\\d{3,4}p".toRegex().find(content)!!.value.trim() } catch (e: IOException) { "" }
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
return Video(url, "$qualityPrefix Doodstream:$quality", videoUrl, headers = doodHeaders(doodTld))
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
return try {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRandomString(length: Int = 10): String {
|
||||
|
@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
var videoApi = url.replace("/v/", "/api/source/")
|
||||
var json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "$qualityPrefix Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'Pelisplushd'
|
||||
pkgNameSuffix = 'es.pelisplushd'
|
||||
extClass = '.Pelisplushd'
|
||||
extVersionCode = 15
|
||||
extVersionCode = 16
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -32,6 +32,7 @@ import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -179,7 +180,7 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
val epId = amazonApiJson.toString().substringAfter("\"id\":\"").substringBefore("\"")
|
||||
val amazonApi = client.newCall(GET("https://www.amazon.com/drive/v1/nodes/$epId/children?resourceVersion=V2&ContentType=JSON&limit=200&sort=%5B%22kind+DESC%22%2C+%22modifiedDate+DESC%22%5D&asset=ALL&tempLink=true&shareId=$shareId")).execute().asJsoup()
|
||||
val videoUrl = amazonApi.toString().substringAfter("\"FOLDER\":").substringAfter("tempLink\":\"").substringBefore("\"")
|
||||
videoList.add(Video(videoUrl, "uwu", videoUrl))
|
||||
videoList.add(Video(videoUrl, "Amazon", videoUrl))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -221,21 +222,24 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "StreamTape")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Voex")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -313,12 +317,18 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"StreamSB:1080p", "StreamSB:720p", "StreamSB:480p", "StreamSB:360p", "StreamSB:240p", "StreamSB:144p", // StreamSB
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
|
||||
"Streamlare:1080p", "Streamlare:720p", "Streamlare:480p", "Streamlare:360p", "Streamlare:240p", // Streamlare
|
||||
"StreamTape", "Amazon", "Voex", "DoodStream", "YourUpload"
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("StreamSB:360p", "StreamSB:720p", "StreamSB:1080p", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "DoodStream")
|
||||
entryValues = arrayOf("StreamSB:360p", "StreamSB:720p", "StreamSB:1080p", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "DoodStream")
|
||||
setDefaultValue("DoodStream")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Voex")
|
||||
summary = "%s"
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
|
@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class DoodExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
|
||||
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
return try {
|
||||
val response = client.newCall(GET(url)).execute()
|
||||
val doodTld = url.substringAfter("https://dood.").substringBefore("/")
|
||||
val content = response.body!!.string()
|
||||
if (!content.contains("'/pass_md5/")) return null
|
||||
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
|
||||
val token = md5.substringAfterLast("/")
|
||||
val randomString = getRandomString()
|
||||
val expiry = System.currentTimeMillis()
|
||||
val videoUrlStart = client.newCall(
|
||||
GET(
|
||||
"https://dood.$doodTld/pass_md5/$md5",
|
||||
Headers.headersOf("referer", url)
|
||||
)
|
||||
).execute().body!!.string()
|
||||
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
|
||||
Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
|
||||
} catch (e: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun getRandomString(length: Int = 10): String {
|
||||
|
@ -4,23 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
return if (json.getBoolean("success")) {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
val `object` = jsonArray.getJSONObject(i)
|
||||
val videoUrl = `object`.getString("file")
|
||||
val quality = "Fembed:" + `object`.getString("label")
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
videoList.reversed()
|
||||
} else {
|
||||
emptyList()
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
@ -24,25 +24,31 @@ class StreamSBExtractor(private val client: OkHttpClient) {
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
fun videosFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val id = url.substringAfter("embed-").substringBefore(".html").substringAfter("/e/")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"https://embedsb.com/sources43/566d337678566f743674494a7c7c${bytesToHex}7c7c346b6767586d6934774855537c7c73747265616d7362/6565417268755339773461447c7c346133383438333436313335376136323337373433383634376337633465366534393338373136643732373736343735373237613763376334363733353737303533366236333463353333363534366137633763373337343732363536313664373336327c7c6b586c3163614468645a47617c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
return try {
|
||||
val sbUrl = url.substringBefore("/e/")
|
||||
val id = url.substringAfter("/e/").substringBefore(".html")
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master =
|
||||
"$sbUrl/sources43/416f794d637048744d4565577c7c${bytesToHex}7c7c776e6c7a365964385a484b767c7c73747265616d7362/656d5a62394f713230524a667c7c373635353537333734623561373634613330353134633631376337633339353037343631363934393335363434333730373633363763376337613737353836323434353534363431343633323533376137633763373337343732363536313664373336327c7c59304b7778506d424c4c32767c7c73747265616d7362"
|
||||
val json = Json.decodeFromString<JsonObject>(
|
||||
client.newCall(GET(master, headers))
|
||||
.execute().body!!.string()
|
||||
)
|
||||
val masterUrl = json["stream_data"]!!.jsonObject["file"].toString().trim('"')
|
||||
val masterPlaylist = client.newCall(GET(masterUrl, headers)).execute().body!!.string()
|
||||
|
||||
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x")
|
||||
.substringBefore(",") + "p"
|
||||
val videoUrl = it.substringAfter("\n").substringBefore("\n")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers))
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class StreamTapeExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, quality: String): Video? {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val script = document.select("script:containsData(document.getElementById('robotlink'))")
|
||||
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '")
|
||||
?: return null
|
||||
val videoUrl = "https:" + script.substringBefore("'") +
|
||||
script.substringAfter("+ ('xcd").substringBefore("'")
|
||||
return Video(url, quality, videoUrl)
|
||||
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
|
||||
return try {
|
||||
val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
|
||||
val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
|
||||
val document = client.newCall(GET(mainUrl)).execute().asJsoup()
|
||||
val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
|
||||
?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
|
||||
?: return null
|
||||
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
|
||||
Video(videoUrl, quality, videoUrl, headers = null)
|
||||
} catch (i: IOException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import java.io.IOException
|
||||
class YourUploadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
try {
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute()
|
||||
if (document.isSuccessful) {
|
||||
val content = document.asJsoup()
|
||||
@ -21,8 +21,9 @@ class YourUploadExtractor(private val client: OkHttpClient) {
|
||||
videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ ext {
|
||||
extName = 'TioanimeH'
|
||||
pkgNameSuffix = 'es.tioanimeh'
|
||||
extClass = '.TioanimeHFactory'
|
||||
extVersionCode = 5
|
||||
extVersionCode = 6
|
||||
libVersion = '13'
|
||||
}
|
||||
|
||||
|
@ -4,9 +4,9 @@ import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.fembedExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.okruExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.yourUploadExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.FembedExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.OkruExtractor
|
||||
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.YourUploadExtractor
|
||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
@ -23,6 +23,7 @@ import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
import java.lang.Exception
|
||||
|
||||
open class TioanimeH(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
|
||||
@ -86,17 +87,14 @@ open class TioanimeH(override val name: String, override val baseUrl: String) :
|
||||
val serverUrl = servers[1].replace("\\/", "/")
|
||||
when (serverName.lowercase()) {
|
||||
"fembed" -> {
|
||||
val videos = fembedExtractor().videosFromUrl(serverUrl)
|
||||
videoList.addAll(videos)
|
||||
FembedExtractor().videosFromUrl(serverUrl).map { vid -> videoList.add(vid) }
|
||||
}
|
||||
"okru" -> {
|
||||
val videos = okruExtractor(client).videosFromUrl(serverUrl)
|
||||
videoList.addAll(videos)
|
||||
OkruExtractor(client).videosFromUrl(serverUrl).map { vid -> videoList.add(vid) }
|
||||
}
|
||||
"yourupload" -> {
|
||||
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
|
||||
val video = yourUploadExtractor(client).videofromurl(serverUrl, headers = headers)
|
||||
videoList.add(video)
|
||||
YourUploadExtractor(client).videoFromUrl(serverUrl, headers = headers).map { vid -> videoList.add(vid) }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -111,21 +109,24 @@ open class TioanimeH(override val name: String, override val baseUrl: String) :
|
||||
override fun videoFromElement(element: Element) = throw Exception("not used")
|
||||
|
||||
override fun List<Video>.sort(): List<Video> {
|
||||
val quality = preferences.getString("preferred_quality", "Fembed: 720p")
|
||||
if (quality != null) {
|
||||
val newList = mutableListOf<Video>()
|
||||
var preferred = 0
|
||||
for (video in this) {
|
||||
if (video.quality == quality) {
|
||||
newList.add(preferred, video)
|
||||
preferred++
|
||||
} else {
|
||||
newList.add(video)
|
||||
}
|
||||
return try {
|
||||
val videoSorted = this.sortedWith(
|
||||
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
|
||||
).toTypedArray()
|
||||
val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
|
||||
val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
|
||||
if (preferredIdx != -1) {
|
||||
videoSorted.drop(preferredIdx + 1)
|
||||
videoSorted[0] = videoSorted[preferredIdx]
|
||||
}
|
||||
return newList
|
||||
videoSorted.toList()
|
||||
} catch (e: IOException) {
|
||||
this
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
private fun getNumberFromString(epsStr: String): String {
|
||||
return epsStr.filter { it.isDigit() }.ifEmpty { "0" }
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
@ -211,11 +212,16 @@ open class TioanimeH(override val name: String, override val baseUrl: String) :
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
val qualities = arrayOf(
|
||||
"Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:360p", "Fembed:240p", "Fembed:144p", // Fembed
|
||||
"Okru:1080p", "Okru:720p", "Okru:480p", "Okru:360p", "Okru:240p", "Okru:144p", // Okru
|
||||
"YourUpload" // video servers without resolution
|
||||
)
|
||||
val videoQualityPref = ListPreference(screen.context).apply {
|
||||
key = "preferred_quality"
|
||||
title = "Preferred quality"
|
||||
entries = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
|
||||
entries = qualities
|
||||
entryValues = qualities
|
||||
setDefaultValue("Fembed:720p")
|
||||
summary = "%s"
|
||||
|
||||
|
@ -3,13 +3,14 @@ import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Connection
|
||||
import org.jsoup.Jsoup
|
||||
import java.io.IOException
|
||||
|
||||
class fembedExtractor {
|
||||
class FembedExtractor {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
if (json.getBoolean("success")) {
|
||||
return try {
|
||||
val videoApi = url.replace("/v/", "/api/source/")
|
||||
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
|
||||
val videoList = mutableListOf<Video>()
|
||||
val jsonArray = json.getJSONArray("data")
|
||||
for (i in 0 until jsonArray.length()) {
|
||||
@ -18,12 +19,9 @@ class fembedExtractor {
|
||||
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
}
|
||||
return videoList
|
||||
} else {
|
||||
val videoUrl = "not used"
|
||||
val quality = "Video taken down for dmca"
|
||||
videoList.add(Video(videoUrl, quality, videoUrl))
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class OkruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val qualities = listOf(
|
||||
Pair("full", "1080p"),
|
||||
Pair("hd", "720p"),
|
||||
Pair("sd", "480p"),
|
||||
Pair("low", "360p"),
|
||||
Pair("lowest", "240p"),
|
||||
Pair("mobile", "144p")
|
||||
)
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val quality = try { qualities.find { q -> q.first == it.substringBefore("\\\"") }?.second } catch (e: IOException) { it.substringBefore("\\\"") }
|
||||
val videoQuality = qualityPrefix + "Okru:" + quality
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl, headers = null))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
|
||||
class YourUploadExtractor(private val client: OkHttpClient) {
|
||||
fun videoFromUrl(url: String, headers: Headers): List<Video> {
|
||||
val videoList = mutableListOf<Video>()
|
||||
return try {
|
||||
val document = client.newCall(GET(url)).execute()
|
||||
if (document.isSuccessful) {
|
||||
val content = document.asJsoup()
|
||||
val baseData =
|
||||
content!!.selectFirst("script:containsData(jwplayerOptions)")!!.data()
|
||||
if (!baseData.isNullOrEmpty()) {
|
||||
val basicUrl = baseData.substringAfter("file: '").substringBefore("',")
|
||||
videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers))
|
||||
}
|
||||
}
|
||||
videoList
|
||||
} catch (e: IOException) {
|
||||
videoList
|
||||
}
|
||||
}
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.Video
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.OkHttpClient
|
||||
class okruExtractor(private val client: OkHttpClient) {
|
||||
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
|
||||
val document = client.newCall(GET(url)).execute().asJsoup()
|
||||
val videoList = mutableListOf<Video>()
|
||||
val videosString = document.select("div[data-options]").attr("data-options")
|
||||
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"")
|
||||
.substringBefore("]")
|
||||
videosString.split("{\\\"name\\\":\\\"").reversed().forEach {
|
||||
val videoUrl = it.substringAfter("url\\\":\\\"")
|
||||
.substringBefore("\\\"")
|
||||
.replace("\\\\u0026", "&")
|
||||
val videoQuality = qualityPrefix + "Okru: " + it.substringBefore("\\\"")
|
||||
if (videoUrl.startsWith("https://")) {
|
||||
videoList.add(Video(videoUrl, videoQuality, videoUrl))
|
||||
}
|
||||
}
|
||||
return videoList
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user