add Wolfdotcom (#6534)
* wolfdotcom * fix selectors * domain preference and auto update * update domain number * auto update domain in ci * update regex * use * current domain number * don't set chapter number as it is more of an index than actual chapter num
This commit is contained in:
parent
bb2e8d2cde
commit
6b8b650004
|
@ -0,0 +1,53 @@
|
||||||
|
ext {
|
||||||
|
extName = 'Wolf.com'
|
||||||
|
extClass = '.WolfFactory'
|
||||||
|
extVersionCode = 1
|
||||||
|
isNsfw = true
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
||||||
|
def domainNumberFileName = "src/ko/wolfdotcom/src/eu/kanade/tachiyomi/extension/ko/wolfdotcom/DomainNumber.kt"
|
||||||
|
def domainNumberFile = new File(domainNumberFileName)
|
||||||
|
def backupFile = new File(domainNumberFileName + "_bak")
|
||||||
|
|
||||||
|
tasks.register('updateDomainNumber') {
|
||||||
|
doLast {
|
||||||
|
def domainNumber = -1
|
||||||
|
def response = new URL("https://nicelink52.com/").text
|
||||||
|
def matcher = response =~ ~/https?:\/\/wfwf(\d+)\.com/
|
||||||
|
if (matcher) {
|
||||||
|
domainNumber = matcher[0][1]
|
||||||
|
println("[Wolf.com] new domain number: $domainNumber")
|
||||||
|
} else {
|
||||||
|
println("[Wolf.com] domain number not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (domainNumber != -1) {
|
||||||
|
domainNumberFile.renameTo(backupFile)
|
||||||
|
domainNumberFile.withPrintWriter {
|
||||||
|
it.println("// THIS FILE IS AUTO-GENERATED, DO NOT COMMIT")
|
||||||
|
it.println("package eu.kanade.tachiyomi.extension.ko.wolfdotcom")
|
||||||
|
it.println("const val DEFAULT_DOMAIN_NUMBER = \"$domainNumber\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
preBuild.dependsOn updateDomainNumber
|
||||||
|
|
||||||
|
tasks.register('restoreBackup') {
|
||||||
|
doLast {
|
||||||
|
if (backupFile.exists()) {
|
||||||
|
println("[Wolf.com] Restoring placeholder file")
|
||||||
|
domainNumberFile.delete()
|
||||||
|
backupFile.renameTo(domainNumberFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.configureEach { task ->
|
||||||
|
if (task.name == "assembleDebug" || task.name == "assembleRelease") {
|
||||||
|
task.finalizedBy(restoreBackup)
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 2.6 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.8 KiB |
Binary file not shown.
After Width: | Height: | Size: 8.6 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.ko.wolfdotcom
|
||||||
|
|
||||||
|
const val DEFAULT_DOMAIN_NUMBER = "363"
|
|
@ -0,0 +1,59 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.ko.wolfdotcom
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import okhttp3.HttpUrl
|
||||||
|
|
||||||
|
interface UrlPartFilter {
|
||||||
|
fun addToUrl(url: HttpUrl.Builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
class FilterData(
|
||||||
|
val type: String,
|
||||||
|
private val typeDisplayName: String? = null,
|
||||||
|
val value: String?,
|
||||||
|
private val valueDisplayName: String,
|
||||||
|
) {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "$typeDisplayName: $valueDisplayName"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SearchFilter(
|
||||||
|
private val options: List<FilterData>,
|
||||||
|
) : Filter.Select<String>(
|
||||||
|
"필터",
|
||||||
|
options.map { it.toString() }.toTypedArray(),
|
||||||
|
),
|
||||||
|
UrlPartFilter {
|
||||||
|
override fun addToUrl(url: HttpUrl.Builder) {
|
||||||
|
val selected = options[state]
|
||||||
|
url.addQueryParameter("type1", selected.type)
|
||||||
|
selected.value?.let {
|
||||||
|
url.addQueryParameter("type2", it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SortFilter(default: Int = 0) :
|
||||||
|
Filter.Select<String>(
|
||||||
|
"정렬 기준",
|
||||||
|
options.map { it.first }.toTypedArray(),
|
||||||
|
default,
|
||||||
|
),
|
||||||
|
UrlPartFilter {
|
||||||
|
|
||||||
|
override fun addToUrl(url: HttpUrl.Builder) {
|
||||||
|
url.addQueryParameter("o", options[state].second)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val options = listOf(
|
||||||
|
"최신순" to "n",
|
||||||
|
"인기순" to "f",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val POPULAR = FilterList(SortFilter(1))
|
||||||
|
val LATEST = FilterList(SortFilter(0))
|
|
@ -0,0 +1,417 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.ko.wolfdotcom
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.preference.EditTextPreference
|
||||||
|
import androidx.preference.PreferenceScreen
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.IOException
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.text.ParseException
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
open class Wolf(
|
||||||
|
name: String,
|
||||||
|
private val browsePath: String,
|
||||||
|
private val entryPath: String,
|
||||||
|
private val readerPath: String,
|
||||||
|
) : HttpSource(), ConfigurableSource {
|
||||||
|
|
||||||
|
override val name = "늑대닷컴 - $name"
|
||||||
|
|
||||||
|
override val lang = "ko"
|
||||||
|
|
||||||
|
override val baseUrl: String
|
||||||
|
get() = "https://wfwf$domainNumber.com"
|
||||||
|
|
||||||
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
override val client = network.cloudflareClient.newBuilder()
|
||||||
|
.addInterceptor(::domainNumberInterceptor)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
|
private val preference: SharedPreferences by lazy {
|
||||||
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||||
|
return fetchSearchManga(page, "", POPULAR)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||||
|
return fetchSearchManga(page, "", LATEST)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var searchFilters: List<FilterData> = emptyList()
|
||||||
|
private var filterParseError = false
|
||||||
|
|
||||||
|
override fun getFilterList(): FilterList {
|
||||||
|
val filters: MutableList<Filter<*>> = mutableListOf(
|
||||||
|
SortFilter(),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (searchFilters.isNotEmpty()) {
|
||||||
|
filters.add(
|
||||||
|
SearchFilter(searchFilters),
|
||||||
|
)
|
||||||
|
} else if (filterParseError) {
|
||||||
|
filters.add(
|
||||||
|
Filter.Header("unable to parse filters"),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
filters.add(
|
||||||
|
Filter.Header("press 'reset' to attempt to load more filters"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return FilterList(filters)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected open fun parseSearchFilters(document: Document) {
|
||||||
|
if (searchFilters.isNotEmpty() || filterParseError) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
val displayName = document.select(".sub-tab > a").eachText()
|
||||||
|
assert(displayName.size == 3)
|
||||||
|
searchFilters =
|
||||||
|
document.select(".tab-day > a, .tab-genre1 > a, .tab-genre2 > a, .tab-alphabet > a")
|
||||||
|
.map {
|
||||||
|
val url = it.absUrl("href").toHttpUrl()
|
||||||
|
val type = url.queryParameter("type1")!!
|
||||||
|
FilterData(
|
||||||
|
type = type,
|
||||||
|
typeDisplayName = when (type) {
|
||||||
|
"day", "complete" -> displayName[0]
|
||||||
|
"genre" -> displayName[1]
|
||||||
|
"alphabet" -> displayName[2]
|
||||||
|
else -> null
|
||||||
|
},
|
||||||
|
value = url.queryParameter("type2"),
|
||||||
|
valueDisplayName = it.ownText(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Log.e(name, "error parsing filters", e)
|
||||||
|
filterParseError = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var browseCache: List<List<BrowseItem>>
|
||||||
|
|
||||||
|
class BrowseItem(
|
||||||
|
val id: Int,
|
||||||
|
val title: String,
|
||||||
|
val cover: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
|
if (query.isNotBlank()) {
|
||||||
|
return querySearch(query)
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (page == 1) {
|
||||||
|
client.newCall(searchMangaRequest(page, query, filters))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map {
|
||||||
|
parseBrowsePage(it)
|
||||||
|
paginatedBrowsePage(0)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Observable.just(
|
||||||
|
paginatedBrowsePage(page - 1),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
|
val url = "$baseUrl/$browsePath".toHttpUrl().newBuilder().apply {
|
||||||
|
filters.filterIsInstance<UrlPartFilter>().forEach { filter ->
|
||||||
|
filter.addToUrl(this)
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
|
||||||
|
return GET(url, headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseBrowsePage(response: Response) {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
parseSearchFilters(document)
|
||||||
|
|
||||||
|
browseCache = document.select(".webtoon-list > ul > li > a").map {
|
||||||
|
val id = it.absUrl("href").toHttpUrl()
|
||||||
|
.queryParameter("toon")!!.toInt()
|
||||||
|
|
||||||
|
BrowseItem(
|
||||||
|
id = id,
|
||||||
|
title = it.selectFirst(".txt > .subject")!!.ownText(),
|
||||||
|
cover = it.selectFirst(".img > img")?.attr("data-original"),
|
||||||
|
)
|
||||||
|
}.chunked(20)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun paginatedBrowsePage(index: Int): MangasPage {
|
||||||
|
return MangasPage(
|
||||||
|
browseCache[index].map {
|
||||||
|
SManga.create().apply {
|
||||||
|
url = it.id.toString()
|
||||||
|
title = it.title
|
||||||
|
thumbnail_url = it.cover
|
||||||
|
}
|
||||||
|
},
|
||||||
|
browseCache.lastIndex > index,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val specialChars = Regex("""[^\p{InHangul_Syllables}0-9a-z ]""", RegexOption.IGNORE_CASE)
|
||||||
|
private val styleImage = Regex("""background-image:url\(([^)]+)\)""")
|
||||||
|
|
||||||
|
private fun querySearch(query: String): Observable<MangasPage> {
|
||||||
|
if (query.length < 2) {
|
||||||
|
throw Exception("두 글자 이상 입력 해주세요.")
|
||||||
|
}
|
||||||
|
val stdQuery = query.replace(specialChars, "")
|
||||||
|
val searchUrl = "$baseUrl/search.html?q=${URLEncoder.encode(stdQuery, "EUC-KR")}"
|
||||||
|
|
||||||
|
return client.newCall(GET(searchUrl, headers))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
val document = Jsoup.parseBodyFragment(response.body.string(), searchUrl)
|
||||||
|
val entries = document.select("article.searchItem")
|
||||||
|
.filter { el ->
|
||||||
|
el.selectFirst("a.searchLink")!!.attr("href").contains(entryPath)
|
||||||
|
}
|
||||||
|
.map { el ->
|
||||||
|
val mangaUrl = el.selectFirst("a.searchLink")!!.absUrl("href")
|
||||||
|
.toHttpUrl()
|
||||||
|
SManga.create().apply {
|
||||||
|
url = mangaUrl.queryParameter("toon")!!
|
||||||
|
title = el.selectFirst(".searchDetailTitle")!!.text()
|
||||||
|
thumbnail_url = el.selectFirst(".searchPng")
|
||||||
|
?.attr("style")
|
||||||
|
?.let {
|
||||||
|
styleImage.find(it)?.groupValues?.get(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MangasPage(entries, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMangaUrl(manga: SManga): String {
|
||||||
|
return baseUrl.toHttpUrl().newBuilder()
|
||||||
|
.addPathSegment(entryPath)
|
||||||
|
.addQueryParameter("toon", manga.url)
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||||
|
return GET(getMangaUrl(manga), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
return SManga.create().apply {
|
||||||
|
title = document.selectFirst(".text-box h1")!!.text()
|
||||||
|
thumbnail_url = document.selectFirst(".img-box img")?.absUrl("src")
|
||||||
|
description = document.selectFirst(".text-box .txt")?.text()
|
||||||
|
genre = document.selectFirst(".text-box .sub:has(> strong:contains(장르))")?.ownText()?.replace("/", ", ")
|
||||||
|
author = document.selectFirst(".text-box .sub:has(> strong:contains(작가))")?.ownText()?.replace("/", ", ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun chapterListRequest(manga: SManga): Request {
|
||||||
|
return mangaDetailsRequest(manga)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class ChapterUrl(
|
||||||
|
val toon: String,
|
||||||
|
val num: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
return document.select(".webtoon-bbs-list a.view_open").map { el ->
|
||||||
|
val chapUrl = el.absUrl("href").toHttpUrl()
|
||||||
|
SChapter.create().apply {
|
||||||
|
url = json.encodeToString(
|
||||||
|
ChapterUrl(
|
||||||
|
chapUrl.queryParameter("toon")!!,
|
||||||
|
chapUrl.queryParameter("num")!!,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
name = el.selectFirst(".subject")!!.ownText()
|
||||||
|
date_upload = el.selectFirst(".date")?.text().parseDate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
|
||||||
|
|
||||||
|
private fun String?.parseDate(): Long {
|
||||||
|
this ?: return 0L
|
||||||
|
|
||||||
|
return try {
|
||||||
|
dateFormat.parse(this)!!.time
|
||||||
|
} catch (_: ParseException) {
|
||||||
|
0L
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getChapterUrl(chapter: SChapter): String {
|
||||||
|
val chapUrl = json.decodeFromString<ChapterUrl>(chapter.url)
|
||||||
|
|
||||||
|
return baseUrl.toHttpUrl().newBuilder()
|
||||||
|
.addPathSegment(readerPath)
|
||||||
|
.addQueryParameter("toon", chapUrl.toon)
|
||||||
|
.addQueryParameter("num", chapUrl.num)
|
||||||
|
.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
|
return GET(getChapterUrl(chapter), headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
return document.select(".image-view img").mapIndexed { idx, img ->
|
||||||
|
Page(idx, imageUrl = img.absUrl("data-original"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
|
EditTextPreference(screen.context).apply {
|
||||||
|
key = PREF_DOMAIN_NUM
|
||||||
|
title = "도메인 번호"
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val value = newValue as String
|
||||||
|
if (value.isEmpty() || value.toIntOrNull() == null) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
domainNumber = value.trim()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.also(screen::addPreference)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var domainNumber = ""
|
||||||
|
get() {
|
||||||
|
val currentValue = field
|
||||||
|
if (currentValue.isNotEmpty()) return currentValue
|
||||||
|
|
||||||
|
val prefValue = preference.getString(PREF_DOMAIN_NUM, "")!!
|
||||||
|
val prefDefaultValue = preference.getString(PREF_DOMAIN_NUM_DEFAULT, "")!!
|
||||||
|
|
||||||
|
if (prefDefaultValue != DEFAULT_DOMAIN_NUMBER) {
|
||||||
|
preference.edit()
|
||||||
|
.putString(PREF_DOMAIN_NUM_DEFAULT, DEFAULT_DOMAIN_NUMBER)
|
||||||
|
.putString(PREF_DOMAIN_NUM, DEFAULT_DOMAIN_NUMBER)
|
||||||
|
.apply()
|
||||||
|
|
||||||
|
field = DEFAULT_DOMAIN_NUMBER
|
||||||
|
return DEFAULT_DOMAIN_NUMBER
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefValue.isNotEmpty()) {
|
||||||
|
field = prefValue
|
||||||
|
return prefValue
|
||||||
|
}
|
||||||
|
|
||||||
|
return DEFAULT_DOMAIN_NUMBER
|
||||||
|
}
|
||||||
|
set(value) {
|
||||||
|
preference.edit().putString(PREF_DOMAIN_NUM, value).apply()
|
||||||
|
|
||||||
|
field = value
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun domainNumberInterceptor(chain: Interceptor.Chain): Response {
|
||||||
|
val request = chain.request()
|
||||||
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
|
val url = request.url.toString()
|
||||||
|
|
||||||
|
if (url.contains(domainRegex)) {
|
||||||
|
val document = Jsoup.parse(response.peekBody(Long.MAX_VALUE).string())
|
||||||
|
val newUrl = document.selectFirst("""#pop-content a[href~=^https?://wfwf\d+\.com]""")
|
||||||
|
?: return response
|
||||||
|
|
||||||
|
response.close()
|
||||||
|
|
||||||
|
val newDomainNum = domainRegex.find(newUrl.attr("href"))?.groupValues?.get(1)
|
||||||
|
?: throw IOException("Failed to update domain number")
|
||||||
|
|
||||||
|
domainNumber = newDomainNum.trim()
|
||||||
|
|
||||||
|
return chain.proceed(
|
||||||
|
request.newBuilder()
|
||||||
|
.url(
|
||||||
|
request.url.newBuilder()
|
||||||
|
.host(baseUrl.toHttpUrl().host)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response
|
||||||
|
}
|
||||||
|
|
||||||
|
private val domainRegex = Regex("""^https?://wfwf(\d+)\.com""")
|
||||||
|
|
||||||
|
override fun imageUrlParse(response: Response): String {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
override fun searchMangaParse(response: Response): MangasPage {
|
||||||
|
throw UnsupportedOperationException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const val PREF_DOMAIN_NUM = "domain_number"
|
||||||
|
private const val PREF_DOMAIN_NUM_DEFAULT = "domain_number_default"
|
|
@ -0,0 +1,21 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.ko.wolfdotcom
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
|
||||||
|
class WolfFactory : SourceFactory {
|
||||||
|
override fun createSources() = listOf(
|
||||||
|
Wolf("웹툰", "ing", "list", "view"), // webtoon
|
||||||
|
Wolf("만화책", "cm", "cl", "cv"), // comic book
|
||||||
|
object : Wolf("포토툰", "pt", "list", "view") { // phototoon
|
||||||
|
override fun getFilterList(): FilterList {
|
||||||
|
return FilterList()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun parseSearchFilters(document: Document) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
Loading…
Reference in New Issue