[skip ci] Update dependencies (#1343)

* Bump harmless dependencies

Note that bumping the android plugin will make compilation show lots of
"hey bro use namespace instead of AndroidManifest.xml" warnings

* Remove duktape dependency

Zero extensions are using it, so its safe to remove. For executing js in
extensions we can use quickjs instead of ducktape.

* Upgrade gradle to 7.6

* Update kotlin

* Update OkHttp

* Update JSoup

Jesus Christ this was boring asf

* Update KtLint

* [skip ci] refactor on some build.gradle.kts files

* Expose coroutines to all extension by default
This commit is contained in:
Claudemirovsky
2023-02-28 10:12:46 -03:00
committed by GitHub
parent a5c2427e70
commit 62f45e094d
387 changed files with 3380 additions and 2909 deletions

View File

@ -86,8 +86,8 @@ class Kuramanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun parseShortInfo(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").first().attr("href"))
anime.thumbnail_url = element.select("a > div").first().attr("data-setbg")
anime.setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
anime.thumbnail_url = element.selectFirst("a > div")!!.attr("data-setbg")
anime.title = element.select("div.product__item__text > h5").text()
return anime
}
@ -124,7 +124,7 @@ class Kuramanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
document.select("select#changeServer > option").forEach {
videoList.addAll(
videosFromServer(response.request.url.toString(), it.attr("value"), it.text())
videosFromServer(response.request.url.toString(), it.attr("value"), it.text()),
)
}
@ -133,7 +133,7 @@ class Kuramanime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun videosFromServer(episodeUrl: String, server: String, name: String): List<Video> {
val document = client.newCall(
GET("$episodeUrl?activate_stream=1&stream_server=$server", headers = headers)
GET("$episodeUrl?activate_stream=1&stream_server=$server", headers = headers),
).execute().asJsoup()
return document.select(videoListSelector()).map { videoFromElement(it, name, episodeUrl) }
}

View File

@ -64,7 +64,7 @@ class Kuronime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create()
val epsNum = getNumberFromEpsString(element.select("span.lchx").text())
episode.setUrlWithoutDomain(element.select("a").first().attr("href"))
episode.setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
episode.episode_number = when {
(epsNum.isNotEmpty()) -> epsNum.toFloat()
else -> 1F
@ -84,9 +84,9 @@ class Kuronime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun getAnimeFromAnimeElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("div > a").first().attr("href"))
anime.setUrlWithoutDomain(element.selectFirst("div > a")!!.attr("href"))
val thumbnailElement = element.selectFirst("div > a > div.limit > img")
val thumbnailElement = element.selectFirst("div > a > div.limit > img")!!
val thumbnail = thumbnailElement.attr("src")
anime.thumbnail_url = if (thumbnail.startsWith("https:")) {
thumbnail
@ -132,7 +132,7 @@ class Kuronime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
document.select("select.mirror > option[value]").forEach { opt ->
val decoded = if (opt.attr("value").isEmpty()) {
document.selectFirst("iframe").attr("data-src")
document.selectFirst("iframe")!!.attr("data-src")
} else {
Jsoup.parse(
String(Base64.decode(opt.attr("value"), Base64.DEFAULT)),

View File

@ -13,7 +13,7 @@ import uy.kohesive.injekt.injectLazy
@Serializable
data class Source(
val file: String,
val label: String
val label: String,
)
class AnimekuExtractor(private val client: OkHttpClient) {
@ -26,7 +26,7 @@ class AnimekuExtractor(private val client: OkHttpClient) {
val quickJs = QuickJs.create()
val decryped = quickJs.evaluate(
script.data().trim().split("\n")[0].replace("eval(function", "function a").replace("decodeURIComponent(escape(r))}(", "r};a(").substringBeforeLast(")")
script.data().trim().split("\n")[0].replace("eval(function", "function a").replace("decodeURIComponent(escape(r))}(", "r};a(").substringBeforeLast(")"),
).toString()
quickJs.close()
@ -35,7 +35,7 @@ class AnimekuExtractor(private val client: OkHttpClient) {
Video(
src.file,
"${src.label} - $name",
src.file
src.file,
)
}
}

View File

@ -10,11 +10,11 @@ import okhttp3.OkHttpClient
class HxFileExtractor(private val client: OkHttpClient) {
fun getVideoFromUrl(url: String, name: String): List<Video> {
val document = client.newCall(GET(url)).execute().asJsoup()
val packed = document.selectFirst("script:containsData(eval\\(function\\()").data()
val packed = document.selectFirst("script:containsData(eval\\(function\\()")!!.data()
val unpacked = JsUnpacker.unpackAndCombine(packed) ?: return emptyList()
val videoUrl = unpacked.substringAfter("\"type\":\"video").substringAfter("\"file\":\"").substringBefore("\"")
return listOf(
Video(videoUrl, "Original - $name", videoUrl, headers = Headers.headersOf("Referer", "https://hxfile.co/"))
Video(videoUrl, "Original - $name", videoUrl, headers = Headers.headersOf("Referer", "https://hxfile.co/")),
)
}
}

View File

@ -27,8 +27,8 @@ class LinkBoxExtractor(private val client: OkHttpClient) {
Video(
it.jsonObject["url"].toString().replace("\"", ""),
"${it.jsonObject["resolution"].toString().replace("\"", "")} - $name",
it.jsonObject["url"].toString().replace("\"", "")
)
it.jsonObject["url"].toString().replace("\"", ""),
),
)
}
return videoList

View File

@ -8,14 +8,14 @@ import okhttp3.OkHttpClient
class Mp4uploadExtractor(private val client: OkHttpClient) {
fun getVideoFromUrl(url: String, headers: Headers, name: String): List<Video> {
val body = client.newCall(GET(url, headers = headers)).execute().body!!.string()
val body = client.newCall(GET(url, headers = headers)).execute().body.string()
val packed = body.substringAfter("<script type='text/javascript'>eval(function(p,a,c,k,e,d)")
.substringBefore("</script>")
val unpacked = JsUnpacker.unpackAndCombine("eval(function(p,a,c,k,e,d)" + packed) ?: return emptyList()
val videoUrl = unpacked.substringAfter("player.src(\"").substringBefore("\");")
return listOf(
Video(videoUrl, "Original - $name", videoUrl, headers = Headers.headersOf("Referer", "https://www.mp4upload.com/"))
Video(videoUrl, "Original - $name", videoUrl, headers = Headers.headersOf("Referer", "https://www.mp4upload.com/")),
)
}
}

View File

@ -14,9 +14,9 @@ class StreamlareExtractor(private val client: OkHttpClient) {
POST(
"https://slwatch.co/api/video/stream/get",
body = "{\"id\":\"$id\"}"
.toRequestBody("application/json".toMediaType())
)
).execute().body!!.string()
.toRequestBody("application/json".toMediaType()),
),
).execute().body.string()
playlist.substringAfter("\"label\":\"").split("\"label\":\"").forEach {
val quality = it.substringAfter("\"label\":\"").substringBefore("\",") + " - $name"

View File

@ -56,7 +56,7 @@ class MiniOppai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun episodeFromElement(element: Element): SEpisode {
val episode = SEpisode.create()
val epsNum = getNumberFromEpsString(element.select("span.lchx").text())
episode.setUrlWithoutDomain(element.select("a").first().attr("href"))
episode.setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
episode.episode_number = when {
(epsNum.isNotEmpty()) -> epsNum.toFloat()
else -> 1F
@ -76,8 +76,8 @@ class MiniOppai : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun getAnimeFromAnimeElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("div > a").first().attr("href"))
anime.thumbnail_url = element.select("img").first().attr("data-src")
anime.setUrlWithoutDomain(element.selectFirst("div > a")!!.attr("href"))
anime.thumbnail_url = element.selectFirst("img")!!.attr("data-src")
anime.title = element.select("div > a > div.tt").text()
return anime
}

View File

@ -61,28 +61,28 @@ class NeoNime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun getAnimeFromAnimeElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("a").first().attr("href"))
anime.thumbnail_url = element.select("a > div.image > img").first().attr("data-src")
anime.setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
anime.thumbnail_url = element.selectFirst("a > div.image > img")!!.attr("data-src")
anime.title = element.select("div.fixyear > div > h2").text()
return anime
}
private fun getAnimeFromEpisodeElement(element: Element): SAnime {
val animepage = client.newCall(GET(element.select("td.bb > a").first().attr("href"))).execute().asJsoup()
val animepage = client.newCall(GET(element.selectFirst("td.bb > a")!!.attr("href"))).execute().asJsoup()
val anime = SAnime.create()
anime.setUrlWithoutDomain(animepage.select("#fixar > div.imagen > a").first().attr("href"))
anime.thumbnail_url = animepage.select("#fixar > div.imagen > a > img").first().attr("data-src")
anime.title = animepage.select("#fixar > div.imagen > a > img").first().attr("alt")
anime.setUrlWithoutDomain(animepage.selectFirst("#fixar > div.imagen > a")!!.attr("href"))
anime.thumbnail_url = animepage.selectFirst("#fixar > div.imagen > a > img")!!.attr("data-src")
anime.title = animepage.selectFirst("#fixar > div.imagen > a > img")!!.attr("alt")
return anime
}
private fun getAnimeFromSearchElement(element: Element): SAnime {
val url = element.select("a").first().attr("href")
val url = element.selectFirst("a")!!.attr("href")
val animepage = client.newCall(GET(url)).execute().asJsoup()
val anime = SAnime.create()
anime.setUrlWithoutDomain(url)
anime.title = animepage.select("#info > div:nth-child(2) > span").text()
anime.thumbnail_url = animepage.select("div.imagen > img").first().attr("data-src")
anime.thumbnail_url = animepage.selectFirst("div.imagen > img")!!.attr("data-src")
anime.status = parseStatus(animepage.select("#info > div:nth-child(13) > span").text())
anime.genre = animepage.select("#info > div:nth-child(3) > span > a").joinToString(", ") { it.text() }
// this site didnt provide artist and author
@ -169,7 +169,7 @@ class NeoNime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun animeDetailsParse(document: Document): SAnime {
val anime = SAnime.create()
anime.title = document.select("#info > div:nth-child(2) > span").text()
anime.thumbnail_url = document.select("div.imagen > img").first().attr("data-src")
anime.thumbnail_url = document.selectFirst("div.imagen > img")!!.attr("data-src")
anime.status = parseStatus(document.select("#info > div:nth-child(13) > span").text())
anime.genre = document.select("#info > div:nth-child(3) > span > a").joinToString(", ") { it.text() }
// this site didnt provide artist and author
@ -250,7 +250,7 @@ class NeoNime : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
GET(link, headers = headers),
).execute().asJsoup()
var iframeUrl = iframe.selectFirst("iframe").attr("src")
var iframeUrl = iframe.selectFirst("iframe")!!.attr("src")
if (!iframeUrl.startsWith("http")) {
iframeUrl = "https:$iframeUrl"

View File

@ -11,12 +11,12 @@ import uy.kohesive.injekt.injectLazy
@Serializable
data class VideoConfig(
val streams: List<Stream>
val streams: List<Stream>,
) {
@Serializable
data class Stream(
val play_url: String,
val format_id: Int
val format_id: Int,
)
}

View File

@ -20,14 +20,18 @@ class GdrivePlayerExtractor(private val client: OkHttpClient) {
fun videosFromUrl(url: String, name: String): List<Video> {
val headers = Headers.headersOf(
"Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Host", "gdriveplayer.to",
"Referer", "https://neonime.fun/",
"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0"
"Accept",
"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Host",
"gdriveplayer.to",
"Referer",
"https://neonime.fun/",
"User-Agent",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0",
)
val body = client.newCall(GET(url.replace(".me", ".to"), headers = headers)).execute()
.body!!.string()
.body.string()
val eval = JsUnpacker.unpackAndCombine(body)!!.replace("\\", "")
val json = Json.decodeFromString<JsonObject>(REGEX_DATAJSON.getFirst(eval))
@ -70,9 +74,8 @@ class GdrivePlayerExtractor(private val client: OkHttpClient) {
hashAlgorithm: String = "MD5",
keyLength: Int = 32,
ivLength: Int = 16,
iterations: Int = 1
iterations: Int = 1,
): List<ByteArray>? {
val md = MessageDigest.getInstance(hashAlgorithm)
val digestLength = md.getDigestLength()
val targetKeySize = keyLength + ivLength
@ -84,12 +87,13 @@ class GdrivePlayerExtractor(private val client: OkHttpClient) {
md.reset()
while (generatedLength < targetKeySize) {
if (generatedLength > 0)
if (generatedLength > 0) {
md.update(
generatedData,
generatedLength - digestLength,
digestLength
digestLength,
)
}
md.update(password)
md.update(salt, 0, 8)
@ -104,7 +108,7 @@ class GdrivePlayerExtractor(private val client: OkHttpClient) {
}
val result = listOf(
generatedData.copyOfRange(0, keyLength),
generatedData.copyOfRange(keyLength, targetKeySize)
generatedData.copyOfRange(keyLength, targetKeySize),
)
return result
} catch (e: DigestException) {

View File

@ -27,8 +27,8 @@ class LinkBoxExtractor(private val client: OkHttpClient) {
Video(
it.jsonObject["url"].toString().replace("\"", ""),
"${it.jsonObject["resolution"].toString().replace("\"", "")} - $name",
it.jsonObject["url"].toString().replace("\"", "")
)
it.jsonObject["url"].toString().replace("\"", ""),
),
)
}
return videoList

View File

@ -93,8 +93,8 @@ class Oploverz : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun getAnimeFromAnimeElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("div > a").first().attr("href"))
anime.thumbnail_url = element.select("div > a > div.limit > img").first().attr("src")
anime.setUrlWithoutDomain(element.selectFirst("div > a")!!.attr("href"))
anime.thumbnail_url = element.selectFirst("div > a > div.limit > img")!!.attr("src")
anime.title = element.select("div > a > div.tt > h2").text()
return anime
}
@ -132,9 +132,11 @@ class Oploverz : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val zippy = document.select(patternZippy).mapNotNull {
runCatching { zippyFromElement(it) }.getOrNull()
}
val google = if (iframe == null) { mutableListOf() } else try {
googleLinkFromElement(iframe)
} catch (e: Exception) { mutableListOf() }
val google = if (iframe == null) { mutableListOf() } else {
try {
googleLinkFromElement(iframe)
} catch (e: Exception) { mutableListOf() }
}
return google + zippy
}
@ -143,7 +145,7 @@ class Oploverz : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
private fun googleLinkFromElement(iframe: Element): List<Video> {
val iframeResponse = client.newCall(GET(iframe.attr("src"))).execute()
val streams = iframeResponse.body!!.string().substringAfter("\"streams\":[").substringBefore("]")
val streams = iframeResponse.body.string().substringAfter("\"streams\":[").substringBefore("]")
val videoList = mutableListOf<Video>()
streams.split("},").reversed().forEach {
val url = unescape(it.substringAfter("{\"play_url\":\"").substringBefore("\""))
@ -250,15 +252,24 @@ class Oploverz : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val delimiter = input[i]
i++ // consume letter or backslash
if (delimiter == '\\' && i < input.length) {
// consume first after backslash
val ch = input[i]
i++
if (ch == '\\' || ch == '/' || ch == '"' || ch == '\'') {
builder.append(ch)
} else if (ch == 'n') builder.append('\n') else if (ch == 'r') builder.append('\r') else if (ch == 't') builder.append(
'\t'
) else if (ch == 'b') builder.append('\b') else if (ch == 'f') builder.append('\u000C') else if (ch == 'u') {
} else if (ch == 'n') {
builder.append('\n')
} else if (ch == 'r') {
builder.append('\r')
} else if (ch == 't') {
builder.append(
'\t',
)
} else if (ch == 'b') {
builder.append('\b')
} else if (ch == 'f') {
builder.append('\u000C')
} else if (ch == 'u') {
val hex = StringBuilder()
// expect 4 digits

View File

@ -101,8 +101,8 @@ class OtakuDesu : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun latestUpdatesFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("div.thumb > a").first().attr("href"))
anime.thumbnail_url = element.select("div.thumb > a > div.thumbz > img").first().attr("src")
anime.setUrlWithoutDomain(element.selectFirst("div.thumb > a")!!.attr("href"))
anime.thumbnail_url = element.selectFirst("div.thumb > a > div.thumbz > img")!!.attr("src")
anime.title = element.select("div.thumb > a > div.thumbz > h2").text()
return anime
}
@ -115,8 +115,8 @@ class OtakuDesu : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.select("div.thumb > a").first().attr("href"))
anime.thumbnail_url = element.select("div.thumb > a > div.thumbz > img").first().attr("src")
anime.setUrlWithoutDomain(element.selectFirst("div.thumb > a")!!.attr("href"))
anime.thumbnail_url = element.selectFirst("div.thumb > a > div.thumbz > img")!!.attr("src")
anime.title = element.select("div.thumb > a > div.thumbz > h2").text()
return anime
}
@ -133,16 +133,16 @@ class OtakuDesu : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
val anime = SAnime.create()
anime.setUrlWithoutDomain(
when (ui) {
"search" -> element.select("h2 > a").first().attr("href")
"search" -> element.selectFirst("h2 > a")!!.attr("href")
"genres" -> element.select(".col-anime-title > a").attr("href")
else -> element.select("div.thumb > a").first().attr("href")
}
else -> element.selectFirst("div.thumb > a")!!.attr("href")
},
)
anime.thumbnail_url = when (ui) {
"search" -> element.select("img").first().attr("src")
"search" -> element.selectFirst("img")!!.attr("src")
"genres" -> element.select(".col-anime-cover > img").attr("src")
else -> element.select("div.thumb > a > div.thumbz > img").first().attr("src")
else -> element.selectFirst("div.thumb > a > div.thumbz > img")!!.attr("src")
}
anime.title = when (ui) {
"search" -> element.select("h2 > a").text().replace(" Subtitle Indonesia", "")
@ -255,7 +255,7 @@ class OtakuDesu : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
// filter
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("Text search ignores filters"),
GenreFilter()
GenreFilter(),
)
private class GenreFilter : UriPartFilter(
@ -298,7 +298,7 @@ class OtakuDesu : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Pair("Supernatural", "supernatural"),
Pair("Thriller", "thriller"),
Pair("Vampire", "vampire"),
)
),
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :