Webtoons.com: fixes (#9349)
* better compatibility with old urls * use index for chapter number as fallback * better chapter number logic * escape chapter names * fix deep link for canvas * Update build.gradle * bgm * deeplink * i + 1
This commit is contained in:
parent
621dc6c121
commit
dd47332ab9
@ -1,7 +1,7 @@
|
|||||||
ext {
|
ext {
|
||||||
extName = 'Webtoons.com'
|
extName = 'Webtoons.com'
|
||||||
extClass = '.WebtoonsFactory'
|
extClass = '.WebtoonsFactory'
|
||||||
extVersionCode = 48
|
extVersionCode = 49
|
||||||
isNsfw = false
|
isNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ class EpisodeList(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
class Episode(
|
class Episode(
|
||||||
val episodeNo: Float,
|
|
||||||
val episodeTitle: String,
|
val episodeTitle: String,
|
||||||
val viewerLink: String,
|
val viewerLink: String,
|
||||||
val exposureDateMillis: Long,
|
val exposureDateMillis: Long,
|
||||||
|
@ -23,6 +23,7 @@ import okhttp3.Request
|
|||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
import org.jsoup.parser.Parser
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.net.SocketException
|
import java.net.SocketException
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
@ -122,18 +123,23 @@ open class Webtoons(
|
|||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
if (query.startsWith(ID_SEARCH_PREFIX)) {
|
if (query.startsWith(ID_SEARCH_PREFIX)) {
|
||||||
val (_, titleLang, titleNo) = query.split(":", limit = 3)
|
val (_, type, lang, titleNo) = query.split(":", limit = 4)
|
||||||
val tmpManga = SManga.create().apply {
|
val tmpManga = SManga.create().apply {
|
||||||
url = "/episodeList?titleNo=$titleNo"
|
url = buildString {
|
||||||
|
if (type == "canvas") {
|
||||||
|
append("/challenge")
|
||||||
}
|
}
|
||||||
return if (titleLang == langCode) {
|
append("/episodeList?titleNo=")
|
||||||
|
append(titleNo)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (lang == langCode) {
|
||||||
fetchMangaDetails(tmpManga).map {
|
fetchMangaDetails(tmpManga).map {
|
||||||
MangasPage(listOf(it), false)
|
MangasPage(listOf(it), false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Observable.just(
|
Observable.just(MangasPage(emptyList(), false))
|
||||||
MangasPage(emptyList(), false),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +206,7 @@ open class Webtoons(
|
|||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initialized = true
|
||||||
thumbnail_url = run {
|
thumbnail_url = run {
|
||||||
val bannerFile = document.selectFirst(".detail_header .thmb img")
|
val bannerFile = document.selectFirst(".detail_header .thmb img")
|
||||||
?.absUrl("src")
|
?.absUrl("src")
|
||||||
@ -232,18 +238,33 @@ open class Webtoons(
|
|||||||
val webtoonUrl = getMangaUrl(manga).toHttpUrl()
|
val webtoonUrl = getMangaUrl(manga).toHttpUrl()
|
||||||
val titleId = webtoonUrl.queryParameter("title_no")
|
val titleId = webtoonUrl.queryParameter("title_no")
|
||||||
?: webtoonUrl.queryParameter("titleNo")
|
?: webtoonUrl.queryParameter("titleNo")
|
||||||
?: throw Exception("id not found, Migrate from $name to $name")
|
?: throw Exception("Migrate from $name to $name")
|
||||||
|
|
||||||
val isCanvas = webtoonUrl.pathSegments.getOrNull(1)?.equals("canvas")
|
val type = run {
|
||||||
?: throw Exception("unknown type, Migrate from $name to $name")
|
val path = webtoonUrl.pathSegments.filter(String::isNotEmpty)
|
||||||
|
|
||||||
|
// older url pattern, people have in their library
|
||||||
|
if (webtoonUrl.encodedPath.contains("episodeList")) {
|
||||||
|
when (path[0]) {
|
||||||
|
// "/episodeList?titleNo=1049"
|
||||||
|
"episodeList" -> "webtoon"
|
||||||
|
// "/challenge/episodeList?titleNo=304446"
|
||||||
|
"challenge" -> "canvas"
|
||||||
|
else -> throw Exception("Migrate from $name to $name")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// "/en/canvas/meme-girls/list?title_no=304446"
|
||||||
|
if (path[1] == "canvas") {
|
||||||
|
"canvas"
|
||||||
|
} else {
|
||||||
|
"webtoon"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val url = mobileUrl.toHttpUrl().newBuilder().apply {
|
val url = mobileUrl.toHttpUrl().newBuilder().apply {
|
||||||
addPathSegments("api/v1")
|
addPathSegments("api/v1")
|
||||||
if (isCanvas) {
|
addPathSegment(type)
|
||||||
addPathSegment("canvas")
|
|
||||||
} else {
|
|
||||||
addPathSegment("webtoon")
|
|
||||||
}
|
|
||||||
addPathSegment(titleId)
|
addPathSegment(titleId)
|
||||||
addPathSegment("episodes")
|
addPathSegment("episodes")
|
||||||
addQueryParameter("pageSize", "99999")
|
addQueryParameter("pageSize", "99999")
|
||||||
@ -255,18 +276,54 @@ open class Webtoons(
|
|||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val result = response.parseAs<EpisodeListResponse>()
|
val result = response.parseAs<EpisodeListResponse>()
|
||||||
|
|
||||||
return result.result.episodeList.map { episode ->
|
val recognized: MutableList<Int> = mutableListOf()
|
||||||
|
val unrecognized: MutableList<Int> = mutableListOf()
|
||||||
|
|
||||||
|
val chapters = result.result.episodeList.mapIndexed { index, episode ->
|
||||||
SChapter.create().apply {
|
SChapter.create().apply {
|
||||||
url = episode.viewerLink
|
url = episode.viewerLink
|
||||||
name = episode.episodeTitle
|
name = Parser.unescapeEntities(episode.episodeTitle, false)
|
||||||
if (episode.hasBgm) {
|
if (episode.hasBgm) {
|
||||||
name += " ♫"
|
name += " ♫"
|
||||||
}
|
}
|
||||||
date_upload = episode.exposureDateMillis
|
date_upload = episode.exposureDateMillis
|
||||||
chapter_number = episode.episodeNo
|
chapter_number = episodeNoRegex
|
||||||
|
.find(episode.episodeTitle)
|
||||||
|
?.groupValues
|
||||||
|
?.get(4)
|
||||||
|
?.toFloat()
|
||||||
|
?: -1f
|
||||||
|
if (chapter_number == -1f) {
|
||||||
|
unrecognized += index
|
||||||
|
} else {
|
||||||
|
recognized += index
|
||||||
}
|
}
|
||||||
}.asReversed()
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (unrecognized.size > recognized.size) {
|
||||||
|
chapters.onEachIndexed { index, chapter ->
|
||||||
|
chapter.chapter_number = (index + 1).toFloat()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unrecognized.forEach { uIdx ->
|
||||||
|
val chapter = chapters[uIdx]
|
||||||
|
val previous = chapters.getOrNull(uIdx - 1)
|
||||||
|
if (previous == null) {
|
||||||
|
chapter.chapter_number = 0f
|
||||||
|
} else {
|
||||||
|
chapter.chapter_number = previous.chapter_number + 0.01f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return chapters.asReversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val episodeNoRegex = Regex(
|
||||||
|
"""(ep(isode)?|ch(apter)?)\s*\.?\s*(\d+(\.\d+)?)""",
|
||||||
|
RegexOption.IGNORE_CASE,
|
||||||
|
)
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
@ -23,11 +23,13 @@ class WebtoonsUrlActivity : Activity() {
|
|||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val titleNo = intent?.data?.getQueryParameter("title_no")
|
val titleNo = intent?.data?.getQueryParameter("title_no")
|
||||||
val lang = intent?.data?.pathSegments?.get(0)
|
val path = intent?.data?.pathSegments
|
||||||
if (titleNo != null) {
|
if (titleNo != null && path != null && path.size >= 3) {
|
||||||
|
val lang = path[0]
|
||||||
|
val type = path[1]
|
||||||
val mainIntent = Intent().apply {
|
val mainIntent = Intent().apply {
|
||||||
action = "eu.kanade.tachiyomi.SEARCH"
|
action = "eu.kanade.tachiyomi.SEARCH"
|
||||||
putExtra("query", "$ID_SEARCH_PREFIX$lang:$titleNo")
|
putExtra("query", "$ID_SEARCH_PREFIX$type:$lang:$titleNo")
|
||||||
putExtra("filter", packageName)
|
putExtra("filter", packageName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user