This commit is contained in:
Mike 2019-07-21 11:58:11 -04:00 committed by Eugene
parent 5b58d5458a
commit 038a6fece4
3 changed files with 82 additions and 75 deletions

View File

@ -5,7 +5,7 @@ ext {
appName = 'Tachiyomi: Naver Comic' appName = 'Tachiyomi: Naver Comic'
pkgNameSuffix = 'ko.navercomic' pkgNameSuffix = 'ko.navercomic'
extClass = '.NaverComicFactory' extClass = '.NaverComicFactory'
extVersionCode = 1 extVersionCode = 2
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -4,9 +4,12 @@ import android.annotation.SuppressLint
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.Request import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Response
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class NaverWebtoon : NaverComicBase("webtoon") { class NaverWebtoon : NaverComicBase("webtoon") {
override val name = "Naver Webtoon" override val name = "Naver Webtoon"
@ -34,41 +37,58 @@ class NaverWebtoon : NaverComicBase("webtoon") {
class NaverBestChallenge : NaverComicChallengeBase("bestChallenge") { class NaverBestChallenge : NaverComicChallengeBase("bestChallenge") {
override val name = "Naver Webtoon Best Challenge" override val name = "Naver Webtoon Best Challenge"
override fun popularMangaRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn") override fun popularMangaRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn?m=main&order=StarScore")
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn?m=main&order=Update") override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn?m=main&order=Update")
} }
class NaverChallenge : NaverComicChallengeBase("challenge") { class NaverChallenge : NaverComicChallengeBase("challenge") {
override val name = "Naver Webtoon Challenge" override val name = "Naver Webtoon Challenge"
override fun popularMangaRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn") override fun popularMangaRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn")
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn?m=list&order=Update") override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/genre/$mType.nhn?m=list&order=Update")
// Need to override again because there's no mobile page. // Chapter list is paginated, but there are no mobile pages to work with
override fun chapterPagedListRequest(manga: SManga, page: Int): Request { override fun chapterListRequest(manga: SManga) = GET("$baseUrl${manga.url}", headers)
return GET("$baseUrl${manga.url}&page=$page")
override fun chapterListSelector() = "tbody tr:not([class])"
override fun chapterListParse(response: Response): List<SChapter> {
var document = response.asJsoup()
val chapters = mutableListOf<SChapter>()
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
while (document.select(paginationNextPageSelector).hasText()) {
document.select(paginationNextPageSelector).let {
document = client.newCall(GET(it.attr("abs:href"))).execute().asJsoup()
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
}
}
return chapters
} }
override fun chapterListSelector() = ".viewList > tbody > tr:not([class])" override val paginationNextPageSelector = "div.paginate a.next"
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val nameElement = element.select("td.title > a").first()
val rawName = nameElement.text().trim()
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.url = nameElement.attr("src") element.select("td + td a").let {
chapter.chapter_number = parseChapterNumber(rawName) val rawName = it.text()
chapter.name = rawName chapter.url = it.attr("href")
chapter.date_upload = parseChapterDate(element.select("td.num").last().text().trim()) chapter.chapter_number = parseChapterNumber(rawName)
chapter.name = rawName
chapter.date_upload = parseChapterDate(element.select("td.num").text().trim())
}
return chapter return chapter
} }
@SuppressLint("SimpleDateFormat") @SuppressLint("SimpleDateFormat")
private fun parseChapterDate(date: String): Long { private fun parseChapterDate(date: String): Long {
return try { return if (date.contains(":")) { Calendar.getInstance().timeInMillis
SimpleDateFormat("yyyy.MM.dd").parse(date).time } else {
} catch (e: Exception) { return try {
e.printStackTrace() SimpleDateFormat("yyyy.MM.dd", Locale.KOREA).parse(date).time
0 } catch (e: Exception) {
e.printStackTrace()
0
}
} }
} }
} }

View File

@ -2,18 +2,20 @@ package eu.kanade.tachiyomi.extension.ko.navercomic
import android.annotation.SuppressLint import android.annotation.SuppressLint
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
abstract class NaverComicBase(protected val mType: String) : ParsedHttpSource() { abstract class NaverComicBase(protected val mType: String) : ParsedHttpSource() {
override val lang: String = "ko" override val lang: String = "ko"
@ -23,70 +25,53 @@ abstract class NaverComicBase(protected val mType: String) : ParsedHttpSource()
override val client: OkHttpClient = network.client override val client: OkHttpClient = network.client
private val mobileHeaders = super.headersBuilder() private val mobileHeaders = super.headersBuilder()
.add("Referer", mobileUrl) .add("Referer", mobileUrl)
.build() .build()
override fun searchMangaSelector() = ".resultList > li h5 > a" override fun searchMangaSelector() = ".resultList > li h5 > a"
override fun searchMangaNextPageSelector() = ".paginate a.next" override fun searchMangaNextPageSelector() = ".paginate a.next"
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("search.nhn?m=$mType&keyword=$query&type=title&page=$page") override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/search.nhn?m=$mType&keyword=$query&type=title&page=$page")
override fun searchMangaFromElement(element: Element): SManga { override fun searchMangaFromElement(element: Element): SManga {
val url = element.attr("href").substringBefore("&week").substringBefore("&listPage=")
val manga = SManga.create() val manga = SManga.create()
manga.url = url manga.url = element.attr("href").substringBefore("&week").substringBefore("&listPage=")
manga.title = element.text().trim() manga.title = element.text().trim()
return manga return manga
} }
override fun chapterListSelector() = "#ct > .toon_lst.lst2 > li > div a" override fun chapterListSelector() = "div#ct > ul.section_episode_list li.item"
// Need to override because the chapter list is paginated. // Chapter list is paginated, use mobile version of site for speed and data savings
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = fetchChapterList(manga, 1) override fun chapterListRequest(manga: SManga) = chapterListRequest(manga.url, 1)
private fun fetchChapterList(manga: SManga, page: Int, private fun chapterListRequest(mangaUrl: String, page: Int): Request {
pastChapters: List<SChapter> = emptyList()): Observable<List<SChapter>> { return GET("$mobileUrl$mangaUrl&page=$page", mobileHeaders)
val chapters = pastChapters.toMutableList() }
fun isSamePage(list: List<SChapter>): Boolean = try {
chapters.last().url == list.last().url override fun chapterListParse(response: Response): List<SChapter> {
} catch (_: Exception) { var document = response.asJsoup()
false val chapters = mutableListOf<SChapter>()
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
var nextPage = 2
while (document.select(paginationNextPageSelector).isNotEmpty()) {
document.select(paginationNextPageSelector).let {
document = client.newCall(chapterListRequest(it.attr("href"), nextPage)).execute().asJsoup()
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
nextPage++
}
} }
return chapters
return fetchChapterListPage(manga, page)
.flatMap {
if (isSamePage(it)) {
Observable.just(chapters)
} else {
chapters += it
fetchChapterList(manga, page + 1, chapters)
}
}
} }
private fun fetchChapterListPage(manga: SManga, page: Int): Observable<List<SChapter>> { open val paginationNextPageSelector = "a.btn_next:not(.disabled)"
return client.newCall(chapterPagedListRequest(manga, page))
.asObservableSuccess()
.map { response ->
chapterListParse(response)
}
}
override fun chapterListRequest(manga: SManga): Request {
return chapterPagedListRequest(manga, 1)
}
open fun chapterPagedListRequest(manga: SManga, page: Int): Request {
return GET("$mobileUrl${manga.url}&page=$page", mobileHeaders)
}
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val rawName = element.select(".toon_name > strong").last().ownText()
val url = element.attr("href").substringBefore("&week").substringBefore("&listPage")
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.url = url val rawName = element.select("span.name").text()
chapter.url = element.select("a").attr("href")
chapter.chapter_number = parseChapterNumber(rawName) chapter.chapter_number = parseChapterNumber(rawName)
chapter.name = rawName chapter.name = rawName
chapter.date_upload = parseChapterDate(element.select(".toon_detail_info .if1").last().text().trim()) chapter.date_upload = parseChapterDate(element.select("span.date").text().trim())
return chapter return chapter
} }
@ -106,11 +91,14 @@ abstract class NaverComicBase(protected val mType: String) : ParsedHttpSource()
@SuppressLint("SimpleDateFormat") @SuppressLint("SimpleDateFormat")
private fun parseChapterDate(date: String): Long { private fun parseChapterDate(date: String): Long {
return try { return if (date.contains(":")) { Calendar.getInstance().timeInMillis
SimpleDateFormat("YY.MM.dd").parse(date).time } else {
} catch (e: Exception) { return try {
e.printStackTrace() SimpleDateFormat("yy.MM.dd", Locale.KOREA).parse(date).time
0 } catch (e: Exception) {
e.printStackTrace()
0
}
} }
} }
@ -121,12 +109,11 @@ abstract class NaverComicBase(protected val mType: String) : ParsedHttpSource()
val manga = SManga.create() val manga = SManga.create()
manga.title = titleElement.first().ownText().trim() manga.title = titleElement.first().ownText().trim()
manga.author = titleElement.select("span").text().trim() manga.author = titleElement.select("span").text().trim()
manga.description = document.select(".comicinfo > p").text().trim() manga.description = document.select("div.detail p").text().trim()
manga.thumbnail_url = element.select(".thumb > a > img").last().attr("src") manga.thumbnail_url = element.select(".thumb > a > img").last().attr("src")
return manga return manga
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>() val pages = mutableListOf<Page>()
try { try {
@ -167,4 +154,4 @@ abstract class NaverComicChallengeBase(mType: String) : NaverComicBase(mType) {
override fun latestUpdatesSelector() = popularMangaSelector() override fun latestUpdatesSelector() = popularMangaSelector()
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector() override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element) override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
} }