Some changes [HentaLA] and New Source [TioAnime / TioHentai] (#635)

This commit is contained in:
Diego Peña Y Lillo
2022-07-09 05:26:24 -04:00
committed by GitHub
parent d46f0717ad
commit a01b6a0159
19 changed files with 377 additions and 47 deletions

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -8,18 +8,17 @@ import eu.kanade.tachiyomi.animeextension.es.hentaila.extractors.FembedExtractor
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
import eu.kanade.tachiyomi.animesource.model.AnimesPage
import eu.kanade.tachiyomi.animesource.model.SAnime import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromString import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -71,7 +70,6 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val episodes = mutableListOf<SEpisode>() val episodes = mutableListOf<SEpisode>()
val animeId = response.request.url.toString().substringAfter("hentai-").lowercase() val animeId = response.request.url.toString().substringAfter("hentai-").lowercase()
val jsoup = response.asJsoup() val jsoup = response.asJsoup()
jsoup.select("div.episodes-list article").forEach { it -> jsoup.select("div.episodes-list article").forEach { it ->
val epNum = it.select("a").attr("href").replace("/ver/$animeId-", "") val epNum = it.select("a").attr("href").replace("/ver/$animeId-", "")
@ -90,25 +88,24 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun episodeFromElement(element: Element) = throw Exception("not used") override fun episodeFromElement(element: Element) = throw Exception("not used")
@OptIn(ExperimentalSerializationApi::class)
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>()
val videoServerList = document.selectFirst("script:containsData(var videos = [)").data().substringAfter("videos = ").substringBefore(";") val videoServers = document.selectFirst("script:containsData(var videos = [)").data().substringAfter("videos = ").substringBefore(";")
.replace("[", "{").replace("]", "}") .replace("[[", "").replace("]]", "")
.replace("\",", "\":") val videoServerList = videoServers.split("],[")
.replace(":0,0", "").replace(":0,1", "") videoServerList.forEach {
.replace("{{", "{").replace("}}", "}")
.replace("},{", ",") val server = it.split(",").map { a -> a.replace("\"", "") }
val jsonServers = json.decodeFromString<JsonObject>(videoServerList) val urlServer = server[1].replace("\\/", "/")
jsonServers.forEach { val nameServer = server[0]
val url = it.value.toString().replace("\"", "")
if (it.key.lowercase() == "fembed") { if (nameServer.lowercase() == "fembed") {
val videos = FembedExtractor().videosFromUrl(url) val videos = FembedExtractor().videosFromUrl(urlServer)
videoList.addAll(videos) videoList.addAll(videos)
} }
if (it.key.lowercase() == "arc") { if (nameServer.lowercase() == "arc") {
val videoUrl = url.substringAfter("#") val videoUrl = urlServer.substringAfter("#")
videoList.add(Video(videoUrl, "Arc", videoUrl, null)) videoList.add(Video(videoUrl, "Arc", videoUrl, null))
} }
} }
@ -123,7 +120,7 @@ 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", "Arc") val quality = preferences.getString("preferred_quality", "Fembed:480p")
if (quality != null) { if (quality != null) {
val newList = mutableListOf<Video>() val newList = mutableListOf<Video>()
var preferred = 0 var preferred = 0
@ -143,47 +140,48 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
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
val results = Jsoup.connect("https://www3.hentaila.com/api/search").method(Connection.Method.POST).data("value", query).execute().body() if (genreFilter.state == 0) {
val results = Jsoup.connect("https://www3.hentaila.com/api/search").method(Connection.Method.POST).data("value", query).execute().body()
val jsonObject = json.decodeFromString<JsonArray>(results)
val animeSlug = JSONObject(jsonObject[0].toString())["slug"]
val ultimateHentaiLink = "$baseUrl/hentai-$animeSlug"
if (query.isNotBlank() && jsonObject.toString() != "[]") {
return GET(ultimateHentaiLink)
}
}
val jsonObject = json.decodeFromString<JsonArray>(results)
val animeSlug = JSONObject(jsonObject[0].toString())["slug"]
val ultimateHentaiLink = "$baseUrl/hentai-$animeSlug"
// for (i in jsonObject) {
// val anime = JSONObject(i.toString())
// val animeSlug = anime["slug"]
// }
return when { return when {
query.isNotBlank() && jsonObject.toString() != "[]" -> GET(ultimateHentaiLink) genreFilter.state != 0 -> GET("$baseUrl/genero/${genreFilter.toUriPart()}?p=$page")
// genreFilter.state != 0 -> GET("$baseUrl/genero/${genreFilter.toUriPart()}?p=$page")
else -> GET("$baseUrl/directorio?p=$page") else -> GET("$baseUrl/directorio?p=$page")
} }
} }
override fun searchAnimeFromElement(element: Element): SAnime { override fun searchAnimeFromElement(element: Element) = throw Exception("not used")
override fun searchAnimeParse(response: Response): AnimesPage {
val anime = mutableListOf<SAnime>()
val element = response.asJsoup()
if (!element.select("article.hentai-single").isNullOrEmpty()) { if (!element.select("article.hentai-single").isNullOrEmpty()) {
val animeSearch = SAnime.create() val animeSearch = SAnime.create()
val mainUrl = element.select("section.section:nth-child(2) > script:nth-child(3)").toString().substringAfter("this.page.url = \"").substringBefore("\"") val mainUrl = element.select("section.section:nth-child(2) > script:nth-child(3)").toString().substringAfter("this.page.url = \"").substringBefore("\"")
animeSearch.setUrlWithoutDomain(mainUrl) animeSearch.setUrlWithoutDomain(mainUrl)
animeSearch.title = element.select("article.hentai-single header.h-header h1").text() animeSearch.title = element.select("article.hentai-single header.h-header h1").text()
animeSearch.thumbnail_url = baseUrl + element.select("article.hentai-single div.h-thumb figure img").attr("src") animeSearch.thumbnail_url = baseUrl + element.select("article.hentai-single div.h-thumb figure img").attr("src")
return animeSearch anime.add(animeSearch)
return AnimesPage(anime, false)
} }
val animes = element.select("div.columns main section.section div.grid.hentais article.hentai").map {
val anime = SAnime.create() popularAnimeFromElement(it)
anime.setUrlWithoutDomain( }
element.select("div.grid.hentais article.hentai a").attr("href")
) return AnimesPage(animes, false)
anime.title = element.select("div.grid.hentais article.hentai header.h-header h2").text()
anime.thumbnail_url = baseUrl + element.select("div.grid.hentais article.hentai div.h-thumb figure img").attr("src")
return anime
} }
override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector() override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector()
override fun searchAnimeSelector(): String = "div.bd.cont" override fun searchAnimeSelector(): String = throw Exception("not used")
override fun animeDetailsParse(document: Document): SAnime { override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create() val anime = SAnime.create()
@ -203,9 +201,9 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesSelector() = throw Exception("not used") override fun latestUpdatesSelector() = throw Exception("not used")
/* 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()
) )
private class GenreFilter : UriPartFilter( private class GenreFilter : UriPartFilter(
@ -217,7 +215,6 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Pair("Anal", "anal"), Pair("Anal", "anal"),
Pair("Casadas", "casadas"), Pair("Casadas", "casadas"),
Pair("Chikan", "chikan"), Pair("Chikan", "chikan"),
Pair("Comedia", "comedia"),
Pair("Ecchi", "ecchi"), Pair("Ecchi", "ecchi"),
Pair("Escolares", "escolares"), Pair("Escolares", "escolares"),
Pair("Enfermeras", "enfermeras"), Pair("Enfermeras", "enfermeras"),
@ -246,7 +243,7 @@ class Hentaila : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Pair("Yuri", "yuri"), Pair("Yuri", "yuri"),
Pair("Bondage", "bondage") Pair("Bondage", "bondage")
) )
) */ )
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.animeextension" />

View File

@ -0,0 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
extName = 'TioanimeH'
pkgNameSuffix = 'es.tioanimeh'
extClass = '.TioanimeHFactory'
extVersionCode = 1
libVersion = '12'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

View File

@ -0,0 +1,232 @@
package eu.kanade.tachiyomi.animeextension.es.tioanimeh
import android.app.Application
import android.content.SharedPreferences
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.fembedExtractor
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.okruExtractor
import eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors.yourUploadExtractor
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
import eu.kanade.tachiyomi.animesource.model.SAnime
import eu.kanade.tachiyomi.animesource.model.SEpisode
import eu.kanade.tachiyomi.animesource.model.Video
import eu.kanade.tachiyomi.animesource.online.ParsedAnimeHttpSource
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.lang.Exception
open class TioanimeH(override val name: String, override val baseUrl: String) : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val lang = "es"
override val supportsLatest = false
override val client: OkHttpClient = network.cloudflareClient
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun popularAnimeSelector(): String = "ul.animes.list-unstyled.row li.col-6.col-sm-4.col-md-3.col-xl-2"
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/directorio?p=$page")
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.url = element.select("article a").attr("href")
anime.title = element.select("article a h3").text()
anime.thumbnail_url = baseUrl + element.select("article a div figure img").attr("src")
return anime
}
override fun popularAnimeNextPageSelector(): String = "nav ul.pagination.d-inline-flex li.page-item a.page-link"
override fun episodeListParse(response: Response): List<SEpisode> {
val document = response.asJsoup()
val epInfoScript = document.selectFirst("script:containsData(var episodes = )").data()
if (epInfoScript.substringAfter("episodes = [").substringBefore("];").isEmpty()) {
return listOf<SEpisode>()
}
val epNumList = epInfoScript.substringAfter("episodes = [").substringBefore("];").split(",")
val epSlug = epInfoScript.substringAfter("anime_info = [").substringBefore("];").replace("\"", "").split(",")[1]
return epNumList.map {
SEpisode.create().apply {
name = "Episodio $it"
url = "/ver/$epSlug-$it"
episode_number = it.toFloat()
}
}
}
override fun episodeListSelector() = throw Exception("not used")
override fun episodeFromElement(element: Element) = throw Exception("not used")
override fun videoListParse(response: Response): List<Video> {
val document = response.asJsoup()
val videoList = mutableListOf<Video>()
val serverList = document.selectFirst("script:containsData(var videos =)").data().substringAfter("var videos = [[").substringBefore("]];")
.replace("\"", "").split("],[")
serverList.forEach() {
val servers = it.split(",")
val serverName = servers[0]
val serverUrl = servers[1].replace("\\/", "/")
when (serverName.lowercase()) {
"fembed" -> {
val videos = fembedExtractor().videosFromUrl(serverUrl)
videoList.addAll(videos)
}
"okru" -> {
val videos = okruExtractor(client).videosFromUrl(serverUrl)
videoList.addAll(videos)
}
"yourupload" -> {
val headers = headers.newBuilder().add("referer", "https://www.yourupload.com/").build()
val video = yourUploadExtractor(client).videofromurl(serverUrl, headers = headers)
videoList.add(video)
}
}
}
return videoList
}
override fun videoListSelector() = throw Exception("not used")
override fun videoUrlParse(document: Document) = throw Exception("not used")
override fun videoFromElement(element: Element) = throw Exception("not used")
override fun List<Video>.sort(): List<Video> {
val quality = preferences.getString("preferred_quality", "Fembed: 720p")
if (quality != null) {
val newList = mutableListOf<Video>()
var preferred = 0
for (video in this) {
if (video.quality == quality) {
newList.add(preferred, video)
preferred++
} else {
newList.add(video)
}
}
return newList
}
return this
}
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
val filterList = if (filters.isEmpty()) getFilterList() else filters
val genreFilter = filterList.find { it is GenreFilter } as GenreFilter
return when {
query.isNotBlank() -> GET("$baseUrl/directorio?q=$query&p=$page", headers)
genreFilter.state != 0 -> GET("$baseUrl/directorio?genero=${genreFilter.toUriPart()}&p=$page")
else -> GET("$baseUrl/directorio?p=$page ")
}
}
override fun searchAnimeFromElement(element: Element): SAnime {
return popularAnimeFromElement(element)
}
override fun searchAnimeNextPageSelector(): String = popularAnimeNextPageSelector()
override fun searchAnimeSelector(): String = popularAnimeSelector()
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
anime.thumbnail_url = document.selectFirst("div.chapterpic img").attr("src")
anime.title = document.selectFirst("div.chapterdetails h1").text()
anime.description = document.select("p.textShort").first().ownText()
anime.genre = document.select("ol.breadcrumb li.breadcrumb-item a").joinToString { it.text() }
anime.status = parseStatus(document.select("div.butns button.btn1").text())
return anime
}
private fun parseStatus(statusString: String): Int {
return when {
statusString.contains("Estreno") -> SAnime.ONGOING
statusString.contains("Finalizado") -> SAnime.COMPLETED
else -> SAnime.UNKNOWN
}
}
override fun latestUpdatesNextPageSelector() = throw Exception("not used")
override fun latestUpdatesFromElement(element: Element) = throw Exception("not used")
override fun latestUpdatesRequest(page: Int) = throw Exception("not used")
override fun latestUpdatesSelector() = throw Exception("not used")
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("La busqueda por texto ignora el filtro"),
GenreFilter()
)
private class GenreFilter : UriPartFilter(
"Generos",
arrayOf(
Pair("<selecionar>", ""),
Pair("Ahegao", "ahegao"),
Pair("Anal", "anal"),
Pair("Casadas", "casadas"),
Pair("Ecchi", "ecchi"),
Pair("Escolares", "escolares"),
Pair("Enfermeras", "enfermeras"),
Pair("Futanari", "futanari"),
Pair("Harem", "Harem"),
Pair("Gore", "gore"),
Pair("Hardcore", "hardcore"),
Pair("Incesto", "incesto"),
Pair("Juegos Sexuales", "juegos-sexuales"),
Pair("Milfs", "milf"),
Pair("Orgia", "orgia"),
Pair("Romance", "romance"),
Pair("Shota", "shota"),
Pair("Succubus", "succubus"),
Pair("Tetonas", "tetonas"),
Pair("Violacion", "violacion"),
Pair("Virgenes(como tu)", "virgenes"),
Pair("Yaoi", "Yaoi"),
Pair("Yuri", "yuri"),
)
)
open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
AnimeFilter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val videoQualityPref = ListPreference(screen.context).apply {
key = "preferred_quality"
title = "Preferred quality"
entries = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
entryValues = arrayOf("Fembed:480p", "Fembed:720p", "Fembed:1080p", "SolidFiles", "Okru: full", "Okru: sd", "Okru: low", "Okru: lowest", "Okru: mobile")
setDefaultValue("Fembed:720p")
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

@ -0,0 +1,18 @@
package eu.kanade.tachiyomi.animeextension.es.tioanimeh
import eu.kanade.tachiyomi.animesource.AnimeSource
import eu.kanade.tachiyomi.animesource.AnimeSourceFactory
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
class TioanimeHFactory : AnimeSourceFactory {
override fun createSources(): List<AnimeSource> = listOf(
tioanime(),
tiohentai()
)
}
class tioanime : TioanimeH("TioAnime", "https://tioanime.com") {
override fun getFilterList(): AnimeFilterList = AnimeFilterList()
}
class tiohentai : TioanimeH("TioHentai", "https://tiohentai.com")

View File

@ -0,0 +1,29 @@
package eu.kanade.tachiyomi.animeextension.es.tioanimeh.extractors
import eu.kanade.tachiyomi.animesource.model.Video
import org.json.JSONObject
import org.jsoup.Connection
import org.jsoup.Jsoup
class fembedExtractor {
fun videosFromUrl(url: String, qualityPrefix: String = ""): List<Video> {
val videoApi = url.replace("/v/", "/api/source/")
val json = JSONObject(Jsoup.connect(videoApi).ignoreContentType(true).method(Connection.Method.POST).execute().body())
val videoList = mutableListOf<Video>()
if (json.getBoolean("success")) {
val videoList = mutableListOf<Video>()
val jsonArray = json.getJSONArray("data")
for (i in 0 until jsonArray.length()) {
val `object` = jsonArray.getJSONObject(i)
val videoUrl = `object`.getString("file")
val quality = qualityPrefix + "Fembed:" + `object`.getString("label")
videoList.add(Video(videoUrl, quality, videoUrl, null))
}
return videoList
} else {
val videoUrl = "not used"
val quality = "Video taken down for dmca"
videoList.add(Video(videoUrl, quality, videoUrl, null))
}
return videoList
}
}

View File

@ -0,0 +1,25 @@
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, null))
}
}
return videoList
}
}

View File

@ -0,0 +1,15 @@
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
class yourUploadExtractor(private val client: OkHttpClient) {
fun videofromurl(url: String, headers: Headers): Video {
val document = client.newCall(GET(url)).execute().asJsoup()
val basicUrl = document.selectFirst("script:containsData(jwplayerOptions)").data().substringAfter("file: '").substringBefore("',")
return Video(basicUrl, "YourUpload", basicUrl, null, headers)
}
}