Wcofun update & fixes (#904)

This commit is contained in:
LuftVerbot
2022-10-07 21:24:48 +02:00
committed by GitHub
parent 64bc6a95d2
commit 2edf76af76
3 changed files with 107 additions and 179 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'Wcofun'
pkgNameSuffix = 'en.wcofun'
extClass = '.Wcofun'
extVersionCode = 5
extVersionCode = 6
libVersion = '13'
}

View File

@ -0,0 +1,89 @@
package eu.kanade.tachiyomi.animeextension.en.wcofun
import android.annotation.SuppressLint
import android.app.Application
import android.os.Handler
import android.os.Looper
import android.webkit.WebResourceRequest
import android.webkit.WebResourceResponse
import android.webkit.WebView
import android.webkit.WebViewClient
import eu.kanade.tachiyomi.network.GET
import okhttp3.Headers.Companion.toHeaders
import okhttp3.Interceptor
import okhttp3.Request
import okhttp3.Response
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.util.concurrent.CountDownLatch
import java.util.concurrent.TimeUnit
class RedirectInterceptor : Interceptor {
private val context = Injekt.get<Application>()
private val handler by lazy { Handler(Looper.getMainLooper()) }
override fun intercept(chain: Interceptor.Chain): Response {
val originalRequest = chain.request()
val newRequest = resolveWithWebView(originalRequest) ?: throw Exception("bruh")
return chain.proceed(newRequest)
}
@SuppressLint("SetJavaScriptEnabled")
private fun resolveWithWebView(request: Request): Request? {
// We need to lock this thread until the WebView finds the challenge solution url, because
// OkHttp doesn't support asynchronous interceptors.
val latch = CountDownLatch(1)
var webView: WebView? = null
val origRequestUrl = request.url.toString()
val headers = request.headers.toMultimap().mapValues { it.value.getOrNull(0) ?: "" }.toMutableMap()
var newRequest: Request? = null
handler.post {
val webview = WebView(context)
webView = webview
with(webview.settings) {
javaScriptEnabled = true
domStorageEnabled = true
databaseEnabled = true
useWideViewPort = false
loadWithOverviewMode = false
blockNetworkLoads = true
userAgentString = request.header("User-Agent")
?: "\"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36 Edg/88.0.705.63\""
}
webview.webViewClient = object : WebViewClient() {
override fun shouldInterceptRequest(
view: WebView,
request: WebResourceRequest,
): WebResourceResponse? {
if (request.url.toString().contains("https://www.wcofun.net")) {
newRequest = GET(request.url.toString(), request.requestHeaders.toHeaders())
latch.countDown()
}
return super.shouldInterceptRequest(view, request)
}
}
webView?.loadUrl(origRequestUrl, headers)
}
// Wait a reasonable amount of time to retrieve the solution. The minimum should be
// around 4 seconds but it can take more due to slow networks or server issues.
latch.await(12, TimeUnit.SECONDS)
handler.post {
webView?.stopLoading()
webView?.destroy()
webView = null
}
return newRequest
}
}

View File

@ -36,7 +36,7 @@ class Wcofun : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override val name = "Wcofun"
override val baseUrl = "https://www.wcofun.com/"
override val baseUrl = "https://www.wcofun.net"
override val lang = "en"
@ -50,18 +50,23 @@ class Wcofun : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun popularAnimeSelector(): String = "div.sidebar-titles li a"
override fun popularAnimeSelector(): String = "#sidebar_right2 ul.items li"
override fun popularAnimeRequest(page: Int): Request = GET(baseUrl)
override fun popularAnimeRequest(page: Int): Request {
val interceptor = client.newBuilder().addInterceptor(RedirectInterceptor()).build()
val headers = interceptor.newCall(GET(baseUrl)).execute().request.headers
return GET(baseUrl, headers = headers)
}
override fun popularAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.text()
anime.thumbnail_url = "https:" + element.select("div.img a img").attr("src")
anime.setUrlWithoutDomain(element.select("div.img a").attr("href"))
anime.title = element.select("div.recent-release-episodes a").text()
return anime
}
override fun popularAnimeNextPageSelector(): String = "ul.pagination li:last-child:not(.selected)"
override fun popularAnimeNextPageSelector(): String? = null
override fun episodeListSelector() = "div.cat-eps a"
@ -176,26 +181,22 @@ class Wcofun : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
override fun searchAnimeFromElement(element: Element): SAnime {
val anime = SAnime.create()
anime.setUrlWithoutDomain(element.attr("href"))
anime.title = element.text()
anime.thumbnail_url = element.select("img").attr("src")
anime.title = element.select("img").attr("alt")
return anime
}
override fun searchAnimeNextPageSelector(): String = "ul.pagination-list li:last-child:not(.selected)"
override fun searchAnimeNextPageSelector(): String? = null
override fun searchAnimeSelector(): String = "div#sidebar_right2 li div.recent-release-episodes a, div.ddmcc li a"
override fun searchAnimeSelector(): String = "div#sidebar_right2 li div.img a"
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
val formBody = FormBody.Builder()
.add("catara", query)
.add("konuara", "series")
.build()
return when {
query.isNotBlank() -> POST("$baseUrl/search", headers, body = formBody)
genreFilter.state != 0 -> GET("$baseUrl/search-by-genre/page/${genreFilter.toUriPart()}")
else -> GET("$baseUrl/")
}
return POST("$baseUrl/search", headers, body = formBody)
}
override fun animeDetailsParse(document: Document): SAnime {
@ -233,166 +234,4 @@ class Wcofun : ConfigurableAnimeSource, ParsedAnimeHttpSource() {
}
screen.addPreference(videoQualityPref)
}
// Filters
override fun getFilterList(): AnimeFilterList = AnimeFilterList(
AnimeFilter.Header("Text search ignores filters"),
GenreFilter()
)
private class GenreFilter : UriPartFilter(
"Genres",
arrayOf(
Pair("<select>", ""),
Pair("Adventure", "4"),
Pair("Comedy", "6"),
Pair("Fantasy", "8"),
Pair("Science Fiction", "10"),
Pair("Mystery", "12"),
Pair("Action", "14"),
Pair("Drama", "16"),
Pair("Surrealist Comedy", "18"),
Pair("Horror", "20"),
Pair("Romance", "22"),
Pair("Animated", "23"),
Pair("Thriller", "24"),
Pair("Slice Of Life", "25"),
Pair("Supernatural", "26"),
Pair("Romantic Comedy", "27"),
Pair("Harem", "28"),
Pair("Sports", "29"),
Pair("Psychological", "30"),
Pair("Magical Girl", "31"),
Pair("Mecha", "35"),
Pair("Role-playing", "33"),
Pair("Military", "34"),
Pair("Science Fantasy", "36"),
Pair("Martial Arts", "37"),
Pair("High School", "38"),
Pair("Parody", "39"),
Pair("Virtual Reality", "40"),
Pair("Space Opera", "41"),
Pair("Post-Apocalyptic", "42"),
Pair("Music", "43"),
Pair("Dark Fantasy", "44"),
Pair("Historical Fantasy", "45"),
Pair("Yuri", "46"),
Pair("Superpower", "47"),
Pair("Magic", "48"),
Pair("Alternate History", "49"),
Pair("Sci-fi", "50"),
Pair("Girls With Guns", "51"),
Pair("Tournament", "52"),
Pair("School", "53"),
Pair("Romantic Drama", "54"),
Pair("Crime", "55"),
Pair("Historical", "56"),
Pair("Dystopian", "57"),
Pair("Steampunk", "58"),
Pair("Metafiction", "59"),
Pair("Police", "60"),
Pair("Detective Fiction", "61"),
Pair("Occult", "62"),
Pair("Tragedy", "63"),
Pair("Fighter", "65"),
Pair("Animated television series", "66"),
Pair("Children's television series", "67"),
Pair("Family television series", "68"),
Pair("Absurdist humor", "69"),
Pair("Dark humor", "70"),
Pair("Surreal humor", "71"),
Pair("Adult animation", "72"),
Pair("Teen Drama", "73"),
Pair("Superhero", "74"),
Pair("Cyberpunk", "75"),
Pair("Suspense", "76"),
Pair("Sitcom", "77"),
Pair("Satire", "78"),
Pair("Anthology series", "79"),
Pair("Edutainment", "80"),
Pair("Espionage", "81"),
Pair("Surrealism", "82"),
Pair("Teen Animation", "83"),
Pair("Toilet humour", "84"),
Pair("Cutaway gag humor", "85"),
Pair("Splatter", "86"),
Pair("Deadpan", "87"),
Pair("Car racing", "88"),
Pair("Chanbara", "89"),
Pair("Goth", "90"),
Pair("Game", "93"),
Pair("Magical boy", "94"),
Pair("Shounen", "95"),
Pair("Kids", "96"),
Pair("shoujo", "97"),
Pair("Baseball", "98"),
Pair("Manga", "99"),
Pair("Friendship", "100"),
Pair("School Dormitory", "101"),
Pair("Ecchi", "102"),
Pair("Seinen", "103"),
Pair("Coming-of-age story", "104"),
Pair("Idol anime", "105"),
Pair("Samurai", "106"),
Pair("Reverse Harem", "107"),
Pair("Urban", "108"),
Pair("War", "109"),
Pair("Vampire", "110"),
Pair("Demons", "111"),
Pair("Urban fantasy", "112"),
Pair("Mythic fiction", "113"),
Pair("Space", "114"),
Pair("Shounen Ai", "115"),
Pair("Shoujo Ai", "116"),
Pair("Slapstick", "117"),
Pair("Surreal", "118"),
Pair("Chinese Cartoon", "119"),
Pair("Short", "120"),
Pair("Movie", "121"),
Pair("Family", "123"),
Pair("Animation", "125"),
Pair("Educational", "128"),
Pair("Musical", "129"),
Pair("Yaoi", "132"),
Pair("Documentary", "133"),
Pair("Football", "134"),
Pair("Learning", "135"),
Pair("Pre-School", "136"),
Pair("Graphic novel", "137"),
Pair("Contemporary fantasy", "140"),
Pair("Adult Cartoons", "141"),
Pair("Cartoon series", "142"),
Pair("Off-color humor", "143"),
Pair("History", "147"),
Pair("Superhero fiction", "149"),
Pair("Sword and sorcery", "155"),
Pair("Stop Motion", "157"),
Pair("Horror comedy", "159"),
Pair("Social satire", "163"),
Pair("Black comedy", "166"),
Pair("Animated sitcom", "168"),
Pair("Game-Show", "170"),
Pair("Western", "172"),
Pair("Comic science fiction", "176"),
Pair("Situation comedy", "178"),
Pair("Adapted Literature", "181"),
Pair("Harold and the Purple Crayon", "202"),
Pair("Spy fiction", "203"),
Pair("Children's fiction", "204"),
Pair("Sketch comedy", "205"),
Pair("Josei", "206"),
Pair("Dementia", "208"),
Pair("Cars", "209"),
Pair("Isekai", "210"),
Pair("Comedy-drama", "211"),
Pair("Senryuu Girl", "214"),
Pair("Musical comedy", "215"),
Pair("Comedy horror", "216"),
)
)
private 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
}
}