update Mangasee due to webpage changes (#521)

This commit is contained in:
Gilfar 2016-11-13 12:33:29 +01:00 committed by inorichi
parent b716a2f8ac
commit 36d4e1f7ef

View file

@ -1,17 +1,21 @@
package eu.kanade.tachiyomi.data.source.online.english package eu.kanade.tachiyomi.data.source.online.english
import android.content.Context
import eu.kanade.tachiyomi.data.database.models.Chapter import eu.kanade.tachiyomi.data.database.models.Chapter
import eu.kanade.tachiyomi.data.database.models.Manga import eu.kanade.tachiyomi.data.database.models.Manga
import eu.kanade.tachiyomi.data.network.POST
import eu.kanade.tachiyomi.data.source.EN import eu.kanade.tachiyomi.data.source.EN
import eu.kanade.tachiyomi.data.source.Language import eu.kanade.tachiyomi.data.source.Language
import eu.kanade.tachiyomi.data.source.model.MangasPage
import eu.kanade.tachiyomi.data.source.model.Page import eu.kanade.tachiyomi.data.source.model.Page
import eu.kanade.tachiyomi.data.source.online.ParsedOnlineSource import eu.kanade.tachiyomi.data.source.online.ParsedOnlineSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.FormBody
import okhttp3.HttpUrl
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 java.util.* import java.text.SimpleDateFormat
import java.util.regex.Pattern import java.util.regex.Pattern
class Mangasee(override val id: Int) : ParsedOnlineSource() { class Mangasee(override val id: Int) : ParsedOnlineSource() {
@ -22,104 +26,128 @@ class Mangasee(override val id: Int) : ParsedOnlineSource() {
override val lang: Language get() = EN override val lang: Language get() = EN
override val supportsLatest = false override val supportsLatest = true
private val datePattern = Pattern.compile("(\\d+)\\s+(.*?)s? (from now|ago).*") private val recentUpdatesPattern = Pattern.compile("(.*?)\\s(\\d+)")
private val dateFields = HashMap<String, Int>().apply { override fun popularMangaInitialUrl() = "$baseUrl/search/request.php?sortBy=popularity&sortOrder=descending"
put("second", Calendar.SECOND)
put("minute", Calendar.MINUTE) override fun popularMangaSelector() = "div.requested > div.row"
put("hour", Calendar.HOUR)
put("day", Calendar.DATE) override fun popularMangaRequest(page: MangasPage): Request {
put("week", Calendar.WEEK_OF_YEAR) if (page.page == 1) {
put("month", Calendar.MONTH) page.url = popularMangaInitialUrl()
put("year", Calendar.YEAR) }
val (body, requestUrl) = convertQueryToPost(page)
return POST(requestUrl, headers, body.build())
} }
private val dateRelationFields = HashMap<String, Int>().apply { override fun popularMangaParse(response: Response, page: MangasPage) {
put("from now", 1) val document = response.asJsoup()
put("ago", -1) for (element in document.select(popularMangaSelector())) {
Manga.create(id).apply {
popularMangaFromElement(element, this)
page.mangas.add(this)
}
}
page.nextPageUrl = page.url
} }
override fun popularMangaInitialUrl() = "$baseUrl/search_result.php?Action=Yes&order=popularity&numResultPerPage=20&sort=desc"
override fun popularMangaSelector() = "div.well > table > tbody > tr"
override fun popularMangaFromElement(element: Element, manga: Manga) { override fun popularMangaFromElement(element: Element, manga: Manga) {
element.select("td > h2 > a").first().let { element.select("a.resultLink").first().let {
manga.setUrlWithoutDomain("/${it.attr("href")}") manga.setUrlWithoutDomain(it.attr("href"))
manga.title = it.text() manga.title = it.text()
} }
} }
override fun popularMangaNextPageSelector() = "ul.pagination > li > a:contains(Next)" // Not used, overrides parent.
override fun popularMangaNextPageSelector() = ""
override fun searchMangaInitialUrl(query: String, filters: List<Filter>) = override fun searchMangaInitialUrl(query: String, filters: List<Filter>) =
"$baseUrl/advanced-search/result.php?sortBy=alphabet&direction=ASC&textOnly=no&resPerPage=20&page=1&seriesName=$query&${filters.map { it.id + "=Yes" }.joinToString("&")}" "$baseUrl/search/request.php?sortBy=popularity&sortOrder=descending&keyword=$query&genre=${filters.map { it.id }.joinToString(",")}"
override fun searchMangaSelector() = "div.row > div > div > div > h1" override fun searchMangaSelector() = "div.searchResults > div.requested > div.row"
override fun searchMangaRequest(page: MangasPage, query: String, filters: List<Filter>): Request {
if (page.page == 1) {
page.url = searchMangaInitialUrl(query, filters)
}
val (body, requestUrl) = convertQueryToPost(page)
return POST(requestUrl, headers, body.build())
}
private fun convertQueryToPost(page: MangasPage): Pair<FormBody.Builder, String> {
val url = HttpUrl.parse(page.url)
val body = FormBody.Builder().add("page", page.page.toString())
for (i in 0..url.querySize() - 1) {
body.add(url.queryParameterName(i), url.queryParameterValue(i))
}
val requestUrl = url.scheme() + "://" + url.host() + url.encodedPath()
return Pair(body, requestUrl)
}
override fun searchMangaParse(response: Response, page: MangasPage, query: String, filters: List<Filter>) {
val document = response.asJsoup()
for (element in document.select(popularMangaSelector())) {
Manga.create(id).apply {
popularMangaFromElement(element, this)
page.mangas.add(this)
}
}
page.nextPageUrl = page.url
}
override fun searchMangaFromElement(element: Element, manga: Manga) { override fun searchMangaFromElement(element: Element, manga: Manga) {
element.select("a").first().let { element.select("a.resultLink").first().let {
manga.setUrlWithoutDomain("/${it.attr("href")}") manga.setUrlWithoutDomain(it.attr("href"))
manga.title = it.text() manga.title = it.text()
} }
} }
override fun searchMangaNextPageSelector() = "ul.pagination > li > a:contains(Next)" // Not used, overrides parent.
override fun searchMangaNextPageSelector() = ""
override fun mangaDetailsParse(document: Document, manga: Manga) { override fun mangaDetailsParse(document: Document, manga: Manga) {
val detailElement = document.select("div.well > div.row").first() val detailElement = document.select("div.well > div.row").first()
manga.author = detailElement.select("a[href^=../search_result.php?author_name=]").first()?.text() manga.author = detailElement.select("a[href^=/search/?author=]").first()?.text()
manga.genre = detailElement.select("div > div.row > div:has(b:contains(Genre:)) > a").map { it.text() }.joinToString() manga.genre = detailElement.select("span.details > div.row > div:has(b:contains(Genre(s))) > a").map { it.text() }.joinToString()
manga.description = detailElement.select("strong:contains(Description:) + div").first()?.text() manga.description = detailElement.select("strong:contains(Description:) + div").first()?.text()
manga.status = detailElement.select("div > div.row > div:has(b:contains(Scanlation Status:))").first()?.text().orEmpty().let { parseStatus(it) } manga.status = detailElement.select("a[href^=/search/?status=]").first()?.text().orEmpty().let { parseStatus(it) }
manga.thumbnail_url = detailElement.select("div > img").first()?.absUrl("src") manga.thumbnail_url = detailElement.select("div > img").first()?.absUrl("src")
} }
private fun parseStatus(status: String) = when { private fun parseStatus(status: String) = when {
status.contains("Ongoing") -> Manga.ONGOING status.contains("Ongoing (Scan)") -> Manga.ONGOING
status.contains("Completed") -> Manga.COMPLETED status.contains("Complete (Scan)") -> Manga.COMPLETED
else -> Manga.UNKNOWN else -> Manga.UNKNOWN
} }
override fun chapterListSelector() = "div.row > div > div.row > div > div.row:has(a.chapter_link[alt])" override fun chapterListSelector() = "div.chapter-list > a"
override fun chapterFromElement(element: Element, chapter: Chapter) { override fun chapterFromElement(element: Element, chapter: Chapter) {
val urlElement = element.select("a").first() val urlElement = element.select("a").first()
chapter.setUrlWithoutDomain("/${urlElement.attr("href")}") chapter.setUrlWithoutDomain(urlElement.attr("href"))
chapter.name = urlElement.text() chapter.name = element.select("span.chapterLabel").first().text()?.let { it } ?: ""
chapter.date_upload = element.select("span").first()?.text()?.let { parseChapterDate(it) } ?: 0 chapter.date_upload = element.select("time").first()?.attr("datetime")?.let { parseChapterDate(it) } ?: 0
} }
private fun parseChapterDate(dateAsString: String): Long { private fun parseChapterDate(dateAsString: String): Long {
val m = datePattern.matcher(dateAsString) return SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateAsString).time
if (m.matches()) {
val amount = Integer.parseInt(m.group(1))
val unit = m.group(2)
val relation = m.group(3)
return Calendar.getInstance().apply {
add(dateFields[unit]!!, dateRelationFields[relation]!! * amount)
}.time.time
} else {
return 0
}
} }
override fun pageListParse(response: Response, pages: MutableList<Page>) { override fun pageListParse(response: Response, pages: MutableList<Page>) {
val document = response.asJsoup() val document = response.asJsoup()
val url = response.request().url().toString().substringBeforeLast('/') val url = response.request().url().toString().substringBeforeLast('/')
val series = document.select("input[name=series]").first().attr("value") val series = document.select("input.IndexName").first().attr("value")
val chapter = document.select("input[name=chapter]").first().attr("value") val chapter = document.select("span.CurChapter").first().text()
val index = document.select("input[name=index]").first().attr("value")
document.select("select[name=page] > option").forEach { document.select("div.ContainerNav").first().select("select.PageSelect > option").forEach {
pages.add(Page(pages.size, "$url/?series=$series&chapter=$chapter&index=$index&page=${pages.size + 1}")) pages.add(Page(pages.size, "$url/$series-chapter-$chapter-page-${pages.size + 1}.html"))
} }
pages.getOrNull(0)?.imageUrl = imageUrlParse(document) pages.getOrNull(0)?.imageUrl = imageUrlParse(document)
} }
@ -128,7 +156,7 @@ class Mangasee(override val id: Int) : ParsedOnlineSource() {
override fun pageListParse(document: Document, pages: MutableList<Page>) { override fun pageListParse(document: Document, pages: MutableList<Page>) {
} }
override fun imageUrlParse(document: Document) = document.select("div > a > img").attr("src") override fun imageUrlParse(document: Document): String = document.select("img.CurImage").attr("src")
// [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n') // [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n')
// http://mangasee.co/advanced-search/ // http://mangasee.co/advanced-search/
@ -171,20 +199,45 @@ class Mangasee(override val id: Int) : ParsedOnlineSource() {
Filter("Yuri", "Yuri") Filter("Yuri", "Yuri")
) )
override fun latestUpdatesInitialUrl(): String { override fun latestUpdatesInitialUrl(): String = "http://mangaseeonline.net/home/latest.request.php"
throw UnsupportedOperationException("not implemented")
// Not used, overrides parent.
override fun latestUpdatesNextPageSelector(): String = ""
override fun latestUpdatesSelector(): String = "a.latestSeries"
override fun latestUpdatesRequest(page: MangasPage): Request {
if (page.page == 1) {
page.url = latestUpdatesInitialUrl()
}
val (body, requestUrl) = convertQueryToPost(page)
return POST(requestUrl, headers, body.build())
} }
override fun latestUpdatesNextPageSelector(): String { override fun latestUpdatesParse(response: Response, page: MangasPage) {
throw UnsupportedOperationException("not implemented") val document = response.asJsoup()
for (element in document.select(latestUpdatesSelector())) {
Manga.create(id).apply {
latestUpdatesFromElement(element, this)
page.mangas.add(this)
}
}
page.nextPageUrl = page.url
} }
override fun latestUpdatesFromElement(element: Element, manga: Manga) { override fun latestUpdatesFromElement(element: Element, manga: Manga) {
throw UnsupportedOperationException("not implemented") element.select("a.latestSeries").first().let {
} val chapterUrl = it.attr("href")
val indexOfMangaUrl = chapterUrl.indexOf("-chapter-")
override fun latestUpdatesSelector(): String { val indexOfLastPath = chapterUrl.lastIndexOf("/")
throw UnsupportedOperationException("not implemented") val mangaUrl = chapterUrl.substring(indexOfLastPath, indexOfMangaUrl)
val defaultText = it.select("p.clamp2").text();
val m = recentUpdatesPattern.matcher(defaultText)
val title = if (m.matches()) m.group(1) else defaultText
manga.setUrlWithoutDomain("/manga" + mangaUrl)
manga.title = title
}
} }
} }