EroMuse - new extension for 8muses and Erofus (#4061)

This commit is contained in:
Mike 2020-08-08 21:52:11 -04:00 committed by GitHub
parent b4e171b52a
commit 0ca178aa52
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 524 additions and 0 deletions

View 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"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1006 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -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")
)
}

View File

@ -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")
)
}