Update four "all" sources (#1314)
* ComiCake: Some cleanup work Signed-off-by: TacoTheDank <SkytkRSfan3895@gmail.com> * E-Hentai: Some cleanup work Signed-off-by: TacoTheDank <SkytkRSfan3895@gmail.com> * FoolSlide: Some cleanup work and source updates Signed-off-by: TacoTheDank <SkytkRSfan3895@gmail.com> * Genkan: Some cleanup work Signed-off-by: TacoTheDank <SkytkRSfan3895@gmail.com>
This commit is contained in:
parent
27175b3dee
commit
c94cc58e7d
|
@ -3,9 +3,9 @@ apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
appName = 'Tachiyomi: ComiCake'
|
appName = 'Tachiyomi: ComiCake'
|
||||||
pkgNameSuffix = "all.comicake"
|
pkgNameSuffix = 'all.comicake'
|
||||||
extClass = '.ComiCakeFactory'
|
extClass = '.ComiCakeFactory'
|
||||||
extVersionCode = 3
|
extVersionCode = 4
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,21 +2,24 @@ package eu.kanade.tachiyomi.extension.all.comicake
|
||||||
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import eu.kanade.tachiyomi.extension.BuildConfig
|
import eu.kanade.tachiyomi.extension.BuildConfig
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
import eu.kanade.tachiyomi.source.model.*
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import org.json.JSONArray
|
import org.json.JSONArray
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import kotlin.collections.ArrayList
|
|
||||||
|
|
||||||
const val COMICAKE_DEFAULT_API_ENDPOINT = "/api" // Highly unlikely to change
|
const val COMICAKE_DEFAULT_API_ENDPOINT = "/api" // Highly unlikely to change
|
||||||
const val COMICAKE_DEFAULT_READER_ENDPOINT = "/r" // Can change based on CC config
|
const val COMICAKE_DEFAULT_READER_ENDPOINT = "/r" // Can change based on CC config
|
||||||
|
|
||||||
open class ComiCake(override val name: String, override val baseUrl: String, override val lang: String, val readerEndpoint: String = COMICAKE_DEFAULT_READER_ENDPOINT, val apiEndpoint: String = COMICAKE_DEFAULT_API_ENDPOINT) : HttpSource() {
|
open class ComiCake(override val name: String,
|
||||||
|
final override val baseUrl: String,
|
||||||
|
override val lang: String,
|
||||||
|
readerEndpoint: String = COMICAKE_DEFAULT_READER_ENDPOINT,
|
||||||
|
apiEndpoint: String = COMICAKE_DEFAULT_API_ENDPOINT) : HttpSource() {
|
||||||
override val versionId = 1
|
override val versionId = 1
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
private val readerBase = baseUrl + readerEndpoint
|
private val readerBase = baseUrl + readerEndpoint
|
||||||
|
@ -41,15 +44,15 @@ open class ComiCake(override val name: String, override val baseUrl: String, ove
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMangasPageFromComicsResponse(json: String, nested: Boolean = false): MangasPage {
|
private fun getMangasPageFromComicsResponse(json: String, nested: Boolean = false): MangasPage {
|
||||||
var response = JSONObject(json)
|
val response = JSONObject(json)
|
||||||
var results = response.getJSONArray("results")
|
val results = response.getJSONArray("results")
|
||||||
val mangas = ArrayList<SManga>()
|
val mangas = ArrayList<SManga>()
|
||||||
val ids = mutableListOf<Int>();
|
val ids = mutableListOf<Int>()
|
||||||
|
|
||||||
for (i in 0 until results.length()) {
|
for (i in 0 until results.length()) {
|
||||||
val obj = results.getJSONObject(i)
|
val obj = results.getJSONObject(i)
|
||||||
if (nested) {
|
if (nested) {
|
||||||
val nestedComic = obj.getJSONObject("comic");
|
val nestedComic = obj.getJSONObject("comic")
|
||||||
val id = nestedComic.getInt("id")
|
val id = nestedComic.getInt("id")
|
||||||
if (ids.contains(id))
|
if (ids.contains(id))
|
||||||
continue
|
continue
|
||||||
|
@ -66,7 +69,7 @@ open class ComiCake(override val name: String, override val baseUrl: String, ove
|
||||||
mangas.add(parseComicJson(obj))
|
mangas.add(parseComicJson(obj))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return MangasPage(mangas, if (response.getString("next").isNullOrEmpty() || response.getString("next") == "null") false else true)
|
return MangasPage(mangas, !(response.getString("next").isNullOrEmpty() || response.getString("next") == "null"))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||||
|
@ -79,10 +82,10 @@ open class ComiCake(override val name: String, override val baseUrl: String, ove
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseComicJson(obj: JSONObject, human: Boolean = false) = SManga.create().apply {
|
private fun parseComicJson(obj: JSONObject, human: Boolean = false) = SManga.create().apply {
|
||||||
if(human) {
|
url = if (human) {
|
||||||
url = "$readerBase/series/${obj.getString("slug")}/"
|
"$readerBase/series/${obj.getString("slug")}/"
|
||||||
} else {
|
} else {
|
||||||
url = obj.getInt("id").toString() // Yeah, I know... Feel free to improve on this
|
obj.getInt("id").toString() // Yeah, I know... Feel free to improve on this
|
||||||
}
|
}
|
||||||
title = obj.getString("name")
|
title = obj.getString("name")
|
||||||
thumbnail_url = obj.getString("cover")
|
thumbnail_url = obj.getString("cover")
|
||||||
|
@ -94,7 +97,7 @@ open class ComiCake(override val name: String, override val baseUrl: String, ove
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseListNames(arr: JSONArray): String {
|
private fun parseListNames(arr: JSONArray): String {
|
||||||
var hold = ArrayList<String>(arr.length())
|
val hold = ArrayList<String>(arr.length())
|
||||||
for (i in 0 until arr.length())
|
for (i in 0 until arr.length())
|
||||||
hold.add(arr.getJSONObject(i).getString("name"))
|
hold.add(arr.getJSONObject(i).getString("name"))
|
||||||
return hold.sorted().joinToString(", ")
|
return hold.sorted().joinToString(", ")
|
||||||
|
@ -133,7 +136,7 @@ open class ComiCake(override val name: String, override val baseUrl: String, ove
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val chapterJson = JSONObject(response.body()!!.string())
|
val chapterJson = JSONObject(response.body()!!.string())
|
||||||
var results = chapterJson.getJSONArray("results")
|
val results = chapterJson.getJSONArray("results")
|
||||||
val ret = ArrayList<SChapter>()
|
val ret = ArrayList<SChapter>()
|
||||||
for (i in 0 until results.length()) {
|
for (i in 0 until results.length()) {
|
||||||
ret.add(parseChapterJson(results.getJSONObject(i)))
|
ret.add(parseChapterJson(results.getJSONObject(i)))
|
||||||
|
@ -144,9 +147,9 @@ open class ComiCake(override val name: String, override val baseUrl: String, ove
|
||||||
override fun pageListParse(response: Response): List<Page> {
|
override fun pageListParse(response: Response): List<Page> {
|
||||||
val webPub = JSONObject(response.body()!!.string())
|
val webPub = JSONObject(response.body()!!.string())
|
||||||
val readingOrder = webPub.getJSONArray("readingOrder")
|
val readingOrder = webPub.getJSONArray("readingOrder")
|
||||||
val ret = ArrayList<Page>();
|
val ret = ArrayList<Page>()
|
||||||
for (i in 0 until readingOrder.length()) {
|
for (i in 0 until readingOrder.length()) {
|
||||||
var pageUrl = readingOrder.getJSONObject(i).getString("href")
|
val pageUrl = readingOrder.getJSONObject(i).getString("href")
|
||||||
ret.add(Page(i, "", pageUrl))
|
ret.add(Page(i, "", pageUrl))
|
||||||
}
|
}
|
||||||
return ret
|
return ret
|
|
@ -4,8 +4,8 @@ apply plugin: 'kotlin-android'
|
||||||
ext {
|
ext {
|
||||||
appName = 'Tachiyomi: E-Hentai'
|
appName = 'Tachiyomi: E-Hentai'
|
||||||
pkgNameSuffix = 'all.ehentai'
|
pkgNameSuffix = 'all.ehentai'
|
||||||
extClass = '.EHJapanese; .EHEnglish; .EHChinese; .EHDutch; .EHFrench; .EHGerman; .EHHungarian; .EHItalian; .EHKorean; .EHPolish; .EHPolish; .EHPortuguese; .EHRussian; .EHSpanish; .EHThai; .EHVietnamese; .EHSpeechless; .EHOther'
|
extClass = '.EHJapanese; .EHEnglish; .EHChinese; .EHDutch; .EHFrench; .EHGerman; .EHHungarian; .EHItalian; .EHKorean; .EHPolish; .EHPortuguese; .EHRussian; .EHSpanish; .EHThai; .EHVietnamese; .EHSpeechless; .EHOther'
|
||||||
extVersionCode = 4
|
extVersionCode = 5
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.ehentai
|
package eu.kanade.tachiyomi.extension.all.ehentai
|
||||||
|
|
||||||
|
import kotlin.math.ln
|
||||||
|
import kotlin.math.pow
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Various utility methods used in the E-Hentai source
|
* Various utility methods used in the E-Hentai source
|
||||||
*/
|
*/
|
||||||
|
@ -36,18 +39,18 @@ operator fun StringBuilder.plusAssign(other: String) {
|
||||||
*/
|
*/
|
||||||
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
fun humanReadableByteCount(bytes: Long, si: Boolean): String {
|
||||||
val unit = if (si) 1000 else 1024
|
val unit = if (si) 1000 else 1024
|
||||||
if (bytes < unit) return bytes.toString() + " B"
|
if (bytes < unit) return "$bytes B"
|
||||||
val exp = (Math.log(bytes.toDouble()) / Math.log(unit.toDouble())).toInt()
|
val exp = (ln(bytes.toDouble()) / ln(unit.toDouble())).toInt()
|
||||||
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
val pre = (if (si) "kMGTPE" else "KMGTPE")[exp - 1] + if (si) "" else "i"
|
||||||
return String.format("%.1f %sB", bytes / Math.pow(unit.toDouble(), exp.toDouble()), pre)
|
return String.format("%.1f %sB", bytes / unit.toDouble().pow(exp.toDouble()), pre)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val KB_FACTOR = 1000
|
private const val KB_FACTOR = 1000
|
||||||
private val KIB_FACTOR = 1024
|
private const val KIB_FACTOR = 1024
|
||||||
private val MB_FACTOR = 1000 * KB_FACTOR
|
private const val MB_FACTOR = 1000 * KB_FACTOR
|
||||||
private val MIB_FACTOR = 1024 * KIB_FACTOR
|
private const val MIB_FACTOR = 1024 * KIB_FACTOR
|
||||||
private val GB_FACTOR = 1000 * MB_FACTOR
|
private const val GB_FACTOR = 1000 * MB_FACTOR
|
||||||
private val GIB_FACTOR = 1024 * MIB_FACTOR
|
private const val GIB_FACTOR = 1024 * MIB_FACTOR
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse human readable size Strings
|
* Parse human readable size Strings
|
||||||
|
|
|
@ -3,24 +3,15 @@ package eu.kanade.tachiyomi.extension.all.ehentai
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.*
|
||||||
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.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.CacheControl
|
import okhttp3.*
|
||||||
import okhttp3.CookieJar
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
|
|
||||||
open class EHentai(override val lang: String, val ehLang: String) : HttpSource() {
|
open class EHentai(override val lang: String, private val ehLang: String) : HttpSource() {
|
||||||
|
|
||||||
override val name = "E-Hentai"
|
override val name = "E-Hentai"
|
||||||
|
|
||||||
|
@ -51,15 +42,13 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
return MangasPage(parsedMangas, hasNextPage)
|
return MangasPage(parsedMangas, hasNextPage)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>>
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = Observable.just(listOf(SChapter.create().apply {
|
||||||
= Observable.just(listOf(SChapter.create().apply {
|
|
||||||
url = manga.url
|
url = manga.url
|
||||||
name = "Chapter"
|
name = "Chapter"
|
||||||
chapter_number = 1f
|
chapter_number = 1f
|
||||||
}))
|
}))
|
||||||
|
|
||||||
override fun fetchPageList(chapter: SChapter)
|
override fun fetchPageList(chapter: SChapter) = fetchChapterPage(chapter, "$baseUrl/${chapter.url}").map {
|
||||||
= fetchChapterPage(chapter, "$baseUrl/${chapter.url}").map {
|
|
||||||
it.mapIndexed { i, s ->
|
it.mapIndexed { i, s ->
|
||||||
Page(i, s)
|
Page(i, s)
|
||||||
}
|
}
|
||||||
|
@ -80,8 +69,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseChapterPage(response: Element)
|
private fun parseChapterPage(response: Element) = with(response) {
|
||||||
= with(response) {
|
|
||||||
select(".gdtm a").map {
|
select(".gdtm a").map {
|
||||||
Pair(it.child(0).attr("alt").toInt(), it.attr("href"))
|
Pair(it.child(0).attr("alt").toInt(), it.attr("href"))
|
||||||
}.sortedBy(Pair<Int, String>::first).map { it.second }
|
}.sortedBy(Pair<Int, String>::first).map { it.second }
|
||||||
|
@ -90,8 +78,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
private fun chapterPageCall(np: String) = client.newCall(chapterPageRequest(np)).asObservableSuccess()
|
private fun chapterPageCall(np: String) = client.newCall(chapterPageRequest(np)).asObservableSuccess()
|
||||||
private fun chapterPageRequest(np: String) = exGet(np, null, headers)
|
private fun chapterPageRequest(np: String) = exGet(np, null, headers)
|
||||||
|
|
||||||
private fun nextPageUrl(element: Element)
|
private fun nextPageUrl(element: Element) = element.select("a[onclick=return false]").last()?.let {
|
||||||
= element.select("a[onclick=return false]").last()?.let {
|
|
||||||
if (it.text() == ">") it.attr("href") else null
|
if (it.text() == ">") it.attr("href") else null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +102,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
override fun searchMangaParse(response: Response) = genericMangaParse(response)
|
override fun searchMangaParse(response: Response) = genericMangaParse(response)
|
||||||
override fun latestUpdatesParse(response: Response) = genericMangaParse(response)
|
override fun latestUpdatesParse(response: Response) = genericMangaParse(response)
|
||||||
|
|
||||||
private fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true)
|
private fun exGet(url: String, page: Int? = null, additionalHeaders: Headers? = null, cache: Boolean = true) = GET(page?.let {
|
||||||
= GET(page?.let {
|
|
||||||
addParam(url, "page", (it - 1).toString())
|
addParam(url, "page", (it - 1).toString())
|
||||||
} ?: url, additionalHeaders?.let {
|
} ?: url, additionalHeaders?.let {
|
||||||
val headers = headers.newBuilder()
|
val headers = headers.newBuilder()
|
||||||
|
@ -204,7 +190,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
Tag(it.text().trim(),
|
Tag(it.text().trim(),
|
||||||
it.hasClass("gtl"))
|
it.hasClass("gtl"))
|
||||||
}
|
}
|
||||||
tags.put(namespace, currentTags)
|
tags[namespace] = currentTags
|
||||||
}
|
}
|
||||||
|
|
||||||
//Copy metadata to manga
|
//Copy metadata to manga
|
||||||
|
@ -214,19 +200,15 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListParse(response: Response)
|
override fun chapterListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
|
||||||
= throw UnsupportedOperationException("Unused method was called somehow!")
|
|
||||||
|
|
||||||
override fun pageListParse(response: Response)
|
override fun pageListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
|
||||||
= throw UnsupportedOperationException("Unused method was called somehow!")
|
|
||||||
|
|
||||||
override fun fetchImageUrl(page: Page)
|
override fun fetchImageUrl(page: Page) = client.newCall(imageUrlRequest(page))
|
||||||
= client.newCall(imageUrlRequest(page))
|
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { realImageUrlParse(it, page) }!!
|
.map { realImageUrlParse(it, page) }!!
|
||||||
|
|
||||||
private fun realImageUrlParse(response: Response, page: Page)
|
private fun realImageUrlParse(response: Response, page: Page) = with(response.asJsoup()) {
|
||||||
= with(response.asJsoup()) {
|
|
||||||
val currentImage = getElementById("img").attr("src")
|
val currentImage = getElementById("img").attr("src")
|
||||||
//TODO We cannot currently do this as page.url is immutable
|
//TODO We cannot currently do this as page.url is immutable
|
||||||
//Each press of the retry button will choose another server
|
//Each press of the retry button will choose another server
|
||||||
|
@ -236,8 +218,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
currentImage
|
currentImage
|
||||||
}!!
|
}!!
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response)
|
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
|
||||||
= throw UnsupportedOperationException("Unused method was called somehow!")
|
|
||||||
|
|
||||||
private val cookiesHeader by lazy {
|
private val cookiesHeader by lazy {
|
||||||
val cookies = mutableMapOf<String, String>()
|
val cookies = mutableMapOf<String, String>()
|
||||||
|
@ -253,25 +234,21 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
.flatMap { it.second }
|
.flatMap { it.second }
|
||||||
.joinToString("x")
|
.joinToString("x")
|
||||||
|
|
||||||
cookies.put("uconfig", buildSettings(settings))
|
cookies["uconfig"] = buildSettings(settings)
|
||||||
|
|
||||||
buildCookies(cookies)
|
buildCookies(cookies)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Headers
|
//Headers
|
||||||
override fun headersBuilder()
|
override fun headersBuilder() = super.headersBuilder().add("Cookie", cookiesHeader)!!
|
||||||
= super.headersBuilder().add("Cookie", cookiesHeader)!!
|
|
||||||
|
|
||||||
private fun buildSettings(settings: List<String?>)
|
private fun buildSettings(settings: List<String?>) = settings.filterNotNull().joinToString(separator = "-")
|
||||||
= settings.filterNotNull().joinToString(separator = "-")
|
|
||||||
|
|
||||||
private fun buildCookies(cookies: Map<String, String>)
|
private fun buildCookies(cookies: Map<String, String>) = cookies.entries.joinToString(separator = "; ", postfix = ";") {
|
||||||
= cookies.entries.map {
|
|
||||||
"${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}"
|
"${URLEncoder.encode(it.key, "UTF-8")}=${URLEncoder.encode(it.value, "UTF-8")}"
|
||||||
}.joinToString(separator = "; ", postfix = ";")
|
}
|
||||||
|
|
||||||
private fun addParam(url: String, param: String, value: String)
|
private fun addParam(url: String, param: String, value: String) = Uri.parse(url)
|
||||||
= Uri.parse(url)
|
|
||||||
.buildUpon()
|
.buildUpon()
|
||||||
.appendQueryParameter(param, value)
|
.appendQueryParameter(param, value)
|
||||||
.toString()
|
.toString()
|
||||||
|
@ -295,9 +272,9 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
AdvancedGroup()
|
AdvancedGroup()
|
||||||
)
|
)
|
||||||
|
|
||||||
class GenreOption(name: String, val genreId: String) : Filter.CheckBox(name, false), UriFilter {
|
class GenreOption(name: String, private val genreId: String) : Filter.CheckBox(name, false), UriFilter {
|
||||||
override fun addToUri(builder: Uri.Builder) {
|
override fun addToUri(builder: Uri.Builder) {
|
||||||
builder.appendQueryParameter("f_" + genreId, if (state) "1" else "0")
|
builder.appendQueryParameter("f_$genreId", if (state) "1" else "0")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,7 +291,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
GenreOption("Misc", "misc")
|
GenreOption("Misc", "misc")
|
||||||
))
|
))
|
||||||
|
|
||||||
class AdvancedOption(name: String, val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter {
|
class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter {
|
||||||
override fun addToUri(builder: Uri.Builder) {
|
override fun addToUri(builder: Uri.Builder) {
|
||||||
if (state)
|
if (state)
|
||||||
builder.appendQueryParameter(param, "on")
|
builder.appendQueryParameter(param, "on")
|
||||||
|
@ -329,7 +306,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
||||||
"5 stars"
|
"5 stars"
|
||||||
)), UriFilter {
|
)), UriFilter {
|
||||||
override fun addToUri(builder: Uri.Builder) {
|
override fun addToUri(builder: Uri.Builder) {
|
||||||
if (state > 0) builder.appendQueryParameter("f_srdd", Integer.toString(state + 1))
|
if (state > 0) builder.appendQueryParameter("f_srdd", (state + 1).toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.ehentai;
|
package eu.kanade.tachiyomi.extension.all.ehentai
|
||||||
|
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
|
|
||||||
|
@ -32,8 +32,7 @@ class ExGalleryMetadata {
|
||||||
val tags: MutableMap<String, List<Tag>> = mutableMapOf()
|
val tags: MutableMap<String, List<Tag>> = mutableMapOf()
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun splitGalleryUrl(url: String)
|
private fun splitGalleryUrl(url: String) = url.let {
|
||||||
= url.let {
|
|
||||||
//Only parse URL if is full URL
|
//Only parse URL if is full URL
|
||||||
val pathSegments = if (it.startsWith("http"))
|
val pathSegments = if (it.startsWith("http"))
|
||||||
Uri.parse(it).pathSegments
|
Uri.parse(it).pathSegments
|
||||||
|
@ -42,15 +41,12 @@ class ExGalleryMetadata {
|
||||||
pathSegments.filterNot(String::isNullOrBlank)
|
pathSegments.filterNot(String::isNullOrBlank)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun galleryId(url: String) = splitGalleryUrl(url)[1]
|
private fun galleryId(url: String) = splitGalleryUrl(url)[1]
|
||||||
|
|
||||||
fun galleryToken(url: String) =
|
private fun galleryToken(url: String) = splitGalleryUrl(url)[2]
|
||||||
splitGalleryUrl(url)[2]
|
|
||||||
|
|
||||||
fun normalizeUrl(id: String, token: String)
|
private fun normalizeUrl(id: String, token: String) = "/g/$id/$token/?nw=always"
|
||||||
= "/g/$id/$token/?nw=always"
|
|
||||||
|
|
||||||
fun normalizeUrl(url: String)
|
fun normalizeUrl(url: String) = normalizeUrl(galleryId(url), galleryToken(url))
|
||||||
= normalizeUrl(galleryId(url), galleryToken(url))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,8 +71,7 @@ fun ExGalleryMetadata.copyTo(manga: SManga) {
|
||||||
.joinToString(separator = "\n")
|
.joinToString(separator = "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildTagsDescription(metadata: ExGalleryMetadata)
|
private fun buildTagsDescription(metadata: ExGalleryMetadata) = StringBuilder("Tags:\n").apply {
|
||||||
= StringBuilder("Tags:\n").apply {
|
|
||||||
//BiConsumer only available in Java 8, we have to use destructuring here
|
//BiConsumer only available in Java 8, we have to use destructuring here
|
||||||
metadata.tags.forEach { (namespace, tags) ->
|
metadata.tags.forEach { (namespace, tags) ->
|
||||||
if (tags.isNotEmpty()) {
|
if (tags.isNotEmpty()) {
|
||||||
|
|
|
@ -3,9 +3,9 @@ apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
ext {
|
ext {
|
||||||
appName = 'Tachiyomi: FoolSlide'
|
appName = 'Tachiyomi: FoolSlide'
|
||||||
pkgNameSuffix = "all.foolslide"
|
pkgNameSuffix = 'all.foolslide'
|
||||||
extClass = '.FoolSlideFactory'
|
extClass = '.FoolSlideFactory'
|
||||||
extVersionCode = 21
|
extVersionCode = 22
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,10 @@ import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
open class FoolSlide(override val name: String, override val baseUrl: String, override val lang: String, val urlModifier: String = "") : ParsedHttpSource() {
|
open class FoolSlide(override val name: String,
|
||||||
|
override val baseUrl: String,
|
||||||
|
override val lang: String,
|
||||||
|
val urlModifier: String = "") : ParsedHttpSource() {
|
||||||
|
|
||||||
protected open val dedupeLatestUpdates = true
|
protected open val dedupeLatestUpdates = true
|
||||||
|
|
||||||
|
@ -96,8 +99,7 @@ open class FoolSlide(override val name: String, override val baseUrl: String, ov
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = "a:has(span.next)"
|
override fun searchMangaNextPageSelector() = "a:has(span.next)"
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga)
|
override fun mangaDetailsRequest(manga: SManga) = allowAdult(super.mangaDetailsRequest(manga))
|
||||||
= allowAdult(super.mangaDetailsRequest(manga))
|
|
||||||
|
|
||||||
open val mangaDetailsInfoSelector = "div.info"
|
open val mangaDetailsInfoSelector = "div.info"
|
||||||
open val mangaDetailsThumbnailSelector = "div.thumbnail img"
|
open val mangaDetailsThumbnailSelector = "div.thumbnail img"
|
||||||
|
@ -119,14 +121,13 @@ open class FoolSlide(override val name: String, override val baseUrl: String, ov
|
||||||
*/
|
*/
|
||||||
private fun allowAdult(request: Request) = allowAdult(request.url().toString())
|
private fun allowAdult(request: Request) = allowAdult(request.url().toString())
|
||||||
|
|
||||||
protected fun allowAdult(url: String): Request {
|
private fun allowAdult(url: String): Request {
|
||||||
return POST(url, body = FormBody.Builder()
|
return POST(url, body = FormBody.Builder()
|
||||||
.add("adult", "true")
|
.add("adult", "true")
|
||||||
.build())
|
.build())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga)
|
override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga))
|
||||||
= allowAdult(super.chapterListRequest(manga))
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "div.group div.element, div.list div.element"
|
override fun chapterListSelector() = "div.group div.element, div.list div.element"
|
||||||
|
|
||||||
|
@ -140,7 +141,8 @@ open class FoolSlide(override val name: String, override val baseUrl: String, ov
|
||||||
val chapter = SChapter.create()
|
val chapter = SChapter.create()
|
||||||
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
chapter.setUrlWithoutDomain(urlElement.attr("href"))
|
||||||
chapter.name = urlElement.text()
|
chapter.name = urlElement.text()
|
||||||
chapter.date_upload = dateElement.text()?.let { parseChapterDate(it.substringAfter(", ")) } ?: 0
|
chapter.date_upload = dateElement.text()?.let { parseChapterDate(it.substringAfter(", ")) }
|
||||||
|
?: 0
|
||||||
return chapter
|
return chapter
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,8 +237,7 @@ open class FoolSlide(override val name: String, override val baseUrl: String, ov
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter)
|
override fun pageListRequest(chapter: SChapter) = allowAdult(super.pageListRequest(chapter))
|
||||||
= allowAdult(super.pageListRequest(chapter))
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
override fun pageListParse(document: Document): List<Page> {
|
||||||
val doc = document.toString()
|
val doc = document.toString()
|
|
@ -6,7 +6,8 @@ import com.google.gson.JsonParser
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.source.Source
|
import eu.kanade.tachiyomi.source.Source
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
import eu.kanade.tachiyomi.source.SourceFactory
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
|
@ -36,7 +37,6 @@ fun getAllFoolSlide(): List<Source> {
|
||||||
MangaScouts(),
|
MangaScouts(),
|
||||||
StormInHeaven(),
|
StormInHeaven(),
|
||||||
Lilyreader(),
|
Lilyreader(),
|
||||||
MidnightHaven(),
|
|
||||||
Russification(),
|
Russification(),
|
||||||
EvilFlowers(),
|
EvilFlowers(),
|
||||||
AkaiYuhiMunTeam(),
|
AkaiYuhiMunTeam(),
|
||||||
|
@ -74,7 +74,7 @@ class SenseScans : FoolSlide("Sense-Scans", "https://sensescans.com", "en", "/re
|
||||||
|
|
||||||
class KireiCake : FoolSlide("Kirei Cake", "https://reader.kireicake.com", "en")
|
class KireiCake : FoolSlide("Kirei Cake", "https://reader.kireicake.com", "en")
|
||||||
|
|
||||||
class SilentSky : FoolSlide("Silent Sky", "http://reader.silentsky-scans.net", "en")
|
class SilentSky : FoolSlide("Silent Sky", "https://reader.silentsky-scans.net", "en")
|
||||||
|
|
||||||
class Mangatellers : FoolSlide("Mangatellers", "http://www.mangatellers.gr", "en", "/reader/reader") {
|
class Mangatellers : FoolSlide("Mangatellers", "http://www.mangatellers.gr", "en", "/reader/reader") {
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
@ -108,12 +108,10 @@ class TsubasaSociety : FoolSlide("Tsubasa Society", "https://www.tsubasasociety.
|
||||||
|
|
||||||
class MangaScouts : FoolSlide("MangaScouts", "http://onlinereader.mangascouts.org", "de")
|
class MangaScouts : FoolSlide("MangaScouts", "http://onlinereader.mangascouts.org", "de")
|
||||||
|
|
||||||
class StormInHeaven : FoolSlide("Storm in Heaven", "http://www.storm-in-heaven.net", "it", "/reader-sih")
|
class StormInHeaven : FoolSlide("Storm in Heaven", "https://www.storm-in-heaven.net", "it", "/reader-sih")
|
||||||
|
|
||||||
class Lilyreader : FoolSlide("Lilyreader", "https://manga.smuglo.li", "en")
|
class Lilyreader : FoolSlide("Lilyreader", "https://manga.smuglo.li", "en")
|
||||||
|
|
||||||
class MidnightHaven : FoolSlide("Midnight Haven", "http://midnighthaven.shounen-ai.net", "en", "/reader")
|
|
||||||
|
|
||||||
class Russification : FoolSlide("Русификация", "https://rusmanga.ru", "ru")
|
class Russification : FoolSlide("Русификация", "https://rusmanga.ru", "ru")
|
||||||
|
|
||||||
class EvilFlowers : FoolSlide("Evil Flowers", "http://reader.evilflowers.com", "en")
|
class EvilFlowers : FoolSlide("Evil Flowers", "http://reader.evilflowers.com", "en")
|
||||||
|
@ -158,5 +156,3 @@ class ShoujoHearts : FoolSlide("ShoujoHearts", "http://shoujohearts.com", "en",
|
||||||
return manga
|
return manga
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,6 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
||||||
class ArtistFilter : Filter.Text("Artist (must be exact match)")
|
class ArtistFilter : Filter.Text("Artist (must be exact match)")
|
||||||
class BookFilter : Filter.CheckBox("Show books only", false)
|
class BookFilter : Filter.CheckBox("Show books only", false)
|
||||||
class TagFilter : Filter.Select<Tag>("Tag", arrayOf(
|
class TagFilter : Filter.Select<Tag>("Tag", arrayOf(
|
||||||
Tag("all", "All"),
|
|
||||||
Tag("ahegao", "Ahegao"),
|
Tag("ahegao", "Ahegao"),
|
||||||
Tag("anal", "Anal"),
|
Tag("anal", "Anal"),
|
||||||
Tag("big-ass", "Big ass"),
|
Tag("big-ass", "Big ass"),
|
||||||
|
@ -155,9 +154,9 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
||||||
Tag("group", "Group"),
|
Tag("group", "Group"),
|
||||||
Tag("hairy", "Hairy"),
|
Tag("hairy", "Hairy"),
|
||||||
Tag("handjob", "Handjob"),
|
Tag("handjob", "Handjob"),
|
||||||
|
Tag("heart-pupils", "Heart pupils"),
|
||||||
Tag("housewife", "Housewife"),
|
Tag("housewife", "Housewife"),
|
||||||
Tag("incest", "Incest"),
|
Tag("incest", "Incest"),
|
||||||
Tag("large-breast", "Large breast"),
|
|
||||||
Tag("lingerie", "Lingerie"),
|
Tag("lingerie", "Lingerie"),
|
||||||
Tag("loli", "Loli"),
|
Tag("loli", "Loli"),
|
||||||
Tag("masturbation", "Masturbation"),
|
Tag("masturbation", "Masturbation"),
|
||||||
|
@ -167,7 +166,7 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
||||||
Tag("pettanko", "Pettanko"),
|
Tag("pettanko", "Pettanko"),
|
||||||
Tag("rape", "Rape"),
|
Tag("rape", "Rape"),
|
||||||
Tag("schoolgirl", "Schoolgirl"),
|
Tag("schoolgirl", "Schoolgirl"),
|
||||||
Tag("sex-toys", "Sex Toys"),
|
Tag("sex-toys", "Sex toys"),
|
||||||
Tag("shota", "Shota"),
|
Tag("shota", "Shota"),
|
||||||
Tag("socks", "Socks"),
|
Tag("socks", "Socks"),
|
||||||
Tag("stocking", "Stocking"),
|
Tag("stocking", "Stocking"),
|
||||||
|
@ -175,11 +174,12 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
|
||||||
Tag("swimsuit", "Swimsuit"),
|
Tag("swimsuit", "Swimsuit"),
|
||||||
Tag("teacher", "Teacher"),
|
Tag("teacher", "Teacher"),
|
||||||
Tag("tsundere", "Tsundere"),
|
Tag("tsundere", "Tsundere"),
|
||||||
Tag("uncensored", "uncensored"),
|
Tag("uncensored", "Uncensored"),
|
||||||
Tag("vanilla", "Vanilla"),
|
Tag("vanilla", "Vanilla"),
|
||||||
Tag("x-ray", "X-ray")
|
Tag("x-ray", "X-Ray")
|
||||||
))
|
))
|
||||||
class Tag(val name: String, val displayName: String) {
|
|
||||||
|
class Tag(val name: String, private val displayName: String) {
|
||||||
override fun toString() = displayName
|
override fun toString() = displayName
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ ext {
|
||||||
appName = 'Tachiyomi: Genkan (multiple sources)'
|
appName = 'Tachiyomi: Genkan (multiple sources)'
|
||||||
pkgNameSuffix = 'all.genkan'
|
pkgNameSuffix = 'all.genkan'
|
||||||
extClass = '.GenkanFactory'
|
extClass = '.GenkanFactory'
|
||||||
extVersionCode = 2
|
extVersionCode = 3
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ import java.util.*
|
||||||
|
|
||||||
abstract class Genkan(
|
abstract class Genkan(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val baseUrl: String,
|
final override val baseUrl: String,
|
||||||
override val lang: String
|
override val lang: String
|
||||||
) : ParsedHttpSource() {
|
) : ParsedHttpSource() {
|
||||||
|
|
||||||
|
@ -165,10 +165,10 @@ abstract class Genkan(
|
||||||
|
|
||||||
// If the date string contains the word "ago" send it off for relative date parsing otherwise use dateFormat
|
// If the date string contains the word "ago" send it off for relative date parsing otherwise use dateFormat
|
||||||
private fun parseChapterDate(string: String): Long? {
|
private fun parseChapterDate(string: String): Long? {
|
||||||
if ("ago" in string) {
|
return if ("ago" in string) {
|
||||||
return parseRelativeDate(string) ?: 0
|
parseRelativeDate(string) ?: 0
|
||||||
} else {
|
} else {
|
||||||
return dateFormat.parse(string).time
|
dateFormat.parse(string).time
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,5 +207,4 @@ abstract class Genkan(
|
||||||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
|
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
|
||||||
|
|
||||||
override fun getFilterList() = FilterList()
|
override fun getFilterList() = FilterList()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue