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:
miguelantonioe
2022-09-02 03:44:40 -05:00
committed by GitHub
parent c2f68cee4f
commit fc30286f7b
101 changed files with 1688 additions and 1075 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Animefenix' extName = 'Animefenix'
pkgNameSuffix = 'es.animefenix' pkgNameSuffix = 'es.animefenix'
extClass = '.Animefenix' extClass = '.Animefenix'
extVersionCode = 5 extVersionCode = 6
libVersion = '13' libVersion = '13'
} }

View File

@ -6,6 +6,7 @@ import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.FembedExtractor 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.OkruExtractor
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.StreamSBExtractor
import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.StreamTapeExtractor import eu.kanade.tachiyomi.animeextension.es.animefenix.extractors.StreamTapeExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
@ -23,6 +24,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.net.URLDecoder import java.net.URLDecoder
class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -90,18 +92,15 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
when { when {
realUrl.contains("ok.ru") -> { realUrl.contains("ok.ru") -> {
val video = OkruExtractor(client).videosFromUrl(realUrl) OkruExtractor(client).videosFromUrl(realUrl).map { videoList.add(it) }
videoList.addAll(video)
} }
realUrl.contains("fembed") -> { realUrl.contains("fembed") -> {
val video = FembedExtractor().videosFromUrl(realUrl) FembedExtractor().videosFromUrl(realUrl).map { videoList.add(it) }
videoList.addAll(video)
} }
realUrl.contains("/stream/amz.php?") -> { realUrl.contains("/stream/amz.php?") -> {
val video = amazonExtractor(baseUrl + realUrl.substringAfter("..")) val video = amazonExtractor(baseUrl + realUrl.substringAfter(".."))
if (video.isNotBlank()) { if (video.isNotBlank()) {
if (realUrl.contains("&ext=es")) { if (realUrl.contains("&ext=es")) {
videoList.add(Video(video, "Amazon ES", video)) videoList.add(Video(video, "Amazon ES", video))
} else { } else {
videoList.add(Video(video, "Amazon", video)) videoList.add(Video(video, "Amazon", video))
@ -117,14 +116,26 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
} }
realUrl.contains("streamtape") -> { realUrl.contains("streamtape") -> {
val video = StreamTapeExtractor(client).videoFromUrl(realUrl, "Streamtape") val video = StreamTapeExtractor(client).videoFromUrl(realUrl, "StreamTape")
if (video != null) { if (video != null) {
videoList.add(video) 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 return videoList
} }
@ -134,6 +145,27 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") 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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
@ -175,6 +207,14 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesSelector() = popularAnimeSelector() 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( override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"), AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter() GenreFilter()
@ -238,31 +278,23 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
fun toUriPart() = vals[state].second 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) { override fun setupPreferenceScreen(screen: PreferenceScreen) {
val videoQualityPref = ListPreference(screen.context).apply { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Servidor Preferido" title = "Preferred quality"
entries = arrayOf("Amazon", "Fembed:480p", "Fembed:720p", "Amazon", "AmazonES", "FireLoad") entries = arrayOf(
entryValues = arrayOf("Amazon", "Fembed:480p", "Fembed:720p", "Amazon", "AmazonES", "FireLoad") "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") setDefaultValue("Amazon")
summary = "%s" summary = "%s"
@ -275,12 +307,4 @@ class Animefenix : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
screen.addPreference(videoQualityPref) 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 ""
}
} }

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class SolidFilesExtractor(private val client: OkHttpClient) { class SolidFilesExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> return try {
if (script.data().contains("\"downloadUrl\":")) { val document = client.newCall(GET(url)).execute().asJsoup()
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") document.select("script").forEach { script ->
val url = data.replace("\"", "") if (script.data().contains("\"downloadUrl\":")) {
val videoUrl = url val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
val quality = "SolidFiles" val url = data.replace("\"", "")
videoList.add(Video(videoUrl, quality, videoUrl)) val videoUrl = url
val quality = prefix + "SolidFiles"
videoList.add(Video(videoUrl, quality, videoUrl))
}
} }
videoList
} catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -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
}
}
}

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'AnimeFLV' extName = 'AnimeFLV'
pkgNameSuffix = 'es.animeflv' pkgNameSuffix = 'es.animeflv'
extClass = '.AnimeFlv' extClass = '.AnimeFlv'
extVersionCode = 25 extVersionCode = 26
libVersion = '13' libVersion = '13'
} }

View File

@ -33,6 +33,7 @@ import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -104,10 +105,6 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun episodeFromElement(element: Element) = throw Exception("not used") 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> { override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup() val document = response.asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
@ -119,7 +116,6 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val json = servers!!.jsonObject val json = servers!!.jsonObject
val quality = json!!["title"]!!.jsonPrimitive!!.content val quality = json!!["title"]!!.jsonPrimitive!!.content
var url = json!!["code"]!!.jsonPrimitive!!.content var url = json!!["code"]!!.jsonPrimitive!!.content
if (quality == "SB") { if (quality == "SB") {
val headers = headers.newBuilder() val headers = headers.newBuilder()
.set("referer", url) .set("referer", url)
@ -131,29 +127,19 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
.set("watchsb", "streamsb") .set("watchsb", "streamsb")
.set("authority", "embedsb.com") .set("authority", "embedsb.com")
.build() .build()
val videos = StreamSBExtractor(client).videosFromUrl(url, headers) StreamSBExtractor(client).videosFromUrl(url, headers).map { videoList.add(it) }
videoList.addAll(videos)
} }
if (quality == "Fembed") { if (quality == "Fembed") {
val videos = FembedExtractor().videosFromUrl(url) FembedExtractor().videosFromUrl(url).map { videoList.add(it) }
videoList.addAll(videos)
} }
if (quality == "Stape") { if (quality == "Stape") {
val url1 = json!!["url"]!!.jsonPrimitive!!.content val url1 = json!!["url"]!!.jsonPrimitive!!.content
val video = StreamTapeExtractor(client).videoFromUrl(url1, quality) val video = StreamTapeExtractor(client).videoFromUrl(url1, "StreamTape")
if (video != null) { if (video != null) videoList.add(video)
videoList.add(video)
}
} }
if (quality == "Doodstream") { if (quality == "Doodstream") {
val video = try { val video = DoodExtractor(client).videoFromUrl(url, "DoodStream")
DoodExtractor(client).videoFromUrl(url, "DoodStream") if (video != null) videoList.add(video)
} catch (e: Exception) {
null
}
if (video != null) {
videoList.add(video)
}
} }
if (quality == "Okru") { if (quality == "Okru") {
val videos = OkruExtractor(client).videosFromUrl(url) val videos = OkruExtractor(client).videosFromUrl(url)
@ -161,8 +147,7 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
if (quality == "YourUpload") { if (quality == "YourUpload") {
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build() val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
val videos = YourUploadExtractor(client).videoFromUrl(url, headers = headers) YourUploadExtractor(client).videoFromUrl(url, headers = headers).map { videoList.add(it) }
if (!videos.isEmpty()) videoList.addAll(videos)
} }
} }
} }
@ -177,21 +162,24 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Stape") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -304,8 +292,18 @@ class AnimeFlv : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val videoQualityPref = ListPreference(screen.context).apply { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile") entries = arrayOf(
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile") "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") setDefaultValue("Fembed:720p")
summary = "%s" summary = "%s"

View File

@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class DoodExtractor(private val client: OkHttpClient) { class DoodExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String): Video? {
val response = client.newCall(GET(url)).execute() return try {
val doodTld = url.substringAfter("https://dood.").substringBefore("/") val response = client.newCall(GET(url)).execute()
val content = response.body!!.string() val doodTld = url.substringAfter("https://dood.").substringBefore("/")
if (!content.contains("'/pass_md5/")) return null val content = response.body!!.string()
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',") if (!content.contains("'/pass_md5/")) return null
val token = md5.substringAfterLast("/") val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val randomString = getRandomString() val token = md5.substringAfterLast("/")
val expiry = System.currentTimeMillis() val randomString = getRandomString()
val videoUrlStart = client.newCall( val expiry = System.currentTimeMillis()
GET( val videoUrlStart = client.newCall(
"https://dood.$doodTld/pass_md5/$md5", GET(
Headers.headersOf("referer", url) "https://dood.$doodTld/pass_md5/$md5",
) Headers.headersOf("referer", url)
).execute().body!!.string() )
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" ).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld)) Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
} catch (e: IOException) {
null
}
} }
private fun getRandomString(length: Int = 10): String { private fun getRandomString(length: Int = 10): String {

View File

@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { 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 videoList = mutableListOf<Video>()
val prefix = qualityPrefix return try {
if (json.getBoolean("success")) { 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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)) videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = qualityPrefix + "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.animeextension.es.animeflv.extractors package eu.kanade.tachiyomi.animeextension.es.animeflv.extractors
import android.util.Log
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
@ -9,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamSBExtractor(private val client: OkHttpClient) { class StreamSBExtractor(private val client: OkHttpClient) {
private val hexArray = "0123456789ABCDEF".toCharArray() private val hexArray = "0123456789ABCDEF".toCharArray()
private fun bytesToHex(bytes: ByteArray): String { private fun bytesToHex(bytes: ByteArray): String {
@ -25,27 +24,31 @@ class StreamSBExtractor(private val client: OkHttpClient) {
return String(hexChars) return String(hexChars)
} }
fun videosFromUrl(url: String, headers: Headers): List<Video> { 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"
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()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach { return try {
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x") val sbUrl = url.substringBefore("/e/")
.substringBefore(",") + "p" val id = url.substringAfter("/e/").substringBefore(".html")
val videoUrl = it.substringAfter("\n").substringBefore("\n") val bytes = id.toByteArray()
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers)) 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
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -10,7 +10,7 @@ import java.io.IOException
class YourUploadExtractor(private val client: OkHttpClient) { class YourUploadExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, headers: Headers): List<Video> { fun videoFromUrl(url: String, headers: Headers): List<Video> {
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
try { return try {
val document = client.newCall(GET(url)).execute() val document = client.newCall(GET(url)).execute()
if (document.isSuccessful) { if (document.isSuccessful) {
val content = document.asJsoup() val content = document.asJsoup()
@ -21,8 +21,9 @@ class YourUploadExtractor(private val client: OkHttpClient) {
videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers)) videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers))
} }
} }
videoList
} catch (e: IOException) { } catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'AnimeID' extName = 'AnimeID'
pkgNameSuffix = 'es.animeid' pkgNameSuffix = 'es.animeid'
extClass = '.AnimeID' extClass = '.AnimeID'
extVersionCode = 3 extVersionCode = 4
libVersion = '13' libVersion = '13'
} }

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.animeextension.es.animeid
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.animeid.extractors.StreamTapeExtractor 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.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.net.URI import java.net.URI
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Date import java.util.Date
@ -130,9 +130,7 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
var jsonString = script.attr("data") var jsonString = script.attr("data")
val jsonUnescape = unescapeJava(jsonString)!!.replace("\\", "") val jsonUnescape = unescapeJava(jsonString)!!.replace("\\", "")
val url = jsonUnescape!!.substringAfter("src=\"").substringBefore("\"").replace("\\\\", "\\") val url = jsonUnescape!!.substringAfter("src=\"").substringBefore("\"").replace("\\\\", "\\")
Log.i("bruh url", url)
val quality = getDomainName(url) val quality = getDomainName(url)
Log.i("bruh domain", quality.toString())
if (quality == "streamtape") { if (quality == "streamtape") {
val video = StreamTapeExtractor(client).videoFromUrl(url, "Streamtape") val video = StreamTapeExtractor(client).videoFromUrl(url, "Streamtape")
if (video != null) { if (video != null) {
@ -185,21 +183,24 @@ class AnimeID : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Streamtape") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "StreamTape")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { 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") genreFilter.state != 0 -> GET("$baseUrl/genero/${genreFilter.toUriPart()}?pag=$page&sort=newest")
else -> GET("$baseUrl/series?sort=newest&pag=$page") else -> GET("$baseUrl/series?sort=newest&pag=$page")
} }
Log.i("genero", request.url.toString())
return request return request
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'AnimeLatinoHD' extName = 'AnimeLatinoHD'
pkgNameSuffix = 'es.animelatinohd' pkgNameSuffix = 'es.animelatinohd'
extClass = '.AnimeLatinoHD' extClass = '.AnimeLatinoHD'
extVersionCode = 3 extVersionCode = 4
libVersion = '13' libVersion = '13'
} }

View File

@ -36,6 +36,7 @@ import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -221,21 +222,24 @@ class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "[Sub] Fembed:720p") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "[Sub] Fembed:720p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -365,11 +369,24 @@ class AnimeLatinoHD : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector() override fun latestUpdatesNextPageSelector() = popularAnimeNextPageSelector()
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "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") entries = options
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") entryValues = options
setDefaultValue("[Sub] Fembed:720p") setDefaultValue("[Sub] Fembed:720p")
summary = "%s" summary = "%s"

View File

@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class DoodExtractor(private val client: OkHttpClient) { class DoodExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String): Video? {
val response = client.newCall(GET(url)).execute() return try {
val doodTld = url.substringAfter("https://dood.").substringBefore("/") val response = client.newCall(GET(url)).execute()
val content = response.body!!.string() val doodTld = url.substringAfter("https://dood.").substringBefore("/")
if (!content.contains("'/pass_md5/")) return null val content = response.body!!.string()
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',") if (!content.contains("'/pass_md5/")) return null
val token = md5.substringAfterLast("/") val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val randomString = getRandomString() val token = md5.substringAfterLast("/")
val expiry = System.currentTimeMillis() val randomString = getRandomString()
val videoUrlStart = client.newCall( val expiry = System.currentTimeMillis()
GET( val videoUrlStart = client.newCall(
"https://dood.$doodTld/pass_md5/$md5", GET(
Headers.headersOf("referer", url) "https://dood.$doodTld/pass_md5/$md5",
) Headers.headersOf("referer", url)
).execute().body!!.string() )
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" ).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld)) Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
} catch (e: IOException) {
null
}
} }
private fun getRandomString(length: Int = 10): String { private fun getRandomString(length: Int = 10): String {

View File

@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { 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 videoList = mutableListOf<Video>()
val prefix = qualityPrefix return try {
if (json.getBoolean("success")) { 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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)) videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = qualityPrefix + "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class SolidFilesExtractor(private val client: OkHttpClient) { class SolidFilesExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, prefix: String = ""): List<Video> { fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> return try {
if (script.data().contains("\"downloadUrl\":")) { val document = client.newCall(GET(url)).execute().asJsoup()
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") document.select("script").forEach { script ->
val url = data.replace("\"", "") if (script.data().contains("\"downloadUrl\":")) {
val videoUrl = url val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
val quality = prefix + "SolidFiles" val url = data.replace("\"", "")
videoList.add(Video(videoUrl, quality, videoUrl)) val videoUrl = url
val quality = prefix + "SolidFiles"
videoList.add(Video(videoUrl, quality, videoUrl))
}
} }
videoList
} catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamSBExtractor(private val client: OkHttpClient) { class StreamSBExtractor(private val client: OkHttpClient) {
private val hexArray = "0123456789ABCDEF".toCharArray() private val hexArray = "0123456789ABCDEF".toCharArray()
private fun bytesToHex(bytes: ByteArray): String { 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> { 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>() val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach { return try {
val quality = prefix + "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x") val sbUrl = url.substringBefore("/e/")
.substringBefore(",") + "p" val id = url.substringAfter("/e/").substringBefore(".html")
val videoUrl = it.substringAfter("\n").substringBefore("\n") val bytes = id.toByteArray()
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers)) 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
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'AnimeonlineNinja' extName = 'AnimeonlineNinja'
pkgNameSuffix = 'es.animeonlineninja' pkgNameSuffix = 'es.animeonlineninja'
extClass = '.AnimeonlineNinja' extClass = '.AnimeonlineNinja'
extVersionCode = 7 extVersionCode = 8
libVersion = '13' libVersion = '13'
} }

View File

@ -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.JsUnpacker
import eu.kanade.tachiyomi.animeextension.es.animeonlineninja.extractors.StreamSBExtractor 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.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.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -27,6 +27,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -102,7 +103,7 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val iframeLink = apiCall.toString().substringAfter("{\"embed_url\":\"").substringBefore("\"") val iframeLink = apiCall.toString().substringAfter("{\"embed_url\":\"").substringBefore("\"")
val sDocument = client.newCall(GET(iframeLink)).execute().asJsoup() val sDocument = client.newCall(GET(iframeLink)).execute().asJsoup()
sDocument.select("div.ODDIV div").forEach { 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 -> it.select("li").forEach { source ->
val sourceUrl = source.attr("onclick").toString().substringAfter("go_to_player('").substringBefore("')") val sourceUrl = source.attr("onclick").toString().substringAfter("go_to_player('").substringBefore("')")
serverslangParse(sourceUrl, lang).map { video -> videoList.add(video) } 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 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 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) } serverslangParse(sourceUrl, lang2).map { video -> videoList.add(video) }
} }
} }
@ -184,8 +185,8 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
serverUrl.contains("uqload") && lang.contains(langSelect) -> { serverUrl.contains("uqload") && lang.contains(langSelect) -> {
val headers = headers.newBuilder().add("referer", "https://uqload.com/").build() val headers = headers.newBuilder().add("referer", "https://uqload.com/").build()
val video = uploadExtractor(client).videofromurl(serverUrl, headers, lang) val video = UploadExtractor(client).videoFromUrl(serverUrl, headers, lang)
videos.add(video) 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 videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Mixdrop") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "SUB Fembed:1080p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -337,7 +341,7 @@ class AnimeonlineNinja : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("SUB Fembed:480p", "SUB Fembed:720p", "SUB Fembed:1080p") entries = arrayOf("SUB Fembed:480p", "SUB Fembed:720p", "SUB Fembed:1080p")
entryValues = 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" summary = "%s"
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->

View File

@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class DoodExtractor(private val client: OkHttpClient) { class DoodExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String): Video? {
val response = client.newCall(GET(url)).execute() return try {
val doodTld = url.substringAfter("https://dood.").substringBefore("/") val response = client.newCall(GET(url)).execute()
val content = response.body!!.string() val doodTld = url.substringAfter("https://dood.").substringBefore("/")
if (!content.contains("'/pass_md5/")) return null val content = response.body!!.string()
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',") if (!content.contains("'/pass_md5/")) return null
val token = md5.substringAfterLast("/") val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val randomString = getRandomString() val token = md5.substringAfterLast("/")
val expiry = System.currentTimeMillis() val randomString = getRandomString()
val videoUrlStart = client.newCall( val expiry = System.currentTimeMillis()
GET( val videoUrlStart = client.newCall(
"https://dood.$doodTld/pass_md5/$md5", GET(
Headers.headersOf("referer", url) "https://dood.$doodTld/pass_md5/$md5",
) Headers.headersOf("referer", url)
).execute().body!!.string() )
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" ).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld)) Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
} catch (e: IOException) {
null
}
} }
private fun getRandomString(length: Int = 10): String { private fun getRandomString(length: Int = 10): String {

View File

@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { 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 videoList = mutableListOf<Video>()
val prefix = qualityPrefix return try {
if (json.getBoolean("success")) { 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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)) videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class SolidFilesExtractor(private val client: OkHttpClient) { class SolidFilesExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> return try {
if (script.data().contains("\"downloadUrl\":")) { val document = client.newCall(GET(url)).execute().asJsoup()
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") document.select("script").forEach { script ->
val url = data.replace("\"", "") if (script.data().contains("\"downloadUrl\":")) {
val videoUrl = url val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
val quality = "SolidFiles" val url = data.replace("\"", "")
videoList.add(Video(videoUrl, quality, videoUrl)) val videoUrl = url
val quality = prefix + "SolidFiles"
videoList.add(Video(videoUrl, quality, videoUrl))
}
} }
videoList
} catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamSBExtractor(private val client: OkHttpClient) { class StreamSBExtractor(private val client: OkHttpClient) {
private val hexArray = "0123456789ABCDEF".toCharArray() private val hexArray = "0123456789ABCDEF".toCharArray()
private fun bytesToHex(bytes: ByteArray): String { private fun bytesToHex(bytes: ByteArray): String {
@ -24,27 +24,31 @@ class StreamSBExtractor(private val client: OkHttpClient) {
return String(hexChars) return String(hexChars)
} }
fun videosFromUrl(url: String, headers: Headers): List<Video> { 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>() val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach { return try {
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x") val sbUrl = url.substringBefore("/e/")
.substringBefore(",") + "p" val id = url.substringAfter("/e/").substringBefore(".html")
val videoUrl = it.substringAfter("\n").substringBefore("\n") val bytes = id.toByteArray()
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers)) 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
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -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
}
}
}

View File

@ -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)
}
}

View File

@ -5,7 +5,7 @@ ext {
extName = 'Animeyt' extName = 'Animeyt'
pkgNameSuffix = 'es.animeyt' pkgNameSuffix = 'es.animeyt'
extClass = '.Animeyt' extClass = '.Animeyt'
extVersionCode = 3 extVersionCode = 4
libVersion = '13' libVersion = '13'
} }

View File

@ -22,6 +22,7 @@ import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class Animeyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Animeyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -98,21 +99,24 @@ class Animeyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "fastream") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fastream:720p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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") 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile") entries = arrayOf("Fastream:720p", "Fastream:480p", "Fastream:360p")
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile") entryValues = arrayOf("Fastream:720p", "Fastream:480p", "Fastream:360p")
setDefaultValue("fastream") setDefaultValue("Fastream:720p")
summary = "%s" summary = "%s"
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->

View File

@ -1,12 +1,19 @@
package eu.kanade.tachiyomi.animeextension.es.animeyt.extractors package eu.kanade.tachiyomi.animeextension.es.animeyt.extractors
import android.util.Log
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup 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 okhttp3.OkHttpClient
import uy.kohesive.injekt.injectLazy
import java.io.IOException import java.io.IOException
class FastreamExtractor(private val client: OkHttpClient) { class FastreamExtractor(private val client: OkHttpClient) {
private val json: Json by injectLazy()
private fun fetchUrls(text: String?): List<String> { private fun fetchUrls(text: String?): List<String> {
if (text.isNullOrEmpty()) return listOf() if (text.isNullOrEmpty()) return listOf()
val linkRegex = "(http|ftp|https):\\/\\/([\\w_-]+(?:(?:\\.[\\w_-]+)+))([\\w.,@?^=%&:\\/~+#-]*[\\w@?^=%&\\/~+#-])".toRegex() 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)) videoList.add(Video(basicUrl, server, basicUrl, headers = null))
} else { } else {
val packedRegex = Regex("eval\\(function\\(p,a,c,k,e,.*\\)\\)") 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 -> packedRegex.findAll(it!!.data()).map { packed -> packed.value }.toList().map { eval ->
val fastreamRegex = "fastream.*?\\.m3u8([^&\">]?)".toRegex()
val unpack = JsUnpacker.unpack(eval) val unpack = JsUnpacker.unpack(eval)
fetchUrls(unpack!!.first()).map { url -> fetchUrls(unpack!!.first()).map { url ->
val fastreamRegex = "fastream.*?\\.m3u8([^&\">]?)".toRegex()
if (fastreamRegex.containsMatchIn(url)) { 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))
}
}
} }
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'AsiaLiveAction' extName = 'AsiaLiveAction'
pkgNameSuffix = 'es.asialiveaction' pkgNameSuffix = 'es.asialiveaction'
extClass = '.AsiaLiveAction' extClass = '.AsiaLiveAction'
extVersionCode = 3 extVersionCode = 4
libVersion = '13' libVersion = '13'
} }

View File

@ -23,6 +23,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
import java.util.Calendar import java.util.Calendar
@ -59,10 +60,10 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun animeDetailsParse(document: Document): SAnime { override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.thumbnail_url = document.selectFirst("header div.Image figure img").attr("src").trim().replace("//", "https://") 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.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() } anime.genre = document.select("div.asia-post-main 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() val year = document.select("header div.asia-post-main p.Info span.Date a").text().toInt()
val currentYear = Calendar.getInstance().get(Calendar.YEAR) val currentYear = Calendar.getInstance().get(Calendar.YEAR)
anime.status = when { anime.status = when {
(year < currentYear) -> SAnime.COMPLETED (year < currentYear) -> SAnime.COMPLETED
@ -80,13 +81,13 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun episodeFromElement(element: Element): SEpisode { override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create() 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.setUrlWithoutDomain(element.attr("href"))
episode.episode_number = when { episode.episode_number = when {
(epNum.isNotEmpty()) -> epNum.toFloat() (epNum.isNotEmpty()) -> epNum.toFloat()
else -> 1F 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 return episode
} }
@ -98,9 +99,10 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val document = response.asJsoup() val document = response.asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> 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() 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 url = content.substringAfter(",['SB','").substringBefore("',0,0]")
val headers = headers.newBuilder() val headers = headers.newBuilder()
.set("Referer", url) .set("Referer", url)
@ -136,21 +138,24 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Fembed:1080p") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:1080p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -218,11 +223,16 @@ class AsiaLiveAction : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesSelector() = popularAnimeSelector() override fun latestUpdatesSelector() = popularAnimeSelector()
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile") entries = qualities
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Stape", "hd", "sd", "low", "lowest", "mobile") entryValues = qualities
setDefaultValue("Fembed:1080p") setDefaultValue("Fembed:1080p")
summary = "%s" summary = "%s"

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamSBExtractor(private val client: OkHttpClient) { class StreamSBExtractor(private val client: OkHttpClient) {
private val hexArray = "0123456789ABCDEF".toCharArray() private val hexArray = "0123456789ABCDEF".toCharArray()
private fun bytesToHex(bytes: ByteArray): String { private fun bytesToHex(bytes: ByteArray): String {
@ -24,26 +24,30 @@ class StreamSBExtractor(private val client: OkHttpClient) {
return String(hexChars) return String(hexChars)
} }
fun videosFromUrl(url: String, headers: Headers): List<Video> { 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/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()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach { return try {
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x") val sbUrl = url.substringBefore("/e/")
.substringBefore(",") + "p" val id = url.substringAfter("/e/").substringBefore(".html")
val videoUrl = it.substringAfter("\n").substringBefore("\n") val bytes = id.toByteArray()
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers)) 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
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Doramasyt' extName = 'Doramasyt'
pkgNameSuffix = 'es.doramasyt' pkgNameSuffix = 'es.doramasyt'
extClass = '.Doramasyt' extClass = '.Doramasyt'
extVersionCode = 2 extVersionCode = 3
libVersion = '13' libVersion = '13'
} }

View File

@ -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.OkruExtractor
import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.SolidFilesExtractor 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.StreamTapeExtractor
import eu.kanade.tachiyomi.animeextension.es.doramasyt.extractors.UqloadExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -25,6 +26,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -91,26 +93,33 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val server = players.text() val server = players.text()
val urlEncoded = players.attr("data-player") val urlEncoded = players.attr("data-player")
val byte = android.util.Base64.decode(urlEncoded, android.util.Base64.DEFAULT) val byte = android.util.Base64.decode(urlEncoded, android.util.Base64.DEFAULT)
val url = String(byte, charset("UTF-8")).replace("https://doramasyt.com/reproductor?url=", "") val url = String(byte, charset("UTF-8")).substringAfter("?url=")
Log.i("bruh server", url) if (server.contains("fembed")) {
if (server == "fembed") {
val videos = FembedExtractor().videosFromUrl(url) val videos = FembedExtractor().videosFromUrl(url)
videoList.addAll(videos) videoList.addAll(videos)
} }
if (server == "streamtape") { if (server.contains("streamtape")) {
val video = StreamTapeExtractor(client).videoFromUrl(url, "Streamtape") val video = StreamTapeExtractor(client).videoFromUrl(url)
if (video != null) { if (video != null) {
videoList.add(video) videoList.add(video)
} }
} }
if (server == "ok") { if (server.contains("ok")) {
val videos = OkruExtractor(client).videosFromUrl(url) val videos = OkruExtractor(client).videosFromUrl(url)
videoList.addAll(videos) videoList.addAll(videos)
} }
if (server == "zeus") { if (server.contains("zeus")) {
val videos = SolidFilesExtractor(client).videosFromUrl(url) val videos = SolidFilesExtractor(client).videosFromUrl(url)
videoList.addAll(videos) 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 return videoList
} }
@ -122,21 +131,24 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "fembed") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { 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") genreFilter.state != 0 -> GET("$baseUrl/doramas?categoria=false&genero=${genreFilter.toUriPart()}&fecha=false&letra=false&p=$page")
else -> GET("$baseUrl/doramas/?p=$page") else -> GET("$baseUrl/doramas/?p=$page")
} }
// GET("$baseUrl/buscar?q=$query&p=$page")
} }
override fun searchAnimeFromElement(element: Element): SAnime { override fun searchAnimeFromElement(element: Element): SAnime {
@ -267,11 +278,16 @@ class Doramasyt : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "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") entries = qualities
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "Streamtape", "SolidFiles", "Okru: mobile", "Okru: lowest", "Okru: low", "Okru: sd", "Okru: hd") entryValues = qualities
setDefaultValue("Fembed:720p") setDefaultValue("Fembed:720p")
summary = "%s" summary = "%s"

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -4,19 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class SolidFilesExtractor(private val client: OkHttpClient) { class SolidFilesExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> return try {
if (script.data().contains("\"downloadUrl\":")) { val document = client.newCall(GET(url)).execute().asJsoup()
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") document.select("script").forEach { script ->
val videoUrl = data.replace("\"", "") if (script.data().contains("\"downloadUrl\":")) {
val quality = "SolidFiles" val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
videoList.add(Video(videoUrl, quality, videoUrl)) val url = data.replace("\"", "")
val videoUrl = url
val quality = prefix + "SolidFiles"
videoList.add(Video(videoUrl, quality, videoUrl))
}
} }
videoList
} catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -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
}
}
}

View File

@ -5,7 +5,7 @@ ext {
extName = 'Hentaijk' extName = 'Hentaijk'
pkgNameSuffix = 'es.hentaijk' pkgNameSuffix = 'es.hentaijk'
extClass = '.Hentaijk' extClass = '.Hentaijk'
extVersionCode = 3 extVersionCode = 4
libVersion = '13' libVersion = '13'
containsNsfw = true containsNsfw = true
} }

View File

@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.animeextension.es.hentaijk
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.hentaijk.extractors.FembedExtractor import eu.kanade.tachiyomi.animeextension.es.hentaijk.extractors.FembedExtractor
@ -26,6 +25,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -75,12 +75,10 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
?.replace("#pag", "") ?.replace("#pag", "")
val firstPage = pageNumber.first()?.attr("href") val firstPage = pageNumber.first()?.attr("href")
?.replace("#pag", "") ?.replace("#pag", "")
Log.i("bruh", "ULTIMA: $lastPage")
if (firstPage != lastPage) { if (firstPage != lastPage) {
var checkLast = 0 var checkLast = 0
for (i in 1 until lastPage?.toInt()!!) { for (i in 1 until lastPage?.toInt()!!) {
Log.i("bruh", "aaa")
for (j in 1..12) { for (j in 1..12) {
// Log.i("bruh", (j + checkLast).toString()) // Log.i("bruh", (j + checkLast).toString())
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
@ -96,7 +94,6 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Jsoup.connect("https://hentaijk.com/ajax/pagination_episodes/$animeId/$lastPage").get() Jsoup.connect("https://hentaijk.com/ajax/pagination_episodes/$animeId/$lastPage").get()
.body().select("body").text().replace("}]", "").split("}").forEach { json -> .body().select("body").text().replace("}]", "").split("}").forEach { json ->
val number = json.substringAfter("\"number\":\"").substringBefore("\"") val number = json.substringAfter("\"number\":\"").substringBefore("\"")
Log.i("bruh", number)
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
episode_number = number.toFloat() episode_number = number.toFloat()
name = "Episodio $number" name = "Episodio $number"
@ -111,7 +108,6 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Jsoup.connect("https://hentaijk.com/ajax/pagination_episodes/$animeId/$lastPage").get() Jsoup.connect("https://hentaijk.com/ajax/pagination_episodes/$animeId/$lastPage").get()
.body().select("body").text().replace("}]", "").split("}").forEach { json -> .body().select("body").text().replace("}]", "").split("}").forEach { json ->
val number = json.substringAfter("\"number\":\"").substringBefore("\"") val number = json.substringAfter("\"number\":\"").substringBefore("\"")
Log.i("bruh", number)
val episode = SEpisode.create().apply { val episode = SEpisode.create().apply {
episode_number = number.toFloat() episode_number = number.toFloat()
name = "Episodio $number" name = "Episodio $number"
@ -210,21 +206,24 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Sabrosio") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Sabrosio")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -262,7 +261,7 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val animeList = mutableListOf<SAnime>() val animeList = mutableListOf<SAnime>()
val document = jsonLine.asJsoup() val document = jsonLine.asJsoup()
val hasNextPage = document.select("section.contenido.spad div.container div.navigation a.nav-next").any() 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() val isFilterLayer = document.select(".card.mb-3.custom_item2").any()
if (isSearchLayer) { if (isSearchLayer) {
document.select(".col-lg-2.col-md-6.col-sm-6").forEach { animeData -> document.select(".col-lg-2.col-md-6.col-sm-6").forEach { animeData ->
@ -288,7 +287,6 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
animeList.add(anime) animeList.add(anime)
} }
} }
Log.i("bruh parseSearchJson", hasNextPage.toString())
return AnimesPage(animeList, hasNextPage) return AnimesPage(animeList, hasNextPage)
} }
@ -443,11 +441,16 @@ class Hentaijk : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "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") entries = qualities
entryValues = arrayOf("Sabrosio", "Desu", "Xtreme S", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile") entryValues = qualities
setDefaultValue("Sabrosio") setDefaultValue("Sabrosio")
summary = "%s" summary = "%s"

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Hentaila' extName = 'Hentaila'
pkgNameSuffix = 'es.hentaila' pkgNameSuffix = 'es.hentaila'
extClass = '.Hentaila' extClass = '.Hentaila'
extVersionCode = 6 extVersionCode = 7
libVersion = '13' libVersion = '13'
containsNsfw = true containsNsfw = true
} }

View File

@ -30,6 +30,7 @@ import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -120,21 +121,24 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Fembed:480p") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:1080p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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) @OptIn(ExperimentalSerializationApi::class)
@ -251,12 +255,16 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("Arc", "Fembed:480p", "Fembed:720p", "Fembed:1080p") entries = qualities
entryValues = arrayOf("Arc", "Fembed:480p", "Fembed:720p", "Fembed:1080p") entryValues = qualities
setDefaultValue("Fembed:480p") setDefaultValue("Fembed:1080p")
summary = "%s" summary = "%s"
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Jkanime' extName = 'Jkanime'
pkgNameSuffix = 'es.jkanime' pkgNameSuffix = 'es.jkanime'
extClass = '.Jkanime' extClass = '.Jkanime'
extVersionCode = 4 extVersionCode = 5
libVersion = '13' libVersion = '13'
} }

View File

@ -26,6 +26,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -205,21 +206,24 @@ class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Nozomi") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Nozomi")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -437,11 +441,16 @@ class Jkanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "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") entries = qualities
entryValues = arrayOf("Nozomi", "Desu", "Xtreme S", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile") entryValues = qualities
setDefaultValue("Nozomi") setDefaultValue("Nozomi")
summary = "%s" summary = "%s"

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Jkhentai' extName = 'Jkhentai'
pkgNameSuffix = 'es.jkhentai' pkgNameSuffix = 'es.jkhentai'
extClass = '.Jkhentai' extClass = '.Jkhentai'
extVersionCode = 5 extVersionCode = 6
libVersion = '13' libVersion = '13'
containsNsfw = true containsNsfw = true
} }

View File

@ -5,6 +5,7 @@ import android.content.SharedPreferences
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.jkhentai.extractors.StreamTapeExtractor 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.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -21,6 +22,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -91,6 +93,11 @@ class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
videoList.add(video) 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 return videoList
@ -103,21 +110,24 @@ class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "StreamTape") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "StreamTape")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -219,8 +229,8 @@ class Jkhentai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val videoQualityPref = ListPreference(screen.context).apply { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("StreamTape") entries = arrayOf("StreamTape", "YourUpload")
entryValues = arrayOf("StreamTape") entryValues = arrayOf("StreamTape", "YourUpload")
setDefaultValue("StreamTape") setDefaultValue("StreamTape")
summary = "%s" summary = "%s"

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -4,20 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class SolidFilesExtractor(private val client: OkHttpClient) { class SolidFilesExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> return try {
if (script.data().contains("\"downloadUrl\":")) { val document = client.newCall(GET(url)).execute().asJsoup()
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") document.select("script").forEach { script ->
val url = data.replace("\"", "") if (script.data().contains("\"downloadUrl\":")) {
val videoUrl = url val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
val quality = "SolidFiles" val url = data.replace("\"", "")
videoList.add(Video(videoUrl, quality, videoUrl)) val videoUrl = url
val quality = prefix + "SolidFiles"
videoList.add(Video(videoUrl, quality, videoUrl))
}
} }
videoList
} catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -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
}
}
}

View File

@ -5,7 +5,7 @@ ext {
extName = 'MonosChinos' extName = 'MonosChinos'
pkgNameSuffix = 'es.monoschinos' pkgNameSuffix = 'es.monoschinos'
extClass = '.MonosChinos' extClass = '.MonosChinos'
extVersionCode = 12 extVersionCode = 13
libVersion = '13' libVersion = '13'
} }

View File

@ -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.FembedExtractor
import eu.kanade.tachiyomi.animeextension.es.monoschinos.extractors.OkruExtractor 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.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.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -25,6 +25,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -52,7 +53,7 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
return SAnime.create().apply { return SAnime.create().apply {
setUrlWithoutDomain(element.select("a").attr("href")) setUrlWithoutDomain(element.select("a").attr("href"))
title = element.select("a div.series div.seriesdetails h3").text() 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") thumbDiv.attr("data-src")
} else { } else {
thumbDiv.attr("src") thumbDiv.attr("src")
@ -91,7 +92,10 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
url.contains("fembed") -> videoList.addAll(FembedExtractor().videosFromUrl(url)) url.contains("fembed") -> videoList.addAll(FembedExtractor().videosFromUrl(url))
url.contains("ok") -> if (!url.contains("streamcherry")) videoList.addAll(OkruExtractor(client).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("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 return videoList
@ -104,21 +108,24 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "SolidFiles") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { 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") else -> GET("$baseUrl/animes?categoria=false&genero=${genreFilter.toUriPart()}&fecha=$yearFilter&letra=$letterFilter&p=$page")
} }
} }
override fun searchAnimeFromElement(element: Element): SAnime { override fun searchAnimeFromElement(element: Element): SAnime {
return popularAnimeFromElement(element) return popularAnimeFromElement(element)
} }
@ -242,11 +250,16 @@ class MonosChinos : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile") entries = qualities
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile") entryValues = qualities
setDefaultValue("Fembed:720p") setDefaultValue("Fembed:720p")
summary = "%s" summary = "%s"

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,23 +4,37 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class OkruExtractor(private val client: OkHttpClient) { class OkruExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
val videosString = document.select("div[data-options]").attr("data-options") return try {
.substringAfter("\\\"videos\\\":[{\\\"name\\\":\\\"") val document = client.newCall(GET(url)).execute().asJsoup()
.substringBefore("]") val qualities = listOf(
videosString.split("{\\\"name\\\":\\\"").reversed().forEach { Pair("full", "1080p"),
val videoUrl = it.substringAfter("url\\\":\\\"") Pair("hd", "720p"),
.substringBefore("\\\"") Pair("sd", "480p"),
.replace("\\\\u0026", "&") Pair("low", "360p"),
val videoQuality = "Okru: " + it.substringBefore("\\\"") Pair("lowest", "240p"),
if (videoUrl.startsWith("https://")) { Pair("mobile", "144p")
videoList.add(Video(videoUrl, videoQuality, videoUrl)) )
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
} }
} }

View File

@ -4,19 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class SolidFilesExtractor(private val client: OkHttpClient) { class SolidFilesExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, prefix: String = ""): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
document.select("script").forEach { script -> return try {
if (script.data().contains("\"downloadUrl\":")) { val document = client.newCall(GET(url)).execute().asJsoup()
val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",") document.select("script").forEach { script ->
val videoUrl = data.replace("\"", "") if (script.data().contains("\"downloadUrl\":")) {
val quality = "SolidFiles" val data = script.data().substringAfter("\"downloadUrl\":").substringBefore(",")
videoList.add(Video(videoUrl, quality, videoUrl)) val url = data.replace("\"", "")
val videoUrl = url
val quality = prefix + "SolidFiles"
videoList.add(Video(videoUrl, quality, videoUrl))
}
} }
videoList
} catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -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
}
}
}

View File

@ -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)
}
}
}

View File

@ -5,7 +5,7 @@ ext {
extName = 'MundoDonghua' extName = 'MundoDonghua'
pkgNameSuffix = 'es.mundodonghua' pkgNameSuffix = 'es.mundodonghua'
extClass = '.MundoDonghua' extClass = '.MundoDonghua'
extVersionCode = 3 extVersionCode = 4
libVersion = '13' libVersion = '13'
} }

View File

@ -23,6 +23,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -113,8 +114,7 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
fetchUrls(unpack!!.first()).map { url -> fetchUrls(unpack!!.first()).map { url ->
if (url.contains("diasfem")) { if (url.contains("diasfem")) {
var serverUrl = url.replace("diasfem", "embedsito") var serverUrl = url.replace("diasfem", "embedsito")
var videos = FembedExtractor().videosFromUrl(serverUrl) FembedExtractor().videosFromUrl(serverUrl).map { vid -> videoList.add(vid) }
videoList.addAll(videos)
} }
} }
if (unpack!!.first()!!.contains("protea_tab")) { if (unpack!!.first()!!.contains("protea_tab")) {
@ -138,9 +138,7 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
.set("referer", response!!.request!!.url!!.toString()) .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") .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() .build()
ProteaExtractor().videosFromUrl(requestlink, "Protea", headers = headers, baseUrl).forEach { ProteaExtractor().videosFromUrl(requestlink, "Protea", headers = headers).map { vid -> videoList.add(vid) }
videoList.add(it)
}
} }
} }
} }
@ -155,23 +153,24 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun videoFromElement(element: Element) = throw Exception("not used") override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
var quality = preferences.getString("preferred_quality", "Protea:720p") return try {
if (quality == null) quality = preferences.getString("preferred_quality", "Fembed:720p") val videoSorted = this.sortedWith(
compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
if (quality != null) { ).toTypedArray()
val newList = mutableListOf<Video>() val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
var preferred = 0 val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
for (video in this) { if (preferredIdx != -1) {
if (video.quality == quality) { videoSorted.drop(preferredIdx + 1)
newList.add(preferred, video) videoSorted[0] = videoSorted[preferredIdx]
preferred++
} else {
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -271,11 +270,15 @@ class MundoDonghua : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesSelector() = popularAnimeSelector() override fun latestUpdatesSelector() = popularAnimeSelector()
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "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") entries = qualities
entryValues = arrayOf("Protea:1080p", "Protea:720p", "Protea:480p", "Protea:380p", "Protea:360p", "Fembed:1080p", "Fembed:720p", "Fembed:480p", "Fembed:380p", "Fembed:360p") entryValues = qualities
setDefaultValue("Fembed:720p") setDefaultValue("Fembed:720p")
summary = "%s" summary = "%s"

View File

@ -4,28 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { 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 videoList = mutableListOf<Video>()
val prefix = qualityPrefix return try {
if (json.getBoolean("success")) { 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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)) videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -15,7 +15,7 @@ import java.io.IOException
class ProteaExtractor() { class ProteaExtractor() {
private val json: Json by injectLazy() 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>() val videoList = mutableListOf<Video>()
try { try {
val document = Jsoup.connect(url).headers(headers.toMap()).ignoreContentType(true).method(Connection.Method.POST).execute() val document = Jsoup.connect(url).headers(headers.toMap()).ignoreContentType(true).method(Connection.Method.POST).execute()
@ -49,15 +49,4 @@ class ProteaExtractor() {
} }
return videoList 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"
}
}
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Pelisflix' extName = 'Pelisflix'
pkgNameSuffix = 'es.pelisflix' pkgNameSuffix = 'es.pelisflix'
extClass = '.PelisflixFactory' extClass = '.PelisflixFactory'
extVersionCode = 1 extVersionCode = 2
libVersion = '13' libVersion = '13'
} }

View File

@ -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 videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "LAT Nupload") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "LAT Nupload")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {

View File

@ -1,5 +1,9 @@
package eu.kanade.tachiyomi.animeextension.es.pelisflix 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.DoodExtractor
import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.FembedExtractor import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.FembedExtractor
import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.StreamTapeExtractor import eu.kanade.tachiyomi.animeextension.es.pelisflix.extractors.StreamTapeExtractor
@ -18,6 +22,9 @@ import okhttp3.RequestBody
import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
class PelisflixFactory : AnimeSourceFactory { class PelisflixFactory : AnimeSourceFactory {
override fun createSources(): List<AnimeSource> = listOf(PelisflixClass(), SeriesflixClass()) 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" 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 { override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").attr("href")) 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()) { AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second 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)
}
} }

View File

@ -7,24 +7,27 @@ import okhttp3.OkHttpClient
import java.io.IOException import java.io.IOException
class DoodExtractor(private val client: OkHttpClient) { class DoodExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, qualityPrefix: String = ""): Video? { fun videoFromUrl(url: String, quality: String): Video? {
val response = client.newCall(GET(url)).execute() return try {
val doodTld = url.substringAfter("https://dood.").substringBefore("/") val response = client.newCall(GET(url)).execute()
val content = response.body!!.string() val doodTld = url.substringAfter("https://dood.").substringBefore("/")
if (!content.contains("'/pass_md5/")) return null val content = response.body!!.string()
val quality = try { "\\d{3,4}p".toRegex().find(content)!!.value.trim() } catch (e: IOException) { "" } if (!content.contains("'/pass_md5/")) return null
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',") val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val token = md5.substringAfterLast("/") val token = md5.substringAfterLast("/")
val randomString = getRandomString() val randomString = getRandomString()
val expiry = System.currentTimeMillis() val expiry = System.currentTimeMillis()
val videoUrlStart = client.newCall( val videoUrlStart = client.newCall(
GET( GET(
"https://dood.$doodTld/pass_md5/$md5", "https://dood.$doodTld/pass_md5/$md5",
Headers.headersOf("referer", url) Headers.headersOf("referer", url)
) )
).execute().body!!.string() ).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return Video(url, "$qualityPrefix Doodstream:$quality", videoUrl, headers = doodHeaders(doodTld)) Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
} catch (e: IOException) {
null
}
} }
private fun getRandomString(length: Int = 10): String { private fun getRandomString(length: Int = 10): String {

View File

@ -4,27 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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)) videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'Pelisplushd' extName = 'Pelisplushd'
pkgNameSuffix = 'es.pelisplushd' pkgNameSuffix = 'es.pelisplushd'
extClass = '.Pelisplushd' extClass = '.Pelisplushd'
extVersionCode = 15 extVersionCode = 16
libVersion = '13' libVersion = '13'
} }

View File

@ -32,6 +32,7 @@ import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy import uy.kohesive.injekt.injectLazy
import java.io.IOException
import java.lang.Exception import java.lang.Exception
class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() { class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@ -179,7 +180,7 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val epId = amazonApiJson.toString().substringAfter("\"id\":\"").substringBefore("\"") 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 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("\"") 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 videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "StreamTape") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Voex")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
@ -313,12 +317,18 @@ class Pelisplushd : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
} }
override fun setupPreferenceScreen(screen: PreferenceScreen) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("StreamSB:360p", "StreamSB:720p", "StreamSB:1080p", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "DoodStream") entries = qualities
entryValues = arrayOf("StreamSB:360p", "StreamSB:720p", "StreamSB:1080p", "Fembed:480p", "Fembed:720p", "Fembed:1080p", "DoodStream") entryValues = qualities
setDefaultValue("DoodStream") setDefaultValue("Voex")
summary = "%s" summary = "%s"
setOnPreferenceChangeListener { _, newValue -> setOnPreferenceChangeListener { _, newValue ->

View File

@ -4,26 +4,30 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class DoodExtractor(private val client: OkHttpClient) { class DoodExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String): Video? {
val response = client.newCall(GET(url)).execute() return try {
val doodTld = url.substringAfter("https://dood.").substringBefore("/") val response = client.newCall(GET(url)).execute()
val content = response.body!!.string() val doodTld = url.substringAfter("https://dood.").substringBefore("/")
if (!content.contains("'/pass_md5/")) return null val content = response.body!!.string()
val md5 = content.substringAfter("'/pass_md5/").substringBefore("',") if (!content.contains("'/pass_md5/")) return null
val token = md5.substringAfterLast("/") val md5 = content.substringAfter("'/pass_md5/").substringBefore("',")
val randomString = getRandomString() val token = md5.substringAfterLast("/")
val expiry = System.currentTimeMillis() val randomString = getRandomString()
val videoUrlStart = client.newCall( val expiry = System.currentTimeMillis()
GET( val videoUrlStart = client.newCall(
"https://dood.$doodTld/pass_md5/$md5", GET(
Headers.headersOf("referer", url) "https://dood.$doodTld/pass_md5/$md5",
) Headers.headersOf("referer", url)
).execute().body!!.string() )
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry" ).execute().body!!.string()
val videoUrl = "$videoUrlStart$randomString?token=$token&expiry=$expiry"
return Video(url, quality, videoUrl, headers = doodHeaders(doodTld)) Video(url, quality, videoUrl, headers = doodHeaders(doodTld))
} catch (e: IOException) {
null
}
} }
private fun getRandomString(length: Int = 10): String { private fun getRandomString(length: Int = 10): String {

View File

@ -4,23 +4,25 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class FembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String): List<Video> { fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val videoApi = url.replace("/v/", "/api/source/") val videoList = mutableListOf<Video>()
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body()) return try {
return if (json.getBoolean("success")) { 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i) val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file") 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.add(Video(videoUrl, quality, videoUrl))
} }
videoList.reversed() videoList
} else { } catch (e: IOException) {
emptyList() videoList
} }
} }
} }

View File

@ -8,9 +8,9 @@ import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.jsonObject import kotlinx.serialization.json.jsonObject
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamSBExtractor(private val client: OkHttpClient) { class StreamSBExtractor(private val client: OkHttpClient) {
private val hexArray = "0123456789ABCDEF".toCharArray() private val hexArray = "0123456789ABCDEF".toCharArray()
private fun bytesToHex(bytes: ByteArray): String { private fun bytesToHex(bytes: ByteArray): String {
@ -24,25 +24,31 @@ class StreamSBExtractor(private val client: OkHttpClient) {
return String(hexChars) return String(hexChars)
} }
fun videosFromUrl(url: String, headers: Headers): List<Video> { fun videosFromUrl(url: String, headers: Headers, prefix: String = ""): 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()
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach { return try {
val quality = "StreamSB:" + it.substringAfter("RESOLUTION=").substringAfter("x") val sbUrl = url.substringBefore("/e/")
.substringBefore(",") + "p" val id = url.substringAfter("/e/").substringBefore(".html")
val videoUrl = it.substringAfter("\n").substringBefore("\n") val bytes = id.toByteArray()
videoList.add(Video(videoUrl, quality, videoUrl, headers = headers)) 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
} }
} }

View File

@ -4,15 +4,21 @@ import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import java.io.IOException
class StreamTapeExtractor(private val client: OkHttpClient) { class StreamTapeExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, quality: String): Video? { fun videoFromUrl(url: String, quality: String = "StreamTape"): Video? {
val document = client.newCall(GET(url)).execute().asJsoup() return try {
val script = document.select("script:containsData(document.getElementById('robotlink'))") val linkRegex = "https?://(www\\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}/[a-z]/".toRegex()
.firstOrNull()?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '") val mainUrl = "https://streamtape.com/e/${ url.replace(linkRegex, "") }"
?: return null val document = client.newCall(GET(mainUrl)).execute().asJsoup()
val videoUrl = "https:" + script.substringBefore("'") + val script = document.selectFirst("script:containsData(document.getElementById('robotlink'))")
script.substringAfter("+ ('xcd").substringBefore("'") ?.data()?.substringAfter("document.getElementById('robotlink').innerHTML = '//")
return Video(url, quality, videoUrl) ?: return null
val videoUrl = "https://" + script.substringBefore("'+ ('xcd") + script.substringAfter("+ ('xcd").substringBefore("')")
Video(videoUrl, quality, videoUrl, headers = null)
} catch (i: IOException) {
null
}
} }
} }

View File

@ -10,7 +10,7 @@ import java.io.IOException
class YourUploadExtractor(private val client: OkHttpClient) { class YourUploadExtractor(private val client: OkHttpClient) {
fun videoFromUrl(url: String, headers: Headers): List<Video> { fun videoFromUrl(url: String, headers: Headers): List<Video> {
val videoList = mutableListOf<Video>() val videoList = mutableListOf<Video>()
try { return try {
val document = client.newCall(GET(url)).execute() val document = client.newCall(GET(url)).execute()
if (document.isSuccessful) { if (document.isSuccessful) {
val content = document.asJsoup() val content = document.asJsoup()
@ -21,8 +21,9 @@ class YourUploadExtractor(private val client: OkHttpClient) {
videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers)) videoList.add(Video(basicUrl, "YourUpload", basicUrl, headers = headers))
} }
} }
videoList
} catch (e: IOException) { } catch (e: IOException) {
videoList
} }
return videoList
} }
} }

View File

@ -5,7 +5,7 @@ ext {
extName = 'TioanimeH' extName = 'TioanimeH'
pkgNameSuffix = 'es.tioanimeh' pkgNameSuffix = 'es.tioanimeh'
extClass = '.TioanimeHFactory' extClass = '.TioanimeHFactory'
extVersionCode = 5 extVersionCode = 6
libVersion = '13' libVersion = '13'
} }

View File

@ -4,9 +4,9 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.fembedExtractor 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.OkruExtractor
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.yourUploadExtractor import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.YourUploadExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
@ -23,6 +23,7 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.lang.Exception import java.lang.Exception
open class TioanimeH(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() { 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("\\/", "/") val serverUrl = servers[1].replace("\\/", "/")
when (serverName.lowercase()) { when (serverName.lowercase()) {
"fembed" -> { "fembed" -> {
val videos = fembedExtractor().videosFromUrl(serverUrl) FembedExtractor().videosFromUrl(serverUrl).map { vid -> videoList.add(vid) }
videoList.addAll(videos)
} }
"okru" -> { "okru" -> {
val videos = okruExtractor(client).videosFromUrl(serverUrl) OkruExtractor(client).videosFromUrl(serverUrl).map { vid -> videoList.add(vid) }
videoList.addAll(videos)
} }
"yourupload" -> { "yourupload" -> {
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build() val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
val video = yourUploadExtractor(client).videofromurl(serverUrl, headers = headers) YourUploadExtractor(client).videoFromUrl(serverUrl, headers = headers).map { vid -> videoList.add(vid) }
videoList.add(video)
} }
} }
} }
@ -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 videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> { override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Fembed: 720p") return try {
if (quality != null) { val videoSorted = this.sortedWith(
val newList = mutableListOf<Video>() compareBy<Video> { it.quality.replace("[0-9]".toRegex(), "") }.thenByDescending { getNumberFromString(it.quality) }
var preferred = 0 ).toTypedArray()
for (video in this) { val userPreferredQuality = preferences.getString("preferred_quality", "Fembed:720p")
if (video.quality == quality) { val preferredIdx = videoSorted.indexOfFirst { x -> x.quality == userPreferredQuality }
newList.add(preferred, video) if (preferredIdx != -1) {
preferred++ videoSorted.drop(preferredIdx + 1)
} else { videoSorted[0] = videoSorted[preferredIdx]
newList.add(video)
}
} }
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 { 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) { 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 { val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality" key = "preferred_quality"
title = "Preferred quality" title = "Preferred quality"
entries = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile") entries = qualities
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile") entryValues = qualities
setDefaultValue("Fembed:720p") setDefaultValue("Fembed:720p")
summary = "%s" summary = "%s"

View File

@ -3,13 +3,14 @@ import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.Connection import org.jsoup.Connection
import org.jsoup.Jsoup import org.jsoup.Jsoup
import java.io.IOException
class fembedExtractor { class FembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> { 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 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 videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data") val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) { for (i in 0 until jsonArray.length()) {
@ -18,12 +19,9 @@ class fembedExtractor {
val quality = qualityPrefix + "Fembed:" + `object`.getString("label") val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
videoList.add(Video(videoUrl, quality, videoUrl)) videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList videoList
} else { } catch (e: IOException) {
val videoUrl = "not used" videoList
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl))
} }
return videoList
} }
} }

View File

@ -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
}
}
}

View File

@ -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
}
}
}

View File

@ -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