Rawdevart Extension (#1436)

Signed-off-by: Rama Bondan Prakoso <ramanarubp@gmail.com>
This commit is contained in:
Rama Bondan Prakoso 2019-08-29 06:12:10 +07:00 committed by Eugene
parent 10cecba09b
commit 66bada2368
8 changed files with 351 additions and 0 deletions

View File

@ -0,0 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: Rawdevart'
pkgNameSuffix = 'ja.rawdevart'
extClass = '.Rawdevart'
extVersionCode = 1
libVersion = '1.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

View File

@ -0,0 +1,339 @@
package eu.kanade.tachiyomi.extension.ja.rawdevart
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.*
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.*
class Rawdevart : ParsedHttpSource() {
override val name = "Rawdevart"
override val baseUrl = "https://rawdevart.com"
override val lang = "ja"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun latestUpdatesRequest(page: Int) =
GET("$baseUrl/comic/?page=$page&lister=0")
override fun latestUpdatesSelector() = "div.row div.hovereffect"
override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create()
val item = element.select("a.head")
manga.setUrlWithoutDomain(item.attr("href"))
manga.title = item.text()
manga.thumbnail_url = if (element.select("img").attr("data-src").contains("http"))
element.select("img").attr("data-src").replace("\\s".toRegex(), "") else
baseUrl + element.select("img").attr("data-src")
return manga
}
override fun latestUpdatesNextPageSelector() = "li.page-item:not(.disabled) a[aria-label=next]"
override fun popularMangaRequest(page: Int) =
GET("$baseUrl/comic/?page=$page&lister=5")
override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element)
override fun popularMangaSelector() = latestUpdatesSelector()
override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/search/")!!.newBuilder()
url.addQueryParameter("page", page.toString())
url.addQueryParameter("title", query)
filters.forEach { filter ->
when (filter) {
is AuthorFilter -> {
url.addQueryParameter("author", filter.state)
}
is ArtistFilter -> {
url.addQueryParameter("artist", filter.state)
}
is SortFilter -> {
url.addQueryParameter("lister", filter.toUriPart())
}
is TypeFilter -> {
val typeToExclude = mutableListOf<String>()
val typeToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.isExcluded())
typeToExclude.add(content.id)
else if (content.isIncluded())
typeToInclude.add(content.id)
}
if (typeToExclude.isNotEmpty()) {
url.addQueryParameter("ctype_exc", typeToExclude
.joinToString(","))
}
if (typeToInclude.isNotEmpty()) {
url.addQueryParameter("ctype_inc", typeToInclude
.joinToString(","))
}
}
is StatusFilter -> {
val statusToExclude = mutableListOf<String>()
val statusToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.isExcluded())
statusToExclude.add(content.id)
else if (content.isIncluded())
statusToInclude.add(content.id)
}
if (statusToExclude.isNotEmpty()) {
url.addQueryParameter("status_exc", statusToExclude
.joinToString(","))
}
if (statusToInclude.isNotEmpty()) {
url.addQueryParameter("status_inc", statusToInclude
.joinToString(","))
}
}
is GenreFilter -> {
val genreToExclude = mutableListOf<String>()
val genreToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.isExcluded())
genreToExclude.add(content.id)
else if (content.isIncluded())
genreToInclude.add(content.id)
}
if (genreToExclude.isNotEmpty()) {
url.addQueryParameter("genre_exc", genreToExclude
.joinToString(","))
}
if (genreToInclude.isNotEmpty()) {
url.addQueryParameter("genre_inc", genreToInclude
.joinToString(","))
}
}
}
}
return GET(url.build().toString(), headers)
}
override fun searchMangaSelector() = latestUpdatesSelector()
override fun searchMangaFromElement(element: Element) = latestUpdatesFromElement(element)
override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector()
override fun mangaDetailsRequest(manga: SManga): Request {
if (manga.url.startsWith("http")) {
return GET(manga.url, headers)
}
return super.mangaDetailsRequest(manga)
}
override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div.manga-main")
val manga = SManga.create()
val status = infoElement.select("th:contains(Status) + td").text()
val genres = mutableListOf<String>()
infoElement.select("div.genres a").forEach { element ->
val genre = element.text()
genres.add(genre)
}
manga.title = infoElement.select("h1").text()
manga.author = infoElement.select("th:contains(Author) + td").text()
manga.artist = infoElement.select("th:contains(Artist) + td").text()
manga.status = parseStatus(status)
manga.genre = genres.joinToString(", ")
manga.description = infoElement.select("div.description").text()
.substringAfter("Description ")
manga.thumbnail_url = if (infoElement.select("img.not-lazy").attr("data-src").contains("http"))
infoElement.select("img.not-lazy").attr("data-src") else
baseUrl + infoElement.select("img.not-lazy").attr("data-src")
return manga
}
private fun parseStatus(status: String?) = when {
status == null -> SManga.UNKNOWN
status.contains("Ongoing") -> SManga.ONGOING
status.contains("Finished") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
override fun chapterListRequest(manga: SManga) = chapterListRequest(manga.url, 1)
private fun chapterListRequest(mangaUrl: String, page: Int): Request {
return GET("$baseUrl$mangaUrl?page=$page", headers)
}
override fun chapterListSelector() = "div.list-group-item"
override fun chapterListParse(response: Response): List<SChapter> {
var document = response.asJsoup()
val chapters = mutableListOf<SChapter>()
var nextPage = 2
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
while (document.select(paginationNextPageSelector).isNotEmpty()) {
val currentPage = document.select("form#filter_form").attr("action")
document = client.newCall(chapterListRequest(currentPage, nextPage)).execute().asJsoup()
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
nextPage++
}
return chapters
}
private val paginationNextPageSelector = latestUpdatesNextPageSelector()
override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create()
chapter.setUrlWithoutDomain(element.select("div.rounded-0 a").attr("href"))
chapter.name = element.select("div.rounded-0 span.text-truncate").text()
chapter.date_upload = element.select("span.mr-2").text().let {
try {
when {
it.contains("ago") -> Date(System.currentTimeMillis() - it.split("\\s".toRegex())[0].toLong() * 60 * 60 * 1000).time
it.contains("Yesterday") -> Date(System.currentTimeMillis() - 24 * 60 * 60 * 1000).time
it.contains(".") -> SimpleDateFormat("MMM. dd, yyyy", Locale.US).parse(it).time
else -> SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(it).time
}
} catch (e: Exception) {
Date(System.currentTimeMillis()).time
}
}
return chapter
}
override fun pageListRequest(chapter: SChapter): Request {
if (chapter.url.startsWith("http")) {
return GET(chapter.url, headers)
}
return super.pageListRequest(chapter)
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
val script = document.select("script").html()
val url = script.substringAfter("const pages = [").substringBefore(",]")
.replace(Regex("""["\\]"""), "")
.split(",")
for (i in 0 until url.size) {
pages.add(Page(i, "", url[i]))
}
return pages
}
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
private class AuthorFilter : Filter.Text("Author")
private class ArtistFilter : Filter.Text("Artist")
private class SortFilter : UriPartFilter("Sort By", arrayOf(
Pair("<select>", ""),
Pair("Latest", "0"),
Pair("A-Z", "1"),
Pair("Z-A", "2"),
Pair("Star", "3"),
Pair("Bookmark", "4"),
Pair("View", "5")
))
private class TypeFilter(type: List<Tag>) : Filter.Group<Tag>("Types", type)
private class StatusFilter(status: List<Tag>) : Filter.Group<Tag>("Status", status)
private class GenreFilter(genres: List<Tag>) : Filter.Group<Tag>("Genres", genres)
override fun getFilterList() = FilterList(
Filter.Header("Combine Sort filter with other filters."),
Filter.Separator(),
AuthorFilter(),
ArtistFilter(),
SortFilter(),
TypeFilter(getTypeList()),
StatusFilter(getStatusList()),
GenreFilter(getGenreList())
)
private fun getTypeList() = listOf(
Tag("0", "Manga"),
Tag("1", "Webtoon"),
Tag("2", "Manhwa - Korean"),
Tag("3", "Manhua - Chinese"),
Tag("4", "Comic"),
Tag("5", "Doujinshi")
)
private fun getStatusList() = listOf(
Tag("0", "Ongoing"),
Tag("1", "Haitus"),
Tag("2", "Axed"),
Tag("3", "Unknown"),
Tag("4", "Finished")
)
private fun getGenreList() = listOf(
Tag("29", "4-koma"),
Tag("1", "Action"),
Tag("37", "Adult"),
Tag("2", "Adventure"),
Tag("3", "Comedy"),
Tag("33", "Cooking"),
Tag("4", "Crime"),
Tag("5", "Drama"),
Tag("30", "Ecchi"),
Tag("6", "Fantasy"),
Tag("34", "Gender Bender"),
Tag("31", "Gore"),
Tag("39", "Harem"),
Tag("7", "Historical"),
Tag("8", "Horror"),
Tag("9", "Isekai"),
Tag("42", "Josei"),
Tag("35", "Martial Arts"),
Tag("36", "Mature"),
Tag("10", "Mecha"),
Tag("11", "Medical"),
Tag("38", "Music"),
Tag("12", "Mystery"),
Tag("13", "Philosophical"),
Tag("14", "Psychological"),
Tag("15", "Romance"),
Tag("40", "School Life"),
Tag("16", "Sci-Fi"),
Tag("41", "Seinen"),
Tag("28", "Shoujo"),
Tag("17", "Shoujo Ai"),
Tag("27", "Shounen"),
Tag("18", "Shounen Ai"),
Tag("19", "Slice of Life"),
Tag("32", "Smut"),
Tag("20", "Sports"),
Tag("21", "Super Powers"),
Tag("43", "Supernatural"),
Tag("22", "Thriller"),
Tag("23", "Tragedy"),
Tag("24", "Wuxia"),
Tag("25", "Yaoi"),
Tag("26", "Yuri")
)
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
private class Tag(val id: String, name: String) : Filter.TriState(name)
}