EroMuse - new extension for 8muses and Erofus (#4061)
This commit is contained in:
parent
b4e171b52a
commit
0ca178aa52
src/all/eromuse
build.gradle
res
src/eu/kanade/tachiyomi/extension/all/eromuse
13
src/all/eromuse/build.gradle
Normal file
13
src/all/eromuse/build.gradle
Normal file
@ -0,0 +1,13 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'EroMuse (8muses and Erofus)'
|
||||
pkgNameSuffix = 'all.eromuse'
|
||||
extClass = '.EroMuseFactory'
|
||||
extVersionCode = 1
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
BIN
src/all/eromuse/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/all/eromuse/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.0 KiB |
BIN
src/all/eromuse/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/all/eromuse/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 1006 B |
BIN
src/all/eromuse/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/all/eromuse/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 2.6 KiB |
BIN
src/all/eromuse/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/all/eromuse/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 5.0 KiB |
BIN
src/all/eromuse/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/all/eromuse/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 7.0 KiB |
BIN
src/all/eromuse/res/web_hi_res_512.png
Normal file
BIN
src/all/eromuse/res/web_hi_res_512.png
Normal file
Binary file not shown.
After ![]() (image error) Size: 42 KiB |
@ -0,0 +1,349 @@
|
||||
package eu.kanade.tachiyomi.extension.all.eromuse
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.Filter
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
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.HttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
open class EroMuse(override val name: String, override val baseUrl: String) : HttpSource() {
|
||||
|
||||
override val lang = "en"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
|
||||
/**
|
||||
* Browse, search, and latest all run through an ArrayDeque of requests that acts as a stack we push and pop to/from
|
||||
* For the fetch functions, we only need to worry about pushing the first page to the stack because subsequent pages
|
||||
* get pushed to the stack during parseManga(). Page 1's URL must include page=1 if the next page would be page=2,
|
||||
* if page 2 is path_to/2, nothing special needs to be done.
|
||||
*/
|
||||
|
||||
// the stack - shouldn't need to touch these except for visibility
|
||||
protected data class StackItem(val url: String, val pageType: Int)
|
||||
private lateinit var stackItem: StackItem
|
||||
protected val pageStack = ArrayDeque<StackItem>()
|
||||
companion object {
|
||||
const val VARIOUS_AUTHORS = 0
|
||||
const val AUTHOR = 1
|
||||
const val SEARCH_RESULTS_OR_BASE = 2
|
||||
}
|
||||
protected lateinit var currentSortingMode: String
|
||||
|
||||
// might need to override for new sources
|
||||
private val nextPageSelector = ".pagination span.current + span a"
|
||||
protected open val albumSelector = "a.c-tile:has(img):not(:has(.members-only))"
|
||||
protected open val topLevelPathSegments = listOf("album", "Various-Authors")
|
||||
private val pageQueryRegex = Regex("""page=\d+""")
|
||||
|
||||
private fun Document.addNextPageToStack() {
|
||||
this.select(nextPageSelector).firstOrNull()?.text()?.toIntOrNull()?.let { int ->
|
||||
val nextPage = if (stackItem.url.contains(pageQueryRegex)) {
|
||||
stackItem.url.replace(pageQueryRegex, "page=$int")
|
||||
} else {
|
||||
val httpUrl = HttpUrl.parse(stackItem.url)!!
|
||||
val builder = if (httpUrl.pathSegments().last().toIntOrNull() is Int) {
|
||||
httpUrl.newBuilder().removePathSegment(httpUrl.pathSegments().lastIndex)
|
||||
} else {
|
||||
httpUrl.newBuilder()
|
||||
}
|
||||
builder.addPathSegment(int.toString()).toString()
|
||||
}
|
||||
pageStack.add(StackItem(nextPage, stackItem.pageType))
|
||||
}
|
||||
}
|
||||
|
||||
protected fun Element.imgAttr(): String = if (this.hasAttr("data-src")) this.attr("abs:data-src") else this.attr("abs:src")
|
||||
|
||||
private fun mangaFromElement(element: Element): SManga {
|
||||
return SManga.create().apply {
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
title = element.text()
|
||||
thumbnail_url = element.select("img").firstOrNull()?.imgAttr()
|
||||
}
|
||||
}
|
||||
|
||||
protected fun parseManga(document: Document): MangasPage {
|
||||
fun internalParse(document: Document): List<SManga> {
|
||||
val authorDocument = if (stackItem.pageType == VARIOUS_AUTHORS) {
|
||||
client.newCall(stackRequest()).execute().asJsoup()
|
||||
} else {
|
||||
document
|
||||
}
|
||||
authorDocument.addNextPageToStack()
|
||||
return authorDocument.select(albumSelector).map { mangaFromElement(it) }
|
||||
}
|
||||
|
||||
if (stackItem.pageType in listOf(VARIOUS_AUTHORS, SEARCH_RESULTS_OR_BASE)) document.addNextPageToStack()
|
||||
val mangas = when (stackItem.pageType) {
|
||||
VARIOUS_AUTHORS -> {
|
||||
document.select(albumSelector)?.let { elements -> elements.reversed().map { pageStack.addLast(StackItem(it.attr("abs:href"), AUTHOR)) } }
|
||||
internalParse(document)
|
||||
}
|
||||
AUTHOR -> {
|
||||
internalParse(document)
|
||||
}
|
||||
SEARCH_RESULTS_OR_BASE -> {
|
||||
val searchMangas = mutableListOf<SManga>()
|
||||
document.select(albumSelector)
|
||||
.map { element ->
|
||||
val url = element.attr("abs:href")
|
||||
when (HttpUrl.parse(url)!!.pathSegments().takeLastWhile { it !in topLevelPathSegments }.count()) {
|
||||
// manga album
|
||||
2 -> {
|
||||
searchMangas.add(mangaFromElement(element))
|
||||
}
|
||||
// author album
|
||||
1 -> {
|
||||
pageStack.addLast(StackItem(url, AUTHOR))
|
||||
if (searchMangas.isEmpty()) searchMangas += internalParse(client.newCall(stackRequest()).execute().asJsoup()) else null
|
||||
}
|
||||
// 0 doesn't need to be parsed; >= 3 probably doesn't need to be parsed but in some instances maybe we could do something
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
searchMangas
|
||||
}
|
||||
else -> emptyList()
|
||||
}
|
||||
return MangasPage(mangas, pageStack.isNotEmpty())
|
||||
}
|
||||
|
||||
protected fun stackRequest(): Request {
|
||||
stackItem = pageStack.removeLast()
|
||||
val url = if (stackItem.pageType == AUTHOR && currentSortingMode.isNotEmpty() && !stackItem.url.contains("sort")) {
|
||||
HttpUrl.parse(stackItem.url)!!.newBuilder().addQueryParameter("sort", currentSortingMode).toString()
|
||||
} else {
|
||||
stackItem.url
|
||||
}
|
||||
return GET(url, headers)
|
||||
}
|
||||
|
||||
// Popular
|
||||
|
||||
protected fun fetchManga(url: String, page: Int, sortingMode: String): Observable<MangasPage> {
|
||||
if (page == 1) {
|
||||
pageStack.clear()
|
||||
pageStack.addLast(StackItem(url, VARIOUS_AUTHORS))
|
||||
currentSortingMode = sortingMode
|
||||
}
|
||||
|
||||
return client.newCall(stackRequest())
|
||||
.asObservableSuccess()
|
||||
.map { response -> parseManga(response.asJsoup()) }
|
||||
}
|
||||
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> = fetchManga("$baseUrl/comics/album/Various-Authors", page, "")
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request = throw UnsupportedOperationException("Not used")
|
||||
override fun popularMangaParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// Latest
|
||||
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> = fetchManga("$baseUrl/comics/album/Various-Authors?sort=date", page, "date")
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used")
|
||||
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// Search
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
if (page == 1) {
|
||||
pageStack.clear()
|
||||
|
||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||
currentSortingMode = filterList.filterIsInstance<SortFilter>().first().toQueryValue()
|
||||
|
||||
if (query.isNotBlank()) {
|
||||
val url = HttpUrl.parse("$baseUrl/search?q=$query")!!.newBuilder().apply {
|
||||
if (currentSortingMode.isNotEmpty()) addQueryParameter("sort", currentSortingMode)
|
||||
addQueryParameter("page", "1")
|
||||
}
|
||||
pageStack.addLast(StackItem(url.toString(), SEARCH_RESULTS_OR_BASE))
|
||||
} else {
|
||||
val albumFilter = filterList.filterIsInstance<AlbumFilter>().first().selection()
|
||||
val url = HttpUrl.parse("$baseUrl/comics/${albumFilter.pathSegments}")!!.newBuilder().apply {
|
||||
if (currentSortingMode.isNotEmpty()) addQueryParameter("sort", currentSortingMode)
|
||||
if (albumFilter.pageType != AUTHOR) addQueryParameter("page", "1")
|
||||
}
|
||||
pageStack.addLast(StackItem(url.toString(), albumFilter.pageType))
|
||||
}
|
||||
}
|
||||
|
||||
return client.newCall(stackRequest())
|
||||
.asObservableSuccess()
|
||||
.map { response -> parseManga(response.asJsoup()) }
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw UnsupportedOperationException("Not used")
|
||||
override fun searchMangaParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// Details
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
return SManga.create().apply {
|
||||
with(response.asJsoup()) {
|
||||
thumbnail_url = select("$albumSelector img").firstOrNull()?.imgAttr()
|
||||
author = select("div.top-menu-breadcrumb li:nth-last-child(2)").text()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Chapters
|
||||
|
||||
protected open val linkedChapterSelector = "a.c-tile:has(img)[href*=/comics/album/]"
|
||||
protected open val pageThumbnailSelector = "a.c-tile:has(img)[href*=/comics/picture/] img"
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val document = response.asJsoup()
|
||||
// Linked albums
|
||||
val chapters = document.select(linkedChapterSelector)
|
||||
.mapNotNull {
|
||||
SChapter.create().apply {
|
||||
name = it.text()
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
}
|
||||
}
|
||||
.reversed()
|
||||
.toMutableList()
|
||||
// Self
|
||||
document.select(pageThumbnailSelector).firstOrNull()?.let {
|
||||
chapters.add(
|
||||
SChapter.create().apply {
|
||||
name = "Chapter"
|
||||
setUrlWithoutDomain(response.request().url().toString())
|
||||
}
|
||||
)
|
||||
}
|
||||
return chapters
|
||||
}
|
||||
|
||||
// Pages
|
||||
|
||||
protected open val pageThumbnailPathSegment = "/th/"
|
||||
protected open val pageFullsizePathSegment = "/fl/"
|
||||
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
return response.asJsoup().select(pageThumbnailSelector).mapIndexed { i, img ->
|
||||
Page(i, "", img.imgAttr().replace(pageThumbnailPathSegment, pageFullsizePathSegment))
|
||||
}
|
||||
}
|
||||
|
||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used")
|
||||
|
||||
// Filters
|
||||
|
||||
override fun getFilterList(): FilterList {
|
||||
return FilterList(
|
||||
Filter.Header("Text search only combines with sort!"),
|
||||
Filter.Separator(),
|
||||
AlbumFilter(getAlbumList()),
|
||||
SortFilter(getSortList())
|
||||
)
|
||||
}
|
||||
|
||||
protected class AlbumFilter(private val vals: Array<Triple<String, String, Int>>) : Filter.Select<String>("Album", vals.map { it.first }.toTypedArray()) {
|
||||
fun selection() = AlbumFilterData(vals[state].second, vals[state].third)
|
||||
data class AlbumFilterData(val pathSegments: String, val pageType: Int)
|
||||
}
|
||||
protected open fun getAlbumList() = arrayOf(
|
||||
Triple("Various Authors", "album/Various-Authors", VARIOUS_AUTHORS),
|
||||
Triple("All Authors", "", SEARCH_RESULTS_OR_BASE),
|
||||
Triple("MilfToon Comics", "album/MilfToon-Comics", AUTHOR),
|
||||
Triple("Fakku Comics", "album/Fakku-Comics", AUTHOR),
|
||||
Triple("BE Story Club Comics", "album/BE-Story-Club-Comics", AUTHOR),
|
||||
Triple("ShadBase Comics", "album/ShadBase-Comics", AUTHOR),
|
||||
Triple("ZZZ Comics", "album/ZZZ-Comics", AUTHOR),
|
||||
Triple("PalComix Comics", "album/PalComix-Comics", AUTHOR),
|
||||
Triple("Hentai and Manga English", "album/Hentai-and-Manga-English", AUTHOR),
|
||||
Triple("MCC Comics", "album/MCC-Comics", AUTHOR),
|
||||
Triple("Expansionfan Comics", "album/Expansionfan-Comics", AUTHOR),
|
||||
Triple("JAB Comics", "album/JAB-Comics", AUTHOR),
|
||||
Triple("Giantess Fan Comics", "album/Giantess-Fan-Comics", AUTHOR),
|
||||
Triple("Renderotica Comics", "album/Renderotica-Comics", AUTHOR),
|
||||
Triple("IllustratedInterracial.com Comics", "album/IllustratedInterracial_com-Comics", AUTHOR),
|
||||
Triple("Giantess Club Comics", "album/Giantess-Club-Comics", AUTHOR),
|
||||
Triple("Innocent Dickgirls Comics", "album/Innocent-Dickgirls-Comics", AUTHOR),
|
||||
Triple("Locofuria Comics", "album/Locofuria-Comics", AUTHOR),
|
||||
Triple("PigKing - CrazyDad Comics", "album/PigKing-CrazyDad-Comics", AUTHOR),
|
||||
Triple("Cartoon Reality Comics", "album/Cartoon-Reality-Comics", AUTHOR),
|
||||
Triple("Affect3D Comics", "album/Affect3D-Comics", AUTHOR),
|
||||
Triple("TG Comics", "album/TG-Comics", AUTHOR),
|
||||
Triple("Melkormancin.com Comics", "album/Melkormancin_com-Comics", AUTHOR),
|
||||
Triple("Seiren.com.br Comics", "album/Seiren_com_br-Comics", AUTHOR),
|
||||
Triple("Tracy Scops Comics", "album/Tracy-Scops-Comics", AUTHOR),
|
||||
Triple("Fake Celebrities Sex Pictures", "album/Fake-Celebrities-Sex-Pictures", AUTHOR),
|
||||
Triple("Fred Perry Comics", "album/Fred-Perry-Comics", AUTHOR),
|
||||
Triple("Witchking00 Comics", "album/Witchking00-Comics", AUTHOR),
|
||||
Triple("8muses Comics", "album/8muses-Comics", AUTHOR),
|
||||
Triple("KAOS Comics", "album/KAOS-Comics", AUTHOR),
|
||||
Triple("Vaesark Comics", "album/Vaesark-Comics", AUTHOR),
|
||||
Triple("Fansadox Comics", "album/Fansadox-Comics", AUTHOR),
|
||||
Triple("DreamTales Comics", "album/DreamTales-Comics", AUTHOR),
|
||||
Triple("Croc Comics", "album/Croc-Comics", AUTHOR),
|
||||
Triple("Jay Marvel Comics", "album/Jay-Marvel-Comics", AUTHOR),
|
||||
Triple("JohnPersons.com Comics", "album/JohnPersons_com-Comics", AUTHOR),
|
||||
Triple("MuscleFan Comics", "album/MuscleFan-Comics", AUTHOR),
|
||||
Triple("Taboolicious.xxx Comics", "album/Taboolicious_xxx-Comics", AUTHOR),
|
||||
Triple("MongoBongo Comics", "album/MongoBongo-Comics", AUTHOR),
|
||||
Triple("Slipshine Comics", "album/Slipshine-Comics", AUTHOR),
|
||||
Triple("Everfire Comics", "album/Everfire-Comics", AUTHOR),
|
||||
Triple("PrismGirls Comics", "album/PrismGirls-Comics", AUTHOR),
|
||||
Triple("Abimboleb Comics", "album/Abimboleb-Comics", AUTHOR),
|
||||
Triple("Y3DF - Your3DFantasy.com Comics", "album/Y3DF-Your3DFantasy_com-Comics", AUTHOR),
|
||||
Triple("Grow Comics", "album/Grow-Comics", AUTHOR),
|
||||
Triple("OkayOkayOKOk Comics", "album/OkayOkayOKOk-Comics", AUTHOR),
|
||||
Triple("Tufos Comics", "album/Tufos-Comics", AUTHOR),
|
||||
Triple("Cartoon Valley", "album/Cartoon-Valley", AUTHOR),
|
||||
Triple("3DMonsterStories.com Comics", "album/3DMonsterStories_com-Comics", AUTHOR),
|
||||
Triple("Kogeikun Comics", "album/Kogeikun-Comics", AUTHOR),
|
||||
Triple("The Foxxx Comics", "album/The-Foxxx-Comics", AUTHOR),
|
||||
Triple("Theme Collections", "album/Theme-Collections", AUTHOR),
|
||||
Triple("Interracial-Comics", "album/Interracial-Comics", AUTHOR),
|
||||
Triple("Expansion Comics", "album/Expansion-Comics", AUTHOR),
|
||||
Triple("Moiarte Comics", "album/Moiarte-Comics", AUTHOR),
|
||||
Triple("Incognitymous Comics", "album/Incognitymous-Comics", AUTHOR),
|
||||
Triple("DizzyDills Comics", "album/DizzyDills-Comics", AUTHOR),
|
||||
Triple("DukesHardcoreHoneys.com Comics", "album/DukesHardcoreHoneys_com-Comics", AUTHOR),
|
||||
Triple("Stormfeder Comics", "album/Stormfeder-Comics", AUTHOR),
|
||||
Triple("Bimbo Story Club Comics", "album/Bimbo-Story-Club-Comics", AUTHOR),
|
||||
Triple("Smudge Comics", "album/Smudge-Comics", AUTHOR),
|
||||
Triple("Dollproject Comics", "album/Dollproject-Comics", AUTHOR),
|
||||
Triple("SuperHeroineComixxx", "album/SuperHeroineComixxx", AUTHOR),
|
||||
Triple("Karmagik Comics", "album/Karmagik-Comics", AUTHOR),
|
||||
Triple("Blacknwhite.com Comics", "album/Blacknwhite_com-Comics", AUTHOR),
|
||||
Triple("ArtOfJaguar Comics", "album/ArtOfJaguar-Comics", AUTHOR),
|
||||
Triple("Kirtu.com Comics", "album/Kirtu_com-Comics", AUTHOR),
|
||||
Triple("UberMonkey Comics", "album/UberMonkey-Comics", AUTHOR),
|
||||
Triple("DarkSoul3D Comics", "album/DarkSoul3D-Comics", AUTHOR),
|
||||
Triple("Markydaysaid Comics", "album/Markydaysaid-Comics", AUTHOR),
|
||||
Triple("Central Comics", "album/Central-Comics", AUTHOR),
|
||||
Triple("Frozen Parody Comics", "album/Frozen-Parody-Comics", AUTHOR),
|
||||
Triple("Blacknwhitecomics.com Comix", "album/Blacknwhitecomics_com-Comix", AUTHOR)
|
||||
)
|
||||
|
||||
protected class SortFilter(private val vals: Array<Pair<String, String>>) : Filter.Select<String>("Sort Order", vals.map { it.first }.toTypedArray()) {
|
||||
fun toQueryValue() = vals[state].second
|
||||
}
|
||||
protected open fun getSortList() = arrayOf(
|
||||
Pair("Views", ""),
|
||||
Pair("Likes", "like"),
|
||||
Pair("Date", "date"),
|
||||
Pair("A-Z", "az")
|
||||
)
|
||||
}
|
@ -0,0 +1,162 @@
|
||||
package eu.kanade.tachiyomi.extension.all.eromuse
|
||||
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class EroMuseFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
EroMuse("8Muses", "https://comics.8muses.com"),
|
||||
Erofus()
|
||||
)
|
||||
}
|
||||
|
||||
@ExperimentalStdlibApi
|
||||
class Erofus : EroMuse("Erofus", "https://www.erofus.com") {
|
||||
|
||||
override val albumSelector = "a.a-click"
|
||||
override val topLevelPathSegments = listOf("various-authors", "comics")
|
||||
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> = fetchManga("$baseUrl/comics/various-authors?sort=viewed&page=1", page, "viewed")
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> = fetchManga("$baseUrl/comics/various-authors?sort=recent&page=1", page, "recent")
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
if (page == 1) {
|
||||
pageStack.clear()
|
||||
|
||||
val filterList = if (filters.isEmpty()) getFilterList() else filters
|
||||
currentSortingMode = filterList.filterIsInstance<SortFilter>().first().toQueryValue()
|
||||
|
||||
if (query.isNotBlank()) {
|
||||
// TODO possibly add genre search if a decent list of them can be built
|
||||
pageStack.addLast(StackItem("$baseUrl/?search=$query&sort=$currentSortingMode&page=1", SEARCH_RESULTS_OR_BASE))
|
||||
} else {
|
||||
val albumFilter = filterList.filterIsInstance<AlbumFilter>().first().selection()
|
||||
val url = HttpUrl.parse(baseUrl + albumFilter.pathSegments)!!.newBuilder()
|
||||
.addQueryParameter("sort", currentSortingMode)
|
||||
.addQueryParameter("page", "1")
|
||||
|
||||
pageStack.addLast(StackItem(url.toString(), albumFilter.pageType))
|
||||
}
|
||||
}
|
||||
|
||||
return client.newCall(stackRequest())
|
||||
.asObservableSuccess()
|
||||
.map { response -> parseManga(response.asJsoup()) }
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
return SManga.create().apply {
|
||||
with(response.asJsoup()) {
|
||||
thumbnail_url = select("$albumSelector img").firstOrNull()?.imgAttr()
|
||||
author = select("div.navigation-breadcrumb li:nth-last-child(3)").text()
|
||||
genre = select("div.album-tag-container a").joinToString { it.text() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val linkedChapterSelector = "a.a-click:has(img)[href^=/comics/]"
|
||||
override val pageThumbnailSelector = "a.a-click:has(img)[href*=/pic/] img"
|
||||
|
||||
override val pageThumbnailPathSegment = "/thumb/"
|
||||
override val pageFullsizePathSegment = "/medium/"
|
||||
|
||||
override fun getAlbumList() = arrayOf(
|
||||
Triple("Various Authors", "/comics/various-authors", VARIOUS_AUTHORS),
|
||||
Triple("All Authors", "", SEARCH_RESULTS_OR_BASE),
|
||||
Triple("Various Authors", "/comics/various-authors", AUTHOR),
|
||||
Triple("TabooLicious.xxx Comics", "/comics/taboolicious_xxx-comics", AUTHOR),
|
||||
Triple("Hentai and Manga English", "/comics/hentai-and-manga-english", AUTHOR),
|
||||
Triple("IllustratedInterracial.com Comics", "/comics/illustratedinterracial_com-comics", AUTHOR),
|
||||
Triple("ZZZ Comics", "/comics/zzz-comics", AUTHOR),
|
||||
Triple("JohnPersons.com Comics", "/comics/johnpersons_com-comics", AUTHOR),
|
||||
Triple("For members only", "/", AUTHOR),
|
||||
Triple("PalComix Comics", "/comics/palcomix-comics", AUTHOR),
|
||||
Triple("Melkormancin.com Comics", "/comics/melkormancin_com-comics", AUTHOR),
|
||||
Triple("TG Comics", "/comics/tg-comics", AUTHOR),
|
||||
Triple("ShadBase Comics", "/comics/shadbase-comics", AUTHOR),
|
||||
Triple("Filthy Figments Comics", "/comics/filthy-figments-comics", AUTHOR),
|
||||
Triple("Witchking00 Comics", "/comics/witchking00-comics", AUTHOR),
|
||||
Triple("Tease Comix", "/comics/tease-comix", AUTHOR),
|
||||
Triple("PrismGirls Comics", "/comics/prismgirls-comics", AUTHOR),
|
||||
Triple("Croc Comics", "/comics/croc-comics", AUTHOR),
|
||||
Triple("CRAZYXXX3DWORLD Comics", "/comics/crazyxxx3dworld-comics", AUTHOR),
|
||||
Triple("Moiarte Comics", "/comics/moiarte-comics", AUTHOR),
|
||||
Triple("Nicole Heat Comics", "/comics/nicole-heat-comics", AUTHOR),
|
||||
Triple("Expansion Comics", "/comics/expansion-comics", AUTHOR),
|
||||
Triple("DizzyDills Comics", "/comics/dizzydills-comics", AUTHOR),
|
||||
Triple("Hustler Cartoons", "/comics/hustler-cartoons", AUTHOR),
|
||||
Triple("ArtOfJaguar Comics", "/comics/artofjaguar-comics", AUTHOR),
|
||||
Triple("Grow Comics", "/comics/grow-comics", AUTHOR),
|
||||
Triple("Bimbo Story Club Comics", "/comics/bimbo-story-club-comics", AUTHOR),
|
||||
Triple("HentaiTNA.com Comics", "/comics/hentaitna_com-comics", AUTHOR),
|
||||
Triple("ZZomp Comics", "/comics/zzomp-comics", AUTHOR),
|
||||
Triple("Seiren.com.br Comics", "/comics/seiren_com_br-comics", AUTHOR),
|
||||
Triple("DukesHardcoreHoneys.com Comics", "/comics/dukeshardcorehoneys_com-comics", AUTHOR),
|
||||
Triple("Frozen Parody Comics", "/comics/frozen-parody-comics", AUTHOR),
|
||||
Triple("Giantess Club Comics", "/comics/giantess-club-comics", AUTHOR),
|
||||
Triple("Ultimate3DPorn Comics", "/comics/ultimate3dporn-comics", AUTHOR),
|
||||
Triple("Sean Harrington Comics", "/comics/sean-harrington-comics", AUTHOR),
|
||||
Triple("Central Comics", "/comics/central-comics", AUTHOR),
|
||||
Triple("Mana World Comics", "/comics/mana-world-comics", AUTHOR),
|
||||
Triple("The Foxxx Comics", "/comics/the-foxxx-comics", AUTHOR),
|
||||
Triple("Bloody Sugar Comics", "/comics/bloody-sugar-comics", AUTHOR),
|
||||
Triple("Deuce Comics", "/comics/deuce-comics", AUTHOR),
|
||||
Triple("Adult Empire Comics", "/comics/adult-empire-comics", AUTHOR),
|
||||
Triple("SuperHeroineComixxx", "/comics/superheroinecomixxx", AUTHOR),
|
||||
Triple("Sluttish Comics", "/comics/sluttish-comics", AUTHOR),
|
||||
Triple("Damn3D Comics", "/comics/damn3d-comics", AUTHOR),
|
||||
Triple("Fake Celebrities Sex Pictures", "/comics/fake-celebrities-sex-pictures", AUTHOR),
|
||||
Triple("Secret Chest Comics", "/comics/secret-chest-comics", AUTHOR),
|
||||
Triple("Project Bellerophon Comics", "/comics/project-bellerophon-comics", AUTHOR),
|
||||
Triple("Smudge Comics", "/comics/smudge-comics", AUTHOR),
|
||||
Triple("Superheroine Central Comics", "/comics/superheroine-central-comics", AUTHOR),
|
||||
Triple("Jay Marvel Comics", "/comics/jay-marvel-comics", AUTHOR),
|
||||
Triple("Fred Perry Comics", "/comics/fred-perry-comics", AUTHOR),
|
||||
Triple("Seduced Amanda Comics", "/comics/seduced-amanda-comics", AUTHOR),
|
||||
Triple("VGBabes Comics", "/comics/vgbabes-comics", AUTHOR),
|
||||
Triple("SodomSluts.com Comics", "/comics/sodomsluts_com-comics", AUTHOR),
|
||||
Triple("AKABUR Comics", "/comics/akabur-comics", AUTHOR),
|
||||
Triple("eBluberry Comics", "/comics/ebluberry-comics", AUTHOR),
|
||||
Triple("InterracialComicPorn.com Comics", "/comics/interracialcomicporn_com-comics", AUTHOR),
|
||||
Triple("Dubh3d-Dubhgilla Comics", "/comics/dubh3d-dubhgilla-comics", AUTHOR),
|
||||
Triple("Gush Bomb Comix", "/comics/gush-bomb-comix", AUTHOR),
|
||||
Triple("Chiyoji Tomo Comics", "/comics/chiyoji-tomo-comics", AUTHOR),
|
||||
Triple("Mangrowing Comics", "/comics/mangrowing-comics", AUTHOR),
|
||||
Triple("eAdultComics Collection", "/comics/eadultcomics-collection", AUTHOR),
|
||||
Triple("Skulltitti Comics", "/comics/skulltitti-comics", AUTHOR),
|
||||
Triple("James Lemay Comics", "/comics/james-lemay-comics", AUTHOR),
|
||||
Triple("TalesOfPleasure.com Comics", "/comics/talesofpleasure_com-comics", AUTHOR),
|
||||
Triple("Eden Comics", "/comics/eden-comics", AUTHOR),
|
||||
Triple("WorldOfPeach Comics", "/comics/worldofpeach-comics", AUTHOR),
|
||||
Triple("Daniel40 Comics", "/comics/daniel40-comics", AUTHOR),
|
||||
Triple("DontFapGirl Comics", "/comics/dontfapgirl-comics", AUTHOR),
|
||||
Triple("Wingbird Comics", "/comics/wingbird-comics", AUTHOR),
|
||||
Triple("Intrigue3d.com Comics", "/comics/intrigue3d_com-comics", AUTHOR),
|
||||
Triple("Hentaikey Comics", "/comics/hentaikey-comics", AUTHOR),
|
||||
Triple("Kamina1978 Comics", "/comics/kamina1978-comics", AUTHOR),
|
||||
Triple("3DPerils Comics", "/comics/3dperils-comics", AUTHOR),
|
||||
Triple("Tracy Scops Comics", "/comics/tracy-scops-comics", AUTHOR),
|
||||
Triple("Shemale3D Comics", "/comics/shemale3d-comics", AUTHOR),
|
||||
Triple("InterracialSex3D.com Comics", "/comics/Interracialsex3d-Com-Comix", AUTHOR),
|
||||
Triple("MyHentaiGrid Comics", "/comics/myhentaigrid-comics", AUTHOR),
|
||||
Triple("Magnifire Comics", "/comics/magnifire-comics", AUTHOR),
|
||||
Triple("Reptileye Comics", "/comics/reptileye-comics", AUTHOR),
|
||||
Triple("ProjectPinkXXX.com Comics", "/comics/projectpinkxxx_com-comics", AUTHOR),
|
||||
Triple("CallMePlisskin Comics", "/comics/callmeplisskin-comics", AUTHOR)
|
||||
)
|
||||
|
||||
override fun getSortList() = arrayOf(
|
||||
Pair("Viewed", "viewed"),
|
||||
Pair("Liked", "liked"),
|
||||
Pair("Date", "recent"),
|
||||
Pair("A-Z", "az")
|
||||
)
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user