commit
83b684c37d
@ -1,31 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.english
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.Source
|
|
||||||
import eu.kanade.tachiyomi.source.model.Page
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import rx.Observable
|
|
||||||
|
|
||||||
class Batoto : Source {
|
|
||||||
|
|
||||||
override val id: Long = 1
|
|
||||||
|
|
||||||
override val name = "Batoto"
|
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
|
||||||
return Observable.error(Exception("RIP Batoto"))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
|
||||||
return Observable.error(Exception("RIP Batoto"))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
|
||||||
return Observable.error(Exception("RIP Batoto"))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString(): String {
|
|
||||||
return "$name (EN)"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,231 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.english
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class Mangafox : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val id: Long = 3
|
|
||||||
|
|
||||||
override val name = "Mangafox"
|
|
||||||
|
|
||||||
override val baseUrl = "http://mangafox.la"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div#mangalist > ul.list > li"
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
val pageStr = if (page != 1) "$page.htm" else ""
|
|
||||||
return GET("$baseUrl/directory/$pageStr", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = "div#mangalist > ul.list > li"
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
val pageStr = if (page != 1) "$page.htm" else ""
|
|
||||||
return GET("$baseUrl/directory/$pageStr?latest")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("a.title").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.text()
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
return popularMangaFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "a:has(span.next)"
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = "a:has(span.next)"
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val url = HttpUrl.parse("$baseUrl/search.php?name_method=cw&author_method=cw&artist_method=cw&advopts=1")!!.newBuilder().addQueryParameter("name", query)
|
|
||||||
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
|
|
||||||
when (filter) {
|
|
||||||
is Status -> url.addQueryParameter(filter.id, filter.state.toString())
|
|
||||||
is GenreList -> filter.state.forEach { genre -> url.addQueryParameter(genre.id, genre.state.toString()) }
|
|
||||||
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
|
||||||
is Type -> url.addQueryParameter("type", if (filter.state == 0) "" else filter.state.toString())
|
|
||||||
is OrderBy -> {
|
|
||||||
url.addQueryParameter("sort", arrayOf("name", "rating", "views", "total_chapters", "last_chapter_time")[filter.state!!.index])
|
|
||||||
url.addQueryParameter("order", if (filter.state?.ascending == true) "az" else "za")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
url.addQueryParameter("page", page.toString())
|
|
||||||
return GET(url.toString(), headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = "div#mangalist > ul.list > li"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("a.title").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.text()
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "a:has(span.next)"
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val infoElement = document.select("div#title").first()
|
|
||||||
val rowElement = infoElement.select("table > tbody > tr:eq(1)").first()
|
|
||||||
val sideInfoElement = document.select("#series_info").first()
|
|
||||||
val licensedElement = document.select("div.warning").first()
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.author = rowElement.select("td:eq(1)").first()?.text()
|
|
||||||
manga.artist = rowElement.select("td:eq(2)").first()?.text()
|
|
||||||
manga.genre = rowElement.select("td:eq(3)").first()?.text()
|
|
||||||
manga.description = infoElement.select("p.summary").first()?.text()
|
|
||||||
val isLicensed = licensedElement?.text()?.contains("licensed")
|
|
||||||
if (isLicensed == true) {
|
|
||||||
manga.status = SManga.LICENSED
|
|
||||||
} else {
|
|
||||||
manga.status = sideInfoElement.select(".data").first()?.text().orEmpty().let { parseStatus(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
manga.thumbnail_url = sideInfoElement.select("div.cover > img").first()?.attr("src")
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String) = when {
|
|
||||||
status.contains("Ongoing") -> SManga.ONGOING
|
|
||||||
status.contains("Completed") -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "div#chapters li div"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val urlElement = element.select("a.tips").first()
|
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = element.select("span.title.nowrap").first()?.text()?.let { urlElement.text() + " - " + it } ?: urlElement.text()
|
|
||||||
chapter.date_upload = element.select("span.date").first()?.text()?.let { parseChapterDate(it) } ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long {
|
|
||||||
return if ("Today" in date || " ago" in date) {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
set(Calendar.HOUR_OF_DAY, 0)
|
|
||||||
set(Calendar.MINUTE, 0)
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
}.timeInMillis
|
|
||||||
} else if ("Yesterday" in date) {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
add(Calendar.DATE, -1)
|
|
||||||
set(Calendar.HOUR_OF_DAY, 0)
|
|
||||||
set(Calendar.MINUTE, 0)
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
}.timeInMillis
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
0L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val url = document.baseUri().substringBeforeLast('/')
|
|
||||||
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
document.select("select.m").first()?.select("option:not([value=0])")?.forEach {
|
|
||||||
pages.add(Page(pages.size, "$url/${it.attr("value")}.html"))
|
|
||||||
}
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String {
|
|
||||||
val url = document.getElementById("image").attr("src")
|
|
||||||
return if ("compressed?token=" !in url) {
|
|
||||||
url
|
|
||||||
} else {
|
|
||||||
"http://mangafox.me/media/logo.png"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Status(val id: String = "is_completed") : Filter.TriState("Completed")
|
|
||||||
private class Genre(name: String, val id: String = "genres[$name]") : Filter.TriState(name)
|
|
||||||
private class TextField(name: String, val key: String) : Filter.Text(name)
|
|
||||||
private class Type : Filter.Select<String>("Type", arrayOf("Any", "Japanese Manga", "Korean Manhwa", "Chinese Manhua"))
|
|
||||||
private class OrderBy : Filter.Sort("Order by",
|
|
||||||
arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"),
|
|
||||||
Filter.Sort.Selection(2, false))
|
|
||||||
|
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
|
||||||
TextField("Author", "author"),
|
|
||||||
TextField("Artist", "artist"),
|
|
||||||
Type(),
|
|
||||||
Status(),
|
|
||||||
OrderBy(),
|
|
||||||
GenreList(getGenreList())
|
|
||||||
)
|
|
||||||
|
|
||||||
// $('select.genres').map((i,el)=>`Genre("${$(el).next().text().trim()}", "${$(el).attr('name')}")`).get().join(',\n')
|
|
||||||
// on http://mangafox.me/search.php
|
|
||||||
private fun getGenreList() = listOf(
|
|
||||||
Genre("Action"),
|
|
||||||
Genre("Adult"),
|
|
||||||
Genre("Adventure"),
|
|
||||||
Genre("Comedy"),
|
|
||||||
Genre("Doujinshi"),
|
|
||||||
Genre("Drama"),
|
|
||||||
Genre("Ecchi"),
|
|
||||||
Genre("Fantasy"),
|
|
||||||
Genre("Gender Bender"),
|
|
||||||
Genre("Harem"),
|
|
||||||
Genre("Historical"),
|
|
||||||
Genre("Horror"),
|
|
||||||
Genre("Josei"),
|
|
||||||
Genre("Martial Arts"),
|
|
||||||
Genre("Mature"),
|
|
||||||
Genre("Mecha"),
|
|
||||||
Genre("Mystery"),
|
|
||||||
Genre("One Shot"),
|
|
||||||
Genre("Psychological"),
|
|
||||||
Genre("Romance"),
|
|
||||||
Genre("School Life"),
|
|
||||||
Genre("Sci-fi"),
|
|
||||||
Genre("Seinen"),
|
|
||||||
Genre("Shoujo"),
|
|
||||||
Genre("Shoujo Ai"),
|
|
||||||
Genre("Shounen"),
|
|
||||||
Genre("Shounen Ai"),
|
|
||||||
Genre("Slice of Life"),
|
|
||||||
Genre("Smut"),
|
|
||||||
Genre("Sports"),
|
|
||||||
Genre("Supernatural"),
|
|
||||||
Genre("Tragedy"),
|
|
||||||
Genre("Webtoons"),
|
|
||||||
Genre("Yaoi"),
|
|
||||||
Genre("Yuri")
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
@ -1,259 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.english
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.security.SecureRandom
|
|
||||||
import java.security.cert.X509Certificate
|
|
||||||
import java.text.ParseException
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.*
|
|
||||||
import javax.net.ssl.SSLContext
|
|
||||||
import javax.net.ssl.X509TrustManager
|
|
||||||
|
|
||||||
class Mangahere : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val id: Long = 2
|
|
||||||
|
|
||||||
override val name = "Mangahere"
|
|
||||||
|
|
||||||
override val baseUrl = "http://www.mangahere.cc"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
private val trustManager = object : X509TrustManager {
|
|
||||||
override fun getAcceptedIssuers(): Array<X509Certificate> {
|
|
||||||
return emptyArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val sslContext = SSLContext.getInstance("SSL").apply {
|
|
||||||
init(null, arrayOf(trustManager), SecureRandom())
|
|
||||||
}
|
|
||||||
|
|
||||||
override val client = super.client.newBuilder()
|
|
||||||
.sslSocketFactory(sslContext.socketFactory, trustManager)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.directory_list > ul > li"
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = "div.directory_list > ul > li"
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/directory/$page.htm?views.za", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/directory/$page.htm?last_chapter_time.za", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun mangaFromElement(query: String, element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select(query).first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = if (it.hasAttr("title")) it.attr("title") else if (it.hasAttr("rel")) it.attr("rel") else it.text()
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
return mangaFromElement("div.title > a", element)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
return popularMangaFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "div.next-page > a.next"
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = "div.next-page > a.next"
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val url = HttpUrl.parse("$baseUrl/search.php?name_method=cw&author_method=cw&artist_method=cw&advopts=1")!!.newBuilder().addQueryParameter("name", query)
|
|
||||||
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
|
|
||||||
when (filter) {
|
|
||||||
is Status -> url.addQueryParameter("is_completed", arrayOf("", "1", "0")[filter.state])
|
|
||||||
is GenreList -> filter.state.forEach { genre -> url.addQueryParameter(genre.id, genre.state.toString()) }
|
|
||||||
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
|
||||||
is Type -> url.addQueryParameter("direction", arrayOf("", "rl", "lr")[filter.state])
|
|
||||||
is OrderBy -> {
|
|
||||||
url.addQueryParameter("sort", arrayOf("name", "rating", "views", "total_chapters", "last_chapter_time")[filter.state!!.index])
|
|
||||||
url.addQueryParameter("order", if (filter.state?.ascending == true) "az" else "za")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
url.addQueryParameter("page", page.toString())
|
|
||||||
return GET(url.toString(), headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = "div.result_search > dl:has(dt)"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
|
||||||
return mangaFromElement("a.manga_info", element)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "div.next-page > a.next"
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val detailElement = document.select(".manga_detail_top").first()
|
|
||||||
val infoElement = detailElement.select(".detail_topText").first()
|
|
||||||
val licensedElement = document.select(".mt10.color_ff00.mb10").first()
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.author = infoElement.select("a[href*=author/]").first()?.text()
|
|
||||||
manga.artist = infoElement.select("a[href*=artist/]").first()?.text()
|
|
||||||
manga.genre = infoElement.select("li:eq(3)").first()?.text()?.substringAfter("Genre(s):")
|
|
||||||
manga.description = infoElement.select("#show").first()?.text()?.substringBeforeLast("Show less")
|
|
||||||
manga.thumbnail_url = detailElement.select("img.img").first()?.attr("src")
|
|
||||||
|
|
||||||
if (licensedElement?.text()?.contains("licensed") == true) {
|
|
||||||
manga.status = SManga.LICENSED
|
|
||||||
} else {
|
|
||||||
manga.status = infoElement.select("li:eq(6)").first()?.text().orEmpty().let { parseStatus(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String) = when {
|
|
||||||
status.contains("Ongoing") -> SManga.ONGOING
|
|
||||||
status.contains("Completed") -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = ".detail_list > ul:not([class]) > li"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val parentEl = element.select("span.left").first()
|
|
||||||
|
|
||||||
val urlElement = parentEl.select("a").first()
|
|
||||||
|
|
||||||
var volume = parentEl.select("span.mr6")?.first()?.text()?.trim() ?: ""
|
|
||||||
if (volume.length > 0) {
|
|
||||||
volume = " - " + volume
|
|
||||||
}
|
|
||||||
|
|
||||||
var title = parentEl?.textNodes()?.last()?.text()?.trim() ?: ""
|
|
||||||
if (title.length > 0) {
|
|
||||||
title = " - " + title
|
|
||||||
}
|
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = urlElement.text() + volume + title
|
|
||||||
chapter.date_upload = element.select("span.right").first()?.text()?.let { parseChapterDate(it) } ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long {
|
|
||||||
return if ("Today" in date) {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
set(Calendar.HOUR_OF_DAY, 0)
|
|
||||||
set(Calendar.MINUTE, 0)
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
}.timeInMillis
|
|
||||||
} else if ("Yesterday" in date) {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
add(Calendar.DATE, -1)
|
|
||||||
set(Calendar.HOUR_OF_DAY, 0)
|
|
||||||
set(Calendar.MINUTE, 0)
|
|
||||||
set(Calendar.SECOND, 0)
|
|
||||||
set(Calendar.MILLISECOND, 0)
|
|
||||||
}.timeInMillis
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time
|
|
||||||
} catch (e: ParseException) {
|
|
||||||
0L
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val licensedError = document.select(".mangaread_error > .mt10").first()
|
|
||||||
if (licensedError != null) {
|
|
||||||
throw Exception(licensedError.text())
|
|
||||||
}
|
|
||||||
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
document.select("select.wid60").first()?.getElementsByTag("option")?.forEach {
|
|
||||||
if (!it.attr("value").contains("featured.html")) {
|
|
||||||
pages.add(Page(pages.size, "http:" + it.attr("value")))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pages.getOrNull(0)?.imageUrl = imageUrlParse(document)
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = document.getElementById("image").attr("src")
|
|
||||||
|
|
||||||
private class Status : Filter.TriState("Completed")
|
|
||||||
private class Genre(name: String, val id: String = "genres[$name]") : Filter.TriState(name)
|
|
||||||
private class TextField(name: String, val key: String) : Filter.Text(name)
|
|
||||||
private class Type : Filter.Select<String>("Type", arrayOf("Any", "Japanese Manga (read from right to left)", "Korean Manhwa (read from left to right)"))
|
|
||||||
private class OrderBy : Filter.Sort("Order by",
|
|
||||||
arrayOf("Series name", "Rating", "Views", "Total chapters", "Last chapter"),
|
|
||||||
Filter.Sort.Selection(2, false))
|
|
||||||
|
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
|
||||||
TextField("Author", "author"),
|
|
||||||
TextField("Artist", "artist"),
|
|
||||||
Type(),
|
|
||||||
Status(),
|
|
||||||
OrderBy(),
|
|
||||||
GenreList(getGenreList())
|
|
||||||
)
|
|
||||||
|
|
||||||
// [...document.querySelectorAll("select[id^='genres'")].map((el,i) => `Genre("${el.nextSibling.nextSibling.textContent.trim()}", "${el.getAttribute('name')}")`).join(',\n')
|
|
||||||
// http://www.mangahere.co/advsearch.htm
|
|
||||||
private fun getGenreList() = listOf(
|
|
||||||
Genre("Action"),
|
|
||||||
Genre("Adventure"),
|
|
||||||
Genre("Comedy"),
|
|
||||||
Genre("Doujinshi"),
|
|
||||||
Genre("Drama"),
|
|
||||||
Genre("Ecchi"),
|
|
||||||
Genre("Fantasy"),
|
|
||||||
Genre("Gender Bender"),
|
|
||||||
Genre("Harem"),
|
|
||||||
Genre("Historical"),
|
|
||||||
Genre("Horror"),
|
|
||||||
Genre("Josei"),
|
|
||||||
Genre("Martial Arts"),
|
|
||||||
Genre("Mature"),
|
|
||||||
Genre("Mecha"),
|
|
||||||
Genre("Mystery"),
|
|
||||||
Genre("One Shot"),
|
|
||||||
Genre("Psychological"),
|
|
||||||
Genre("Romance"),
|
|
||||||
Genre("School Life"),
|
|
||||||
Genre("Sci-fi"),
|
|
||||||
Genre("Seinen"),
|
|
||||||
Genre("Shoujo"),
|
|
||||||
Genre("Shoujo Ai"),
|
|
||||||
Genre("Shounen"),
|
|
||||||
Genre("Shounen Ai"),
|
|
||||||
Genre("Slice of Life"),
|
|
||||||
Genre("Sports"),
|
|
||||||
Genre("Supernatural"),
|
|
||||||
Genre("Tragedy"),
|
|
||||||
Genre("Yaoi"),
|
|
||||||
Genre("Yuri")
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
@ -1,249 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.english
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.POST
|
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|
||||||
import okhttp3.FormBody
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.regex.Pattern
|
|
||||||
|
|
||||||
class Mangasee : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val id: Long = 9
|
|
||||||
|
|
||||||
override val name = "Mangasee"
|
|
||||||
|
|
||||||
override val baseUrl = "http://mangaseeonline.us"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
private val recentUpdatesPattern = Pattern.compile("(.*?)\\s(\\d+\\.?\\d*)\\s?(Completed)?")
|
|
||||||
|
|
||||||
private val indexPattern = Pattern.compile("-index-(.*?)-")
|
|
||||||
|
|
||||||
private val catalogHeaders = Headers.Builder().apply {
|
|
||||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
|
||||||
add("Host", "mangaseeonline.us")
|
|
||||||
}.build()
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.requested > div.row"
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
val (body, requestUrl) = convertQueryToPost(page, "$baseUrl/search/request.php?sortBy=popularity&sortOrder=descending")
|
|
||||||
return POST(requestUrl, catalogHeaders, body.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("a.resultLink").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.text()
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "button.requestMore"
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = "div.requested > div.row"
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val url = HttpUrl.parse("$baseUrl/search/request.php")!!.newBuilder()
|
|
||||||
if (!query.isEmpty()) url.addQueryParameter("keyword", query)
|
|
||||||
val genres = mutableListOf<String>()
|
|
||||||
val genresNo = mutableListOf<String>()
|
|
||||||
for (filter in if (filters.isEmpty()) getFilterList() else filters) {
|
|
||||||
when (filter) {
|
|
||||||
is Sort -> {
|
|
||||||
if (filter.state?.index != 0)
|
|
||||||
url.addQueryParameter("sortBy", if (filter.state?.index == 1) "dateUpdated" else "popularity")
|
|
||||||
if (filter.state?.ascending != true)
|
|
||||||
url.addQueryParameter("sortOrder", "descending")
|
|
||||||
}
|
|
||||||
is SelectField -> if (filter.state != 0) url.addQueryParameter(filter.key, filter.values[filter.state])
|
|
||||||
is TextField -> if (!filter.state.isEmpty()) url.addQueryParameter(filter.key, filter.state)
|
|
||||||
is GenreList -> filter.state.forEach { genre ->
|
|
||||||
when (genre.state) {
|
|
||||||
Filter.TriState.STATE_INCLUDE -> genres.add(genre.name)
|
|
||||||
Filter.TriState.STATE_EXCLUDE -> genresNo.add(genre.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (genres.isNotEmpty()) url.addQueryParameter("genre", genres.joinToString(","))
|
|
||||||
if (genresNo.isNotEmpty()) url.addQueryParameter("genreNo", genresNo.joinToString(","))
|
|
||||||
|
|
||||||
val (body, requestUrl) = convertQueryToPost(page, url.toString())
|
|
||||||
return POST(requestUrl, catalogHeaders, body.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertQueryToPost(page: Int, url: String): Pair<FormBody.Builder, String> {
|
|
||||||
val url = HttpUrl.parse(url)!!
|
|
||||||
val body = FormBody.Builder().add("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 searchMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("a.resultLink").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.text()
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "button.requestMore"
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val detailElement = document.select("div.well > div.row").first()
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.author = detailElement.select("a[href^=/search/?author=]").first()?.text()
|
|
||||||
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.status = detailElement.select("a[href^=/search/?status=]").first()?.text().orEmpty().let { parseStatus(it) }
|
|
||||||
manga.thumbnail_url = detailElement.select("div > img").first()?.absUrl("src")
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String) = when {
|
|
||||||
status.contains("Ongoing (Scan)") -> SManga.ONGOING
|
|
||||||
status.contains("Complete (Scan)") -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "div.chapter-list > a"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val urlElement = element.select("a").first()
|
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = element.select("span.chapterLabel").first().text()?.let { it } ?: ""
|
|
||||||
chapter.date_upload = element.select("time").first()?.attr("datetime")?.let { parseChapterDate(it) } ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(dateAsString: String): Long {
|
|
||||||
return SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(dateAsString).time
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val fullUrl = document.baseUri()
|
|
||||||
val url = fullUrl.substringBeforeLast('/')
|
|
||||||
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
|
|
||||||
val series = document.select("input.IndexName").first().attr("value")
|
|
||||||
val chapter = document.select("span.CurChapter").first().text()
|
|
||||||
var index = ""
|
|
||||||
|
|
||||||
val m = indexPattern.matcher(fullUrl)
|
|
||||||
if (m.find()) {
|
|
||||||
val indexNumber = m.group(1)
|
|
||||||
index = "-index-$indexNumber"
|
|
||||||
}
|
|
||||||
|
|
||||||
document.select("div.ContainerNav").first().select("select.PageSelect > option").forEach {
|
|
||||||
pages.add(Page(pages.size, "$url/$series-chapter-$chapter$index-page-${pages.size + 1}.html"))
|
|
||||||
}
|
|
||||||
pages.getOrNull(0)?.imageUrl = imageUrlParse(document)
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = document.select("img.CurImage").attr("src")
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = "button.requestMore"
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector(): String = "a.latestSeries"
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
val url = "http://mangaseeonline.net/home/latest.request.php"
|
|
||||||
val (body, requestUrl) = convertQueryToPost(page, url)
|
|
||||||
return POST(requestUrl, catalogHeaders, body.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("a.latestSeries").first().let {
|
|
||||||
val chapterUrl = it.attr("href")
|
|
||||||
val indexOfMangaUrl = chapterUrl.indexOf("-chapter-")
|
|
||||||
val indexOfLastPath = chapterUrl.lastIndexOf("/")
|
|
||||||
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
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Sort : Filter.Sort("Sort", arrayOf("Alphabetically", "Date updated", "Popularity"), Filter.Sort.Selection(2, false))
|
|
||||||
private class Genre(name: String) : Filter.TriState(name)
|
|
||||||
private class TextField(name: String, val key: String) : Filter.Text(name)
|
|
||||||
private class SelectField(name: String, val key: String, values: Array<String>, state: Int = 0) : Filter.Select<String>(name, values, state)
|
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
|
||||||
TextField("Years", "year"),
|
|
||||||
TextField("Author", "author"),
|
|
||||||
SelectField("Scan Status", "status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")),
|
|
||||||
SelectField("Publish Status", "pstatus", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")),
|
|
||||||
SelectField("Type", "type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")),
|
|
||||||
Sort(),
|
|
||||||
GenreList(getGenreList())
|
|
||||||
)
|
|
||||||
|
|
||||||
// [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n')
|
|
||||||
// http://mangasee.co/advanced-search/
|
|
||||||
private fun getGenreList() = listOf(
|
|
||||||
Genre("Action"),
|
|
||||||
Genre("Adult"),
|
|
||||||
Genre("Adventure"),
|
|
||||||
Genre("Comedy"),
|
|
||||||
Genre("Doujinshi"),
|
|
||||||
Genre("Drama"),
|
|
||||||
Genre("Ecchi"),
|
|
||||||
Genre("Fantasy"),
|
|
||||||
Genre("Gender Bender"),
|
|
||||||
Genre("Harem"),
|
|
||||||
Genre("Hentai"),
|
|
||||||
Genre("Historical"),
|
|
||||||
Genre("Horror"),
|
|
||||||
Genre("Josei"),
|
|
||||||
Genre("Lolicon"),
|
|
||||||
Genre("Martial Arts"),
|
|
||||||
Genre("Mature"),
|
|
||||||
Genre("Mecha"),
|
|
||||||
Genre("Mystery"),
|
|
||||||
Genre("Psychological"),
|
|
||||||
Genre("Romance"),
|
|
||||||
Genre("School Life"),
|
|
||||||
Genre("Sci-fi"),
|
|
||||||
Genre("Seinen"),
|
|
||||||
Genre("Shotacon"),
|
|
||||||
Genre("Shoujo"),
|
|
||||||
Genre("Shoujo Ai"),
|
|
||||||
Genre("Shounen"),
|
|
||||||
Genre("Shounen Ai"),
|
|
||||||
Genre("Slice of Life"),
|
|
||||||
Genre("Smut"),
|
|
||||||
Genre("Sports"),
|
|
||||||
Genre("Supernatural"),
|
|
||||||
Genre("Tragedy"),
|
|
||||||
Genre("Yaoi"),
|
|
||||||
Genre("Yuri")
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
|
@ -1,224 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.english
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.POST
|
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class Readmangatoday : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val id: Long = 8
|
|
||||||
|
|
||||||
override val name = "ReadMangaToday"
|
|
||||||
|
|
||||||
override val baseUrl = "https://www.readmng.com"
|
|
||||||
|
|
||||||
override val lang = "en"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override val client: OkHttpClient get() = network.cloudflareClient
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Search only returns data with this set
|
|
||||||
*/
|
|
||||||
override fun headersBuilder() = Headers.Builder().apply {
|
|
||||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
|
||||||
add("X-Requested-With", "XMLHttpRequest")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/hot-manga/$page", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/latest-releases/$page", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.hot-manga > div.style-list > div.box"
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = "div.hot-manga > div.style-grid > div.box"
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("div.title > h2 > a").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.attr("title")
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
return popularMangaFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "div.hot-manga > ul.pagination > li > a:contains(»)"
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = "div.hot-manga > ul.pagination > li > a:contains(»)"
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
val builder = okhttp3.FormBody.Builder()
|
|
||||||
builder.add("manga-name", query)
|
|
||||||
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
|
|
||||||
when (filter) {
|
|
||||||
is TextField -> builder.add(filter.key, filter.state)
|
|
||||||
is Type -> builder.add("type", arrayOf("all", "japanese", "korean", "chinese")[filter.state])
|
|
||||||
is Status -> builder.add("status", arrayOf("both", "completed", "ongoing")[filter.state])
|
|
||||||
is GenreList -> filter.state.forEach { genre ->
|
|
||||||
when (genre.state) {
|
|
||||||
Filter.TriState.STATE_INCLUDE -> builder.add("include[]", genre.id.toString())
|
|
||||||
Filter.TriState.STATE_EXCLUDE -> builder.add("exclude[]", genre.id.toString())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return POST("$baseUrl/service/advanced_search", headers, builder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = "div.style-list > div.box"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
|
||||||
val manga = SManga.create()
|
|
||||||
element.select("div.title > h2 > a").first().let {
|
|
||||||
manga.setUrlWithoutDomain(it.attr("href"))
|
|
||||||
manga.title = it.attr("title")
|
|
||||||
}
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "div.next-page > a.next"
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val detailElement = document.select("div.movie-meta").first()
|
|
||||||
val genreElement = detailElement.select("dl.dl-horizontal > dd:eq(5) a")
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.author = document.select("ul.cast-list li.director > ul a").first()?.text()
|
|
||||||
manga.artist = document.select("ul.cast-list li:not(.director) > ul a").first()?.text()
|
|
||||||
manga.description = detailElement.select("li.movie-detail").first()?.text()
|
|
||||||
manga.status = detailElement.select("dl.dl-horizontal > dd:eq(3)").first()?.text().orEmpty().let { parseStatus(it) }
|
|
||||||
manga.thumbnail_url = detailElement.select("img.img-responsive").first()?.attr("src")
|
|
||||||
|
|
||||||
var genres = mutableListOf<String>()
|
|
||||||
genreElement?.forEach { genres.add(it.text()) }
|
|
||||||
manga.genre = genres.joinToString(", ")
|
|
||||||
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseStatus(status: String) = when {
|
|
||||||
status.contains("Ongoing") -> SManga.ONGOING
|
|
||||||
status.contains("Completed") -> SManga.COMPLETED
|
|
||||||
else -> SManga.UNKNOWN
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "ul.chp_lst > li"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val urlElement = element.select("a").first()
|
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = urlElement.select("span.val").text()
|
|
||||||
chapter.date_upload = element.select("span.dte").first()?.text()?.let { parseChapterDate(it) } ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long {
|
|
||||||
val dateWords: List<String> = date.split(" ")
|
|
||||||
|
|
||||||
if (dateWords.size == 3) {
|
|
||||||
val timeAgo = Integer.parseInt(dateWords[0])
|
|
||||||
val date: Calendar = Calendar.getInstance()
|
|
||||||
|
|
||||||
if (dateWords[1].contains("Minute")) {
|
|
||||||
date.add(Calendar.MINUTE, -timeAgo)
|
|
||||||
} else if (dateWords[1].contains("Hour")) {
|
|
||||||
date.add(Calendar.HOUR_OF_DAY, -timeAgo)
|
|
||||||
} else if (dateWords[1].contains("Day")) {
|
|
||||||
date.add(Calendar.DAY_OF_YEAR, -timeAgo)
|
|
||||||
} else if (dateWords[1].contains("Week")) {
|
|
||||||
date.add(Calendar.WEEK_OF_YEAR, -timeAgo)
|
|
||||||
} else if (dateWords[1].contains("Month")) {
|
|
||||||
date.add(Calendar.MONTH, -timeAgo)
|
|
||||||
} else if (dateWords[1].contains("Year")) {
|
|
||||||
date.add(Calendar.YEAR, -timeAgo)
|
|
||||||
}
|
|
||||||
|
|
||||||
return date.timeInMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0L
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
document.select("ul.list-switcher-2 > li > select.jump-menu").first().getElementsByTag("option").forEach {
|
|
||||||
pages.add(Page(pages.size, it.attr("value")))
|
|
||||||
}
|
|
||||||
pages.getOrNull(0)?.imageUrl = imageUrlParse(document)
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = document.select("#chapter_img").first().attr("src")
|
|
||||||
|
|
||||||
private class Status : Filter.TriState("Completed")
|
|
||||||
private class Genre(name: String, val id: Int) : Filter.TriState(name)
|
|
||||||
private class TextField(name: String, val key: String) : Filter.Text(name)
|
|
||||||
private class Type : Filter.Select<String>("Type", arrayOf("All", "Japanese Manga", "Korean Manhwa", "Chinese Manhua"))
|
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
|
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
|
||||||
TextField("Author", "author-name"),
|
|
||||||
TextField("Artist", "artist-name"),
|
|
||||||
Type(),
|
|
||||||
Status(),
|
|
||||||
GenreList(getGenreList())
|
|
||||||
)
|
|
||||||
|
|
||||||
// [...document.querySelectorAll("ul.manga-cat span")].map(el => `Genre("${el.nextSibling.textContent.trim()}", ${el.getAttribute('data-id')})`).join(',\n')
|
|
||||||
// http://www.readmanga.today/advanced-search
|
|
||||||
private fun getGenreList() = listOf(
|
|
||||||
Genre("Action", 2),
|
|
||||||
Genre("Adventure", 4),
|
|
||||||
Genre("Comedy", 5),
|
|
||||||
Genre("Doujinshi", 6),
|
|
||||||
Genre("Drama", 7),
|
|
||||||
Genre("Ecchi", 8),
|
|
||||||
Genre("Fantasy", 9),
|
|
||||||
Genre("Gender Bender", 10),
|
|
||||||
Genre("Harem", 11),
|
|
||||||
Genre("Historical", 12),
|
|
||||||
Genre("Horror", 13),
|
|
||||||
Genre("Josei", 14),
|
|
||||||
Genre("Lolicon", 15),
|
|
||||||
Genre("Martial Arts", 16),
|
|
||||||
Genre("Mature", 17),
|
|
||||||
Genre("Mecha", 18),
|
|
||||||
Genre("Mystery", 19),
|
|
||||||
Genre("One shot", 20),
|
|
||||||
Genre("Psychological", 21),
|
|
||||||
Genre("Romance", 22),
|
|
||||||
Genre("School Life", 23),
|
|
||||||
Genre("Sci-fi", 24),
|
|
||||||
Genre("Seinen", 25),
|
|
||||||
Genre("Shotacon", 26),
|
|
||||||
Genre("Shoujo", 27),
|
|
||||||
Genre("Shoujo Ai", 28),
|
|
||||||
Genre("Shounen", 29),
|
|
||||||
Genre("Shounen Ai", 30),
|
|
||||||
Genre("Slice of Life", 31),
|
|
||||||
Genre("Smut", 32),
|
|
||||||
Genre("Sports", 33),
|
|
||||||
Genre("Supernatural", 34),
|
|
||||||
Genre("Tragedy", 35),
|
|
||||||
Genre("Yaoi", 36),
|
|
||||||
Genre("Yuri", 37)
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,122 +0,0 @@
|
|||||||
package eu.kanade.tachiyomi.source.online.german
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
|
||||||
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.ParsedHttpSource
|
|
||||||
import okhttp3.Request
|
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
|
|
||||||
class WieManga : ParsedHttpSource() {
|
|
||||||
|
|
||||||
override val id: Long = 10
|
|
||||||
|
|
||||||
override val name = "Wie Manga!"
|
|
||||||
|
|
||||||
override val baseUrl = "http://www.wiemanga.com"
|
|
||||||
|
|
||||||
override val lang = "de"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = ".booklist td > div"
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = ".booklist td > div"
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/list/Hot-Book/", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
|
||||||
return GET("$baseUrl/list/New-Update/", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
val image = element.select("dt img")
|
|
||||||
val title = element.select("dd a:first-child")
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.setUrlWithoutDomain(title.attr("href"))
|
|
||||||
manga.title = title.text()
|
|
||||||
manga.thumbnail_url = image.attr("src")
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
return popularMangaFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = null
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = null
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
|
||||||
return GET("$baseUrl/search/?wd=$query", headers)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = ".searchresult td > div"
|
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga {
|
|
||||||
val image = element.select(".resultimg img")
|
|
||||||
val title = element.select(".resultbookname")
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.setUrlWithoutDomain(title.attr("href"))
|
|
||||||
manga.title = title.text()
|
|
||||||
manga.thumbnail_url = image.attr("src")
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = ".pagetor a.l"
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val imageElement = document.select(".bookmessgae tr > td:nth-child(1)").first()
|
|
||||||
val infoElement = document.select(".bookmessgae tr > td:nth-child(2)").first()
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
manga.author = infoElement.select("dd:nth-of-type(2) a").first()?.text()
|
|
||||||
manga.artist = infoElement.select("dd:nth-of-type(3) a").first()?.text()
|
|
||||||
manga.description = infoElement.select("dl > dt:last-child").first()?.text()?.replaceFirst("Beschreibung", "")
|
|
||||||
manga.thumbnail_url = imageElement.select("img").first()?.attr("src")
|
|
||||||
|
|
||||||
if (manga.author == "RSS")
|
|
||||||
manga.author = null
|
|
||||||
|
|
||||||
if (manga.artist == "RSS")
|
|
||||||
manga.artist = null
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = ".chapterlist tr:not(:first-child)"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val urlElement = element.select(".col1 a").first()
|
|
||||||
val dateElement = element.select(".col3 a").first()
|
|
||||||
|
|
||||||
val chapter = SChapter.create()
|
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
|
||||||
chapter.name = urlElement.text()
|
|
||||||
chapter.date_upload = dateElement?.text()?.let { parseChapterDate(it) } ?: 0
|
|
||||||
return chapter
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long {
|
|
||||||
return SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(date).time
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
val pages = mutableListOf<Page>()
|
|
||||||
|
|
||||||
document.select("select#page").first().select("option").forEach {
|
|
||||||
pages.add(Page(pages.size, it.attr("value")))
|
|
||||||
}
|
|
||||||
return pages
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = document.select("img#comicpic").first().attr("src")
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,59 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<resources>
|
||||||
|
<string name="categories">Mga Kategorya</string>
|
||||||
|
<string name="manga">Mga Manga</string>
|
||||||
|
<string name="chapters">Mga Kabanata</string>
|
||||||
|
<string name="track">Sinusubaybayan</string>
|
||||||
|
<string name="history">Kasaysayan</string>
|
||||||
|
<string name="label_settings">Mga Setting</string>
|
||||||
|
<string name="label_download_queue">Queue sa Pag-download</string>
|
||||||
|
<string name="label_library">Aking Aklatan</string>
|
||||||
|
<string name="label_recent_manga">Kakabasa Lang</string>
|
||||||
|
<string name="label_catalogues">Mga Katalogo</string>
|
||||||
|
<string name="label_recent_updates">Mga Update sa Aklatan</string>
|
||||||
|
<string name="label_latest_updates">Mga Kakalabas lang na Update</string>
|
||||||
|
<string name="label_categories">Mga Kategorya</string>
|
||||||
|
<string name="label_selected">Napili: %1$d</string>
|
||||||
|
<string name="label_backup">Backup</string>
|
||||||
|
<string name="label_migration">Pag-migrate ng Source</string>
|
||||||
|
<string name="label_extensions">Mga Extension</string>
|
||||||
|
<string name="label_extension_info">Tungkol sa Extension</string>
|
||||||
|
<string name="action_settings">Mga Setting</string>
|
||||||
|
<string name="action_filter">Ibukod</string>
|
||||||
|
<string name="action_filter_downloaded">Na-download</string>
|
||||||
|
<string name="action_filter_bookmarked">Na-bookmark</string>
|
||||||
|
<string name="action_filter_unread">Hindi pa Nababasa</string>
|
||||||
|
<string name="action_filter_read">Nabasa</string>
|
||||||
|
<string name="action_filter_empty">Tanggalin ang Pagbukod</string>
|
||||||
|
<string name="action_sort_alpha">Paalpabetiko</string>
|
||||||
|
<string name="action_sort_total">Kabuuang Bilang ng mga Kabanata</string>
|
||||||
|
<string name="action_sort_last_read">Huling nabasa</string>
|
||||||
|
<string name="action_sort_last_updated">Huling na-update</string>
|
||||||
|
<string name="action_search">Hanapin</string>
|
||||||
|
<string name="action_global_search">Global na paghahanap</string>
|
||||||
|
<string name="action_select_all">Piliin lahat</string>
|
||||||
|
<string name="name">Pangalan</string>
|
||||||
|
<string name="action_mark_as_read">Markahang Nabasa</string>
|
||||||
|
<string name="action_mark_as_unread">Markahang Hindi pa Nababasa</string>
|
||||||
|
<string name="action_mark_previous_as_read">Markahang Nabasa ang Nauna</string>
|
||||||
|
<string name="action_download">I-download</string>
|
||||||
|
<string name="action_bookmark">I-bookmark</string>
|
||||||
|
<string name="action_remove_bookmark">Tanggalin ang bookmark</string>
|
||||||
|
<string name="action_delete">I-delete</string>
|
||||||
|
<string name="action_update">I-update</string>
|
||||||
|
<string name="action_update_library">I-update ang Aklatan</string>
|
||||||
|
<string name="action_edit">I-edit</string>
|
||||||
|
<string name="action_add">Idagdag</string>
|
||||||
|
<string name="action_add_category">Magdagdag ng Kategorya</string>
|
||||||
|
<string name="action_edit_categories">I-edit ang mga kategorya</string>
|
||||||
|
<string name="action_rename_category">I-rename ang kategorya</string>
|
||||||
|
<string name="action_move_category">Ilipat sa mga kategorya</string>
|
||||||
|
<string name="action_edit_cover">I-edit ang cover picture</string>
|
||||||
|
<string name="action_sort_up">I-sort pataas</string>
|
||||||
|
<string name="action_sort_down">I-sort pababa</string>
|
||||||
|
<string name="action_show_downloaded">Mga Na-download</string>
|
||||||
|
<string name="action_next_unread">Susunod na Hindi pa Nababasa</string>
|
||||||
|
<string name="action_start">Simula</string>
|
||||||
|
<string name="action_stop">Itigil</string>
|
||||||
|
<string name="action_pause">Ihinto</string>
|
||||||
|
</resources>
|
Loading…
Reference in new issue