Update Kotlin, coroutines, kolinter (#4363)

* Update kolinter, address some build warnings

* Update to Kotlin 1.4.10, coroutines 1.3.9
This commit is contained in:
arkon 2020-09-13 18:33:59 -04:00 committed by GitHub
parent 19a3cd2367
commit 016653bdc0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
229 changed files with 9702 additions and 8853 deletions

View File

@ -1,6 +1,6 @@
buildscript { buildscript {
ext.kotlin_version = '1.3.72' ext.kotlin_version = '1.4.10'
ext.coroutines_version = '1.3.5' ext.coroutines_version = '1.3.9'
repositories { repositories {
google() google()
maven { url 'https://plugins.gradle.org/m2/' } maven { url 'https://plugins.gradle.org/m2/' }
@ -10,7 +10,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:4.0.1' classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath 'org.jmailen.gradle:kotlinter-gradle:2.3.2' classpath 'org.jmailen.gradle:kotlinter-gradle:3.0.2'
} }
} }

View File

@ -1,6 +1,6 @@
object Deps { object Deps {
object kotlin { object kotlin {
const val version = "1.3.72" const val version = "1.4.10"
const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version" const val stdlib = "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$version"
} }

View File

@ -7,13 +7,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
open class BoomManga( open class BoomManga(
override val name: String, override val name: String,
@ -69,11 +69,11 @@ open class BoomManga(
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.url = element.select("a").attr("href") chapter.url = element.select("a").attr("href")
chapter.chapter_number = element.select("[data-num]").attr("data-num").toFloat() chapter.chapter_number = element.select("[data-num]").attr("data-num").toFloat()
val date = element.select(".date").text() val date = element.select(".date").text()
if (date.isNotBlank()) { chapter.date_upload = parseDate(date) } if (date.isNotBlank()) { chapter.date_upload = parseDate(date) }
chapter.name = nameselector(element).trim() chapter.name = nameselector(element).trim()
return chapter return chapter
} }
@ -84,7 +84,7 @@ open class BoomManga(
} }
private fun parseDate(date: String): Long { private fun parseDate(date: String): Long {
return SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.US).parse(date).time return SimpleDateFormat("yyyy-MM-dd kk:mm:ss", Locale.US).parse(date)?.time ?: 0L
} }
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {

View File

@ -10,14 +10,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
abstract class ComiCake( abstract class ComiCake(
override val name: String, override val name: String,
@ -146,7 +146,7 @@ abstract class ComiCake(
private fun parseChapterJson(obj: JSONObject) = SChapter.create().apply { private fun parseChapterJson(obj: JSONObject) = SChapter.create().apply {
name = obj.getString("title") // title will always have content, vs. name that's an optional field name = obj.getString("title") // title will always have content, vs. name that's an optional field
chapter_number = (obj.getInt("chapter") + (obj.getInt("subchapter") / 10.0)).toFloat() chapter_number = (obj.getInt("chapter") + (obj.getInt("subchapter") / 10.0)).toFloat()
date_upload = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ", Locale.getDefault()).parse(obj.getString("published_at")).time date_upload = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZZZ", Locale.getDefault()).parse(obj.getString("published_at"))?.time ?: 0L
// TODO scanlator field by adding team to expandable in CC (low priority given the use case of CC) // TODO scanlator field by adding team to expandable in CC (low priority given the use case of CC)
url = obj.getString("manifest") url = obj.getString("manifest")
} }

View File

@ -4,8 +4,6 @@ import android.annotation.SuppressLint
import android.app.Application import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.support.v7.preference.CheckBoxPreference as LegacyCheckBoxPreference
import android.support.v7.preference.PreferenceScreen as LegacyPreferenceScreen
import androidx.preference.CheckBoxPreference import androidx.preference.CheckBoxPreference
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
@ -24,7 +22,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.net.URLEncoder
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.Headers import okhttp3.Headers
@ -34,6 +31,9 @@ import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.net.URLEncoder
import android.support.v7.preference.CheckBoxPreference as LegacyCheckBoxPreference
import android.support.v7.preference.PreferenceScreen as LegacyPreferenceScreen
open class EHentai(override val lang: String, private val ehLang: String) : ConfigurableSource, HttpSource() { open class EHentai(override val lang: String, private val ehLang: String) : ConfigurableSource, HttpSource() {
@ -85,11 +85,15 @@ open class EHentai(override val lang: String, private val ehLang: String) : Conf
return MangasPage(parsedMangas, hasNextPage) return MangasPage(parsedMangas, hasNextPage)
} }
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = Observable.just(listOf(SChapter.create().apply { override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> = Observable.just(
url = manga.url listOf(
name = "Chapter" SChapter.create().apply {
chapter_number = 1f url = manga.url
})) name = "Chapter"
chapter_number = 1f
}
)
)
override fun fetchPageList(chapter: SChapter) = fetchChapterPage(chapter, "$baseUrl/${chapter.url}").map { override fun fetchPageList(chapter: SChapter) = fetchChapterPage(chapter, "$baseUrl/${chapter.url}").map {
it.mapIndexed { i, s -> it.mapIndexed { i, s ->
@ -218,8 +222,10 @@ open class EHentai(override val lang: String, private val ehLang: String) : Conf
?.trim() ?.trim()
?.let { right -> ?.let { right ->
ignore { ignore {
when (left.removeSuffix(":") when (
.toLowerCase()) { left.removeSuffix(":")
.toLowerCase()
) {
"posted" -> datePosted = EX_DATE_FORMAT.parse(right)?.time ?: 0 "posted" -> datePosted = EX_DATE_FORMAT.parse(right)?.time ?: 0
"visible" -> visible = right.nullIfBlank() "visible" -> visible = right.nullIfBlank()
"language" -> { "language" -> {
@ -255,8 +261,10 @@ open class EHentai(override val lang: String, private val ehLang: String) : Conf
select("#taglist tr").forEach { select("#taglist tr").forEach {
val namespace = it.select(".tc").text().removeSuffix(":") val namespace = it.select(".tc").text().removeSuffix(":")
val currentTags = it.select("div").map { element -> val currentTags = it.select("div").map { element ->
Tag(element.text().trim(), Tag(
element.hasClass("gtl")) element.text().trim(),
element.hasClass("gtl")
)
} }
tags[namespace] = currentTags tags[namespace] = currentTags
} }
@ -367,18 +375,21 @@ open class EHentai(override val lang: String, private val ehLang: String) : Conf
} }
} }
class GenreGroup : UriGroup<GenreOption>("Genres", listOf( class GenreGroup : UriGroup<GenreOption>(
GenreOption("Dōjinshi", "doujinshi"), "Genres",
GenreOption("Manga", "manga"), listOf(
GenreOption("Artist CG", "artistcg"), GenreOption("Dōjinshi", "doujinshi"),
GenreOption("Game CG", "gamecg"), GenreOption("Manga", "manga"),
GenreOption("Western", "western"), GenreOption("Artist CG", "artistcg"),
GenreOption("Non-H", "non-h"), GenreOption("Game CG", "gamecg"),
GenreOption("Image Set", "imageset"), GenreOption("Western", "western"),
GenreOption("Cosplay", "cosplay"), GenreOption("Non-H", "non-h"),
GenreOption("Asian Porn", "asianporn"), GenreOption("Image Set", "imageset"),
GenreOption("Misc", "misc") GenreOption("Cosplay", "cosplay"),
)) GenreOption("Asian Porn", "asianporn"),
GenreOption("Misc", "misc")
)
)
class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : CheckBox(name, defValue), UriFilter { class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : CheckBox(name, defValue), UriFilter {
override fun addToUri(builder: Uri.Builder) { override fun addToUri(builder: Uri.Builder) {
@ -423,19 +434,22 @@ open class EHentai(override val lang: String, private val ehLang: String) : Conf
} }
// Explicit type arg for listOf() to workaround this: KT-16570 // Explicit type arg for listOf() to workaround this: KT-16570
class AdvancedGroup : UriGroup<Filter<*>>("Advanced Options", listOf( class AdvancedGroup : UriGroup<Filter<*>>(
AdvancedOption("Search Gallery Name", "f_sname", true), "Advanced Options",
AdvancedOption("Search Gallery Tags", "f_stags", true), listOf(
AdvancedOption("Search Gallery Description", "f_sdesc"), AdvancedOption("Search Gallery Name", "f_sname", true),
AdvancedOption("Search Torrent Filenames", "f_storr"), AdvancedOption("Search Gallery Tags", "f_stags", true),
AdvancedOption("Only Show Galleries With Torrents", "f_sto"), AdvancedOption("Search Gallery Description", "f_sdesc"),
AdvancedOption("Search Low-Power Tags", "f_sdt1"), AdvancedOption("Search Torrent Filenames", "f_storr"),
AdvancedOption("Search Downvoted Tags", "f_sdt2"), AdvancedOption("Only Show Galleries With Torrents", "f_sto"),
AdvancedOption("Show Expunged Galleries", "f_sh"), AdvancedOption("Search Low-Power Tags", "f_sdt1"),
RatingOption(), AdvancedOption("Search Downvoted Tags", "f_sdt2"),
MinPagesOption(), AdvancedOption("Show Expunged Galleries", "f_sh"),
MaxPagesOption() RatingOption(),
)) MinPagesOption(),
MaxPagesOption()
)
)
private class EnforceLanguageFilter(default: Boolean) : CheckBox("Enforce language", default) private class EnforceLanguageFilter(default: Boolean) : CheckBox("Enforce language", default)

View File

@ -38,8 +38,9 @@ fun ExGalleryMetadata.copyTo(manga: SManga) {
manga.status = SManga.COMPLETED manga.status = SManga.COMPLETED
title?.let { t -> title?.let { t ->
if (ONGOING_SUFFIX.any { if (ONGOING_SUFFIX.any {
t.endsWith(it, ignoreCase = true) t.endsWith(it, ignoreCase = true)
}) manga.status = SManga.ONGOING }
) manga.status = SManga.ONGOING
} }
// Build a nice looking description out of what we know // Build a nice looking description out of what we know

View File

@ -37,14 +37,17 @@ open class EliMangasProvider(
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
val json = gson.fromJson<JsonArray>(response.body()!!.string()).asJsonArray val json = gson.fromJson<JsonArray>(response.body()!!.string()).asJsonArray
return MangasPage(json.map { return MangasPage(
SManga.create().apply { json.map {
val id = it["id"].asString SManga.create().apply {
url = id val id = it["id"].asString
title = it["name"].asString url = id
thumbnail_url = "https://www.elimangas.com/images/$id.jpg" title = it["name"].asString
} thumbnail_url = "https://www.elimangas.com/images/$id.jpg"
}, json.size() >= 30) }
},
json.size() >= 30
)
} }
// Latest // Latest

View File

@ -7,14 +7,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.util.Calendar
import java.util.concurrent.TimeUnit
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.Calendar
import java.util.concurrent.TimeUnit
open class Emerald( open class Emerald(
override val name: String, override val name: String,
@ -76,8 +76,11 @@ open class Emerald(
} }
} }
if (styleToInclude.isNotEmpty()) { if (styleToInclude.isNotEmpty()) {
url.addQueryParameter("styles", styleToInclude url.addQueryParameter(
.joinToString(",")) "styles",
styleToInclude
.joinToString(",")
)
} }
} }
is DemographicFilter -> { is DemographicFilter -> {
@ -88,8 +91,11 @@ open class Emerald(
} }
} }
if (demographicToInclude.isNotEmpty()) { if (demographicToInclude.isNotEmpty()) {
url.addQueryParameter("demogs", demographicToInclude url.addQueryParameter(
.joinToString(",")) "demogs",
demographicToInclude
.joinToString(",")
)
} }
} }
is StatusFilter -> { is StatusFilter -> {
@ -110,8 +116,11 @@ open class Emerald(
} }
} }
if (genreToInclude.isNotEmpty()) { if (genreToInclude.isNotEmpty()) {
url.addQueryParameter("genres", genreToInclude url.addQueryParameter(
.joinToString(",")) "genres",
genreToInclude
.joinToString(",")
)
} }
} }
is StarFilter -> { is StarFilter -> {
@ -154,8 +163,10 @@ open class Emerald(
val manga = SManga.create() val manga = SManga.create()
val genres = mutableListOf<String>() val genres = mutableListOf<String>()
val status = infoElement.select("div.attr-item:contains(status) span").text() val status = infoElement.select("div.attr-item:contains(status) span").text()
infoElement.select("div.attr-item:contains(genres) span").text().split(" / " infoElement.select("div.attr-item:contains(genres) span").text().split(
.toRegex()).forEach { element -> " / "
.toRegex()
).forEach { element ->
genres.add(element) genres.add(element)
} }
manga.title = infoElement.select("h3").text() manga.title = infoElement.select("h3").text()
@ -259,10 +270,12 @@ open class Emerald(
val imgJson = JSONObject(script) val imgJson = JSONObject(script)
val imgNames = imgJson.names() val imgNames = imgJson.names()
for (i in 0 until imgNames.length()) { if (imgNames != null) {
val imgKey = imgNames.getString(i) for (i in 0 until imgNames.length()) {
val imgUrl = imgJson.getString(imgKey) val imgKey = imgNames.getString(i)
pages.add(Page(i, "", imgUrl)) val imgUrl = imgJson.getString(imgKey)
pages.add(Page(i, "", imgUrl))
}
} }
return pages return pages
@ -276,40 +289,49 @@ open class Emerald(
private class GenreFilter(genres: List<Tag>) : Filter.Group<Tag>("Genres", genres) private class GenreFilter(genres: List<Tag>) : Filter.Group<Tag>("Genres", genres)
private class StatusFilter : Filter.TriState("Completed") private class StatusFilter : Filter.TriState("Completed")
private class StarFilter : UriPartFilter("Stars", arrayOf( private class StarFilter : UriPartFilter(
Pair("<select>", ""), "Stars",
Pair("5 Stars", "5"), arrayOf(
Pair("4 Stars", "4"), Pair("<select>", ""),
Pair("3 Stars", "3"), Pair("5 Stars", "5"),
Pair("2 Stars", "2"), Pair("4 Stars", "4"),
Pair("1 Stars", "1") Pair("3 Stars", "3"),
)) Pair("2 Stars", "2"),
Pair("1 Stars", "1")
)
)
private class ChapterFilter : UriPartFilter("Chapters", arrayOf( private class ChapterFilter : UriPartFilter(
Pair("<select>", ""), "Chapters",
Pair("1 ~ 9", "1-9"), arrayOf(
Pair("10 ~ 29", "10-29"), Pair("<select>", ""),
Pair("30 ~ 99", "30-99"), Pair("1 ~ 9", "1-9"),
Pair("100 ~ 199", "100-199"), Pair("10 ~ 29", "10-29"),
Pair("200+", "200"), Pair("30 ~ 99", "30-99"),
Pair("100+", "100"), Pair("100 ~ 199", "100-199"),
Pair("50+", "50"), Pair("200+", "200"),
Pair("10+", "10"), Pair("100+", "100"),
Pair("1+", "1") Pair("50+", "50"),
)) Pair("10+", "10"),
Pair("1+", "1")
)
)
private class SortBy : UriPartFilter("Sorts By", arrayOf( private class SortBy : UriPartFilter(
Pair("<select>", ""), "Sorts By",
Pair("Totally", "views_t"), arrayOf(
Pair("365 days", "views_y"), Pair("<select>", ""),
Pair("30 days", "views_m"), Pair("Totally", "views_t"),
Pair("7 days", "views_w"), Pair("365 days", "views_y"),
Pair("24 hours", "views_d"), Pair("30 days", "views_m"),
Pair("60 minutes", "views_h"), Pair("7 days", "views_w"),
Pair("A-Z", "title"), Pair("24 hours", "views_d"),
Pair("Update time", "update"), Pair("60 minutes", "views_h"),
Pair("Add time", "create") Pair("A-Z", "title"),
)) Pair("Update time", "update"),
Pair("Add time", "create")
)
)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
Filter.Header("NOTE: Ignored if using text search!"), Filter.Header("NOTE: Ignored if using text search!"),

View File

@ -10,8 +10,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.nio.charset.Charset
import java.util.Calendar
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -20,6 +18,8 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import java.nio.charset.Charset
import java.util.Calendar
/** /**
* For sites based on the Flat-Manga CMS * For sites based on the Flat-Manga CMS
@ -81,11 +81,14 @@ abstract class FMReader(
url.addQueryParameter("ungenre", ungenre) url.addQueryParameter("ungenre", ungenre)
} }
is SortBy -> { is SortBy -> {
url.addQueryParameter("sort", when (filter.state?.index) { url.addQueryParameter(
0 -> "name" "sort",
1 -> "views" when (filter.state?.index) {
else -> "last_update" 0 -> "name"
}) 1 -> "views"
else -> "last_update"
}
)
if (filter.state?.ascending == true) if (filter.state?.ascending == true)
url.addQueryParameter("sort_type", "ASC") url.addQueryParameter("sort_type", "ASC")
} }

View File

@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.net.URLEncoder
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -20,6 +19,7 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.net.URLEncoder
class FMReaderFactory : SourceFactory { class FMReaderFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(
@ -242,9 +242,11 @@ class SayTruyen : FMReader("Say Truyen", "https://saytruyen.com", "vi") {
} }
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
return response.asJsoup().let { document -> return response.asJsoup().let { document ->
document.select(chapterListSelector()).map { chapterFromElement(it).apply { document.select(chapterListSelector()).map {
scanlator = document.select("div.row li:has(b:contains(Nhóm dịch)) small").text() chapterFromElement(it).apply {
} } scanlator = document.select("div.row li:has(b:contains(Nhóm dịch)) small").text()
}
}
} }
} }
override fun pageListParse(document: Document): List<Page> = super.pageListParse(document).onEach { it.imageUrl!!.trim() } override fun pageListParse(document: Document): List<Page> = super.pageListParse(document).onEach { it.imageUrl!!.trim() }

View File

@ -10,17 +10,17 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.FormBody
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.HashSet import java.util.HashSet
import java.util.Locale import java.util.Locale
import okhttp3.FormBody
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
abstract class FoolSlide( abstract class FoolSlide(
override val name: String, override val name: String,
@ -116,9 +116,9 @@ abstract class FoolSlide(
// if there's no image on the details page, get the first page of the first chapter // if there's no image on the details page, get the first page of the first chapter
fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? { fun getDetailsThumbnail(document: Document, urlSelector: String = chapterUrlSelector): String? {
return document.select("div.thumbnail img, table.thumb img").firstOrNull()?.attr("abs:src") return document.select("div.thumbnail img, table.thumb img").firstOrNull()?.attr("abs:src")
?: document.select(chapterListSelector()).last().select(urlSelector).attr("abs:href") ?: document.select(chapterListSelector()).last().select(urlSelector).attr("abs:href")
.let { url -> client.newCall(allowAdult(GET(url, headers))).execute() } .let { url -> client.newCall(allowAdult(GET(url, headers))).execute() }
.let { response -> pageListParse(response).first().imageUrl } .let { response -> pageListParse(response).first().imageUrl }
} }
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
@ -138,9 +138,12 @@ abstract class FoolSlide(
private fun allowAdult(request: Request) = allowAdult(request.url().toString()) private fun allowAdult(request: Request) = allowAdult(request.url().toString())
private fun allowAdult(url: String): Request { private fun allowAdult(url: String): Request {
return POST(url, body = FormBody.Builder() return POST(
.add("adult", "true") url,
.build()) body = FormBody.Builder()
.add("adult", "true")
.build()
)
} }
override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga)) override fun chapterListRequest(manga: SManga) = allowAdult(super.chapterListRequest(manga))
@ -216,7 +219,7 @@ abstract class FoolSlide(
if (result != null) { if (result != null) {
// Result parsed but no year, copy current year over // Result parsed but no year, copy current year over
result = Calendar.getInstance().apply { result = Calendar.getInstance().apply {
time = result time = result!!
set(Calendar.YEAR, Calendar.getInstance().get(Calendar.YEAR)) set(Calendar.YEAR, Calendar.getInstance().get(Calendar.YEAR))
}.time }.time
} }

View File

@ -9,12 +9,12 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.net.URLEncoder
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.net.URLEncoder
@Nsfw @Nsfw
class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga") { class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga") {
@ -124,7 +124,8 @@ class HentaiCafe : FoolSlide("Hentai Cafe", "https://hentai.cafe", "en", "/manga
response.close() response.close()
// Better error message for invalid artist // Better error message for invalid artist
if (response.code() == 404 && if (response.code() == 404 &&
!filters.findInstance<ArtistFilter>()?.state.isNullOrBlank()) !filters.findInstance<ArtistFilter>()?.state.isNullOrBlank()
)
error("Invalid artist!") error("Invalid artist!")
else throw Exception("HTTP error ${response.code()}") else throw Exception("HTTP error ${response.code()}")
} }
@ -145,192 +146,195 @@ 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("", "<select>"), "Tag",
Tag("ahegao", "Ahegao"), arrayOf(
Tag("anal", "Anal"), Tag("", "<select>"),
Tag("apron", "Apron"), Tag("ahegao", "Ahegao"),
Tag("ashioki", "Ashioki"), Tag("anal", "Anal"),
Tag("bakunyuu", "Bakunyuu"), Tag("apron", "Apron"),
Tag("bathroom-sex", "Bathroom sex"), Tag("ashioki", "Ashioki"),
Tag("beauty-mark", "Beauty mark"), Tag("bakunyuu", "Bakunyuu"),
Tag("big-ass", "Big ass"), Tag("bathroom-sex", "Bathroom sex"),
Tag("big-breast", "Big breast"), Tag("beauty-mark", "Beauty mark"),
Tag("big-dick", "Big dick"), Tag("big-ass", "Big ass"),
Tag("biting", "Biting"), Tag("big-breast", "Big breast"),
Tag("black-mail", "Blackmail"), Tag("big-dick", "Big dick"),
Tag("blindfold", "Blindfold"), Tag("biting", "Biting"),
Tag("blowjob", "Blowjob"), Tag("black-mail", "Blackmail"),
Tag("body-swap", "Body swap"), Tag("blindfold", "Blindfold"),
Tag("bondage", "Bondage"), Tag("blowjob", "Blowjob"),
Tag("booty", "Booty"), Tag("body-swap", "Body swap"),
Tag("bride", "Bride"), Tag("bondage", "Bondage"),
Tag("bukkake", "Bukkake"), Tag("booty", "Booty"),
Tag("bunny-girl", "Bunny girl"), Tag("bride", "Bride"),
Tag("busty", "Busty"), Tag("bukkake", "Bukkake"),
Tag("cat", "Cat"), Tag("bunny-girl", "Bunny girl"),
Tag("cat-girl", "Cat girl"), Tag("busty", "Busty"),
Tag("catgirl", "Catgirl"), Tag("cat", "Cat"),
Tag("cheating", "Cheating"), Tag("cat-girl", "Cat girl"),
Tag("cheerleader", "Cheerleader"), Tag("catgirl", "Catgirl"),
Tag("chikan", "Chikan"), Tag("cheating", "Cheating"),
Tag("christmas", "Christmas"), Tag("cheerleader", "Cheerleader"),
Tag("chubby", "Chubby"), Tag("chikan", "Chikan"),
Tag("color", "Color"), Tag("christmas", "Christmas"),
Tag("comedy", "Comedy"), Tag("chubby", "Chubby"),
Tag("condom", "Condom"), Tag("color", "Color"),
Tag("cosplay", "Cosplay"), Tag("comedy", "Comedy"),
Tag("creampie", "Creampie"), Tag("condom", "Condom"),
Tag("crossdressing", "Crossdressing"), Tag("cosplay", "Cosplay"),
Tag("crotch-tattoo", "Crotch tattoo"), Tag("creampie", "Creampie"),
Tag("cunnilingus", "Cunnilingus"), Tag("crossdressing", "Crossdressing"),
Tag("dark-skin", "Dark skin"), Tag("crotch-tattoo", "Crotch tattoo"),
Tag("deepthroat", "Deepthroat"), Tag("cunnilingus", "Cunnilingus"),
Tag("defloration", "Defloration"), Tag("dark-skin", "Dark skin"),
Tag("devil", "Devil"), Tag("deepthroat", "Deepthroat"),
Tag("double-penetration", "Double penetration"), Tag("defloration", "Defloration"),
Tag("doujin", "Doujin"), Tag("devil", "Devil"),
Tag("doujinshi", "Doujinshi"), Tag("double-penetration", "Double penetration"),
Tag("drama", "Drama"), Tag("doujin", "Doujin"),
Tag("drug", "Drug"), Tag("doujinshi", "Doujinshi"),
Tag("drunk", "Drunk"), Tag("drama", "Drama"),
Tag("elf", "Elf"), Tag("drug", "Drug"),
Tag("exhibitionism", "Exhibitionism"), Tag("drunk", "Drunk"),
Tag("eyebrows", "Eyebrows"), Tag("elf", "Elf"),
Tag("eyepatch", "Eyepatch"), Tag("exhibitionism", "Exhibitionism"),
Tag("facesitting", "Facesitting"), Tag("eyebrows", "Eyebrows"),
Tag("fangs", "Fangs"), Tag("eyepatch", "Eyepatch"),
Tag("fantasy", "Fantasy"), Tag("facesitting", "Facesitting"),
Tag("fellatio", "Fellatio"), Tag("fangs", "Fangs"),
Tag("femboy", "Femboy"), Tag("fantasy", "Fantasy"),
Tag("femdom", "Femdom"), Tag("fellatio", "Fellatio"),
Tag("filming", "Filming"), Tag("femboy", "Femboy"),
Tag("flat-chest", "Flat chest"), Tag("femdom", "Femdom"),
Tag("footjob", "Footjob"), Tag("filming", "Filming"),
Tag("freckles", "Freckles"), Tag("flat-chest", "Flat chest"),
Tag("full-color", "Full color"), Tag("footjob", "Footjob"),
Tag("furry", "Furry"), Tag("freckles", "Freckles"),
Tag("futanari", "Futanari"), Tag("full-color", "Full color"),
Tag("gangbang", "Gangbang"), Tag("furry", "Furry"),
Tag("gender-bender", "Gender bender"), Tag("futanari", "Futanari"),
Tag("genderbend", "Genderbend"), Tag("gangbang", "Gangbang"),
Tag("girls4m", "Girls4m"), Tag("gender-bender", "Gender bender"),
Tag("glasses", "Glasses"), Tag("genderbend", "Genderbend"),
Tag("group", "Group"), Tag("girls4m", "Girls4m"),
Tag("gyaru", "Gyaru"), Tag("glasses", "Glasses"),
Tag("hairy", "Hairy"), Tag("group", "Group"),
Tag("hairy-armpit", "Hairy armpit"), Tag("gyaru", "Gyaru"),
Tag("handjob", "Handjob"), Tag("hairy", "Hairy"),
Tag("harem", "Harem"), Tag("hairy-armpit", "Hairy armpit"),
Tag("headphones", "Headphones"), Tag("handjob", "Handjob"),
Tag("heart-pupils", "Heart pupils"), Tag("harem", "Harem"),
Tag("hentai", "Hentai"), Tag("headphones", "Headphones"),
Tag("historical", "Historical"), Tag("heart-pupils", "Heart pupils"),
Tag("horns", "Horns"), Tag("hentai", "Hentai"),
Tag("horror", "Horror"), Tag("historical", "Historical"),
Tag("housewife", "Housewife"), Tag("horns", "Horns"),
Tag("huge-boobs", "Huge-boobs"), Tag("horror", "Horror"),
Tag("humiliation", "Humiliation"), Tag("housewife", "Housewife"),
Tag("idol", "Idol"), Tag("huge-boobs", "Huge-boobs"),
Tag("imouto", "Imouto"), Tag("humiliation", "Humiliation"),
Tag("impregnation", "Impregnation"), Tag("idol", "Idol"),
Tag("incest", "Incest"), Tag("imouto", "Imouto"),
Tag("inseki", "Inseki"), Tag("impregnation", "Impregnation"),
Tag("inverted-nipples", "Inverted nipples"), Tag("incest", "Incest"),
Tag("irrumatio", "Irrumatio"), Tag("inseki", "Inseki"),
Tag("isekai", "Isekai"), Tag("inverted-nipples", "Inverted nipples"),
Tag("kemono-mimi", "Kemono mimi"), Tag("irrumatio", "Irrumatio"),
Tag("kimono", "Kimono"), Tag("isekai", "Isekai"),
Tag("kogal", "Kogal"), Tag("kemono-mimi", "Kemono mimi"),
Tag("lactation", "Lactation"), Tag("kimono", "Kimono"),
Tag("large-breast", "Large breast"), Tag("kogal", "Kogal"),
Tag("lingerie", "Lingerie"), Tag("lactation", "Lactation"),
Tag("loli", "Loli"), Tag("large-breast", "Large breast"),
Tag("love-hotel", "Love hotel"), Tag("lingerie", "Lingerie"),
Tag("magical-girl", "Magical girl"), Tag("loli", "Loli"),
Tag("maid", "Maid"), Tag("love-hotel", "Love hotel"),
Tag("masturbation", "Masturbation"), Tag("magical-girl", "Magical girl"),
Tag("miko", "Miko"), Tag("maid", "Maid"),
Tag("milf", "Milf"), Tag("masturbation", "Masturbation"),
Tag("mind-break", "Mind break"), Tag("miko", "Miko"),
Tag("mind-control", "Mind control"), Tag("milf", "Milf"),
Tag("monster-girl", "Monster girl"), Tag("mind-break", "Mind break"),
Tag("muscles", "Muscles"), Tag("mind-control", "Mind control"),
Tag("nakadashi", "Nakadashi"), Tag("monster-girl", "Monster girl"),
Tag("naked-apron", "Naked apron"), Tag("muscles", "Muscles"),
Tag("netorare", "Netorare"), Tag("nakadashi", "Nakadashi"),
Tag("netorase", "Netorase"), Tag("naked-apron", "Naked apron"),
Tag("netori", "Netori"), Tag("netorare", "Netorare"),
Tag("ninja", "Ninja"), Tag("netorase", "Netorase"),
Tag("nun", "Nun"), Tag("netori", "Netori"),
Tag("nurse", "Nurse"), Tag("ninja", "Ninja"),
Tag("office-lady", "Office lady"), Tag("nun", "Nun"),
Tag("ojousama", "Ojousama"), Tag("nurse", "Nurse"),
Tag("old-man", "Old man"), Tag("office-lady", "Office lady"),
Tag("onani", "Onani"), Tag("ojousama", "Ojousama"),
Tag("oni", "Oni"), Tag("old-man", "Old man"),
Tag("orgasm-denial", "Orgasm denial"), Tag("onani", "Onani"),
Tag("osananajimi", "Osananajimi"), Tag("oni", "Oni"),
Tag("pailoli", "Pailoli"), Tag("orgasm-denial", "Orgasm denial"),
Tag("paizuri", "Paizuri"), Tag("osananajimi", "Osananajimi"),
Tag("pegging", "Pegging"), Tag("pailoli", "Pailoli"),
Tag("petite", "Petite"), Tag("paizuri", "Paizuri"),
Tag("pettanko", "Pettanko"), Tag("pegging", "Pegging"),
Tag("ponytail", "Ponytail"), Tag("petite", "Petite"),
Tag("pregnant", "Pregnant"), Tag("pettanko", "Pettanko"),
Tag("prositution", "Prositution"), Tag("ponytail", "Ponytail"),
Tag("pubic-hair", "Pubic Hair"), Tag("pregnant", "Pregnant"),
Tag("qipao", "Qipao"), Tag("prositution", "Prositution"),
Tag("rape", "Rape"), Tag("pubic-hair", "Pubic Hair"),
Tag("reverse-rape", "Reverse rape"), Tag("qipao", "Qipao"),
Tag("rimjob", "Rimjob"), Tag("rape", "Rape"),
Tag("schoolgirl", "Schoolgirl"), Tag("reverse-rape", "Reverse rape"),
Tag("schoolgirl-outfit", "Schoolgirl outfit"), Tag("rimjob", "Rimjob"),
Tag("sci-fi", "Sci-fi"), Tag("schoolgirl", "Schoolgirl"),
Tag("senpai", "Senpai"), Tag("schoolgirl-outfit", "Schoolgirl outfit"),
Tag("sex", "Sex"), Tag("sci-fi", "Sci-fi"),
Tag("sex-toys", "Sex toys"), Tag("senpai", "Senpai"),
Tag("shimapan", "Shimapan"), Tag("sex", "Sex"),
Tag("shota", "Shota"), Tag("sex-toys", "Sex toys"),
Tag("shouta", "Shouta"), Tag("shimapan", "Shimapan"),
Tag("sister", "Sister"), Tag("shota", "Shota"),
Tag("sleeping", "Sleeping"), Tag("shouta", "Shouta"),
Tag("small-breast", "Small breast"), Tag("sister", "Sister"),
Tag("socks", "Socks"), Tag("sleeping", "Sleeping"),
Tag("spats", "Spats"), Tag("small-breast", "Small breast"),
Tag("spread", "Spread"), Tag("socks", "Socks"),
Tag("squirting", "Squirting"), Tag("spats", "Spats"),
Tag("stocking", "Stocking"), Tag("spread", "Spread"),
Tag("stockings", "Stockings"), Tag("squirting", "Squirting"),
Tag("succubus", "Succubus"), Tag("stocking", "Stocking"),
Tag("swimsuit", "Swimsuit"), Tag("stockings", "Stockings"),
Tag("swinging", "Swinging"), Tag("succubus", "Succubus"),
Tag("tall-girl", "Tall-girl"), Tag("swimsuit", "Swimsuit"),
Tag("tanlines", "Tanlines"), Tag("swinging", "Swinging"),
Tag("teacher", "Teacher"), Tag("tall-girl", "Tall-girl"),
Tag("tentacles", "Tentacles"), Tag("tanlines", "Tanlines"),
Tag("threesome", "Threesome"), Tag("teacher", "Teacher"),
Tag("time-stop", "Time stop"), Tag("tentacles", "Tentacles"),
Tag("tomboy", "Tomboy"), Tag("threesome", "Threesome"),
Tag("toys", "Toys"), Tag("time-stop", "Time stop"),
Tag("trans", "Trans"), Tag("tomboy", "Tomboy"),
Tag("tsundere", "Tsundere"), Tag("toys", "Toys"),
Tag("twin", "Twin"), Tag("trans", "Trans"),
Tag("twintails", "Twintails"), Tag("tsundere", "Tsundere"),
Tag("ugly-bastard", "Ugly bastard"), Tag("twin", "Twin"),
Tag("uncensored", "Uncensored"), Tag("twintails", "Twintails"),
Tag("unlimited", "Unlimited"), Tag("ugly-bastard", "Ugly bastard"),
Tag("urination", "Urination"), Tag("uncensored", "Uncensored"),
Tag("vanilla", "Vanilla"), Tag("unlimited", "Unlimited"),
Tag("virgin", "Virgin"), Tag("urination", "Urination"),
Tag("vomit", "Vomit"), Tag("vanilla", "Vanilla"),
Tag("voyeurism", "Voyeurism"), Tag("virgin", "Virgin"),
Tag("waitress", "Waitress"), Tag("vomit", "Vomit"),
Tag("x-ray", "X-Ray"), Tag("voyeurism", "Voyeurism"),
Tag("yandere", "Yandere"), Tag("waitress", "Waitress"),
Tag("yukata", "Yukata"), Tag("x-ray", "X-Ray"),
Tag("yuri", "Yuri") Tag("yandere", "Yandere"),
)) Tag("yukata", "Yukata"),
Tag("yuri", "Yuri")
)
)
class Tag(val name: String, private val displayName: String) { class Tag(val name: String, private val displayName: String) {
override fun toString() = displayName override fun toString() = displayName

View File

@ -8,15 +8,15 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
abstract class Genkan( abstract class Genkan(
override val name: String, override val name: String,

View File

@ -4,8 +4,6 @@ import android.app.Application
import android.content.SharedPreferences import android.content.SharedPreferences
import android.support.v7.preference.CheckBoxPreference import android.support.v7.preference.CheckBoxPreference
import android.support.v7.preference.PreferenceScreen import android.support.v7.preference.PreferenceScreen
import androidx.preference.CheckBoxPreference as AndroidXCheckBoxPreference
import androidx.preference.PreferenceScreen as AndroidXPreferenceScreen
import com.github.salomonbrys.kotson.array import com.github.salomonbrys.kotson.array
import com.github.salomonbrys.kotson.get import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.string import com.github.salomonbrys.kotson.string
@ -28,6 +26,8 @@ import rx.Single
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import androidx.preference.CheckBoxPreference as AndroidXCheckBoxPreference
import androidx.preference.PreferenceScreen as AndroidXPreferenceScreen
/** /**
* Ported from TachiyomiSy * Ported from TachiyomiSy
@ -190,13 +190,13 @@ open class Hitomi(override val lang: String, private val nozomiLang: String) : H
} }
} }
return base.flatMap { (_, ids) -> return base.flatMap { (_, ids) ->
val chunks = ids.chunked(PAGE_SIZE) val chunks = ids.chunked(PAGE_SIZE)
nozomiIdsToMangas(chunks[page - 1]).map { mangas -> nozomiIdsToMangas(chunks[page - 1]).map { mangas ->
MangasPage(mangas, page < chunks.size) MangasPage(mangas, page < chunks.size)
} }
}.toObservable() }.toObservable()
} }
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException("Not used") override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = throw UnsupportedOperationException("Not used")

View File

@ -4,12 +4,12 @@ import eu.kanade.tachiyomi.extension.all.hitomi.Hitomi.Companion.LTN_BASE_URL
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservable import eu.kanade.tachiyomi.network.asObservable
import eu.kanade.tachiyomi.network.asObservableSuccess import eu.kanade.tachiyomi.network.asObservableSuccess
import java.security.MessageDigest
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import rx.Observable import rx.Observable
import rx.Single import rx.Single
import java.security.MessageDigest
private typealias HashedTerm = ByteArray private typealias HashedTerm = ByteArray

View File

@ -24,9 +24,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import okhttp3.Credentials import okhttp3.Credentials
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
@ -38,6 +35,9 @@ import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() { open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
override fun popularMangaRequest(page: Int): Request = override fun popularMangaRequest(page: Int): Request =
@ -215,8 +215,10 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
else -> SManga.UNKNOWN else -> SManga.UNKNOWN
} }
// TODO: remove safe calls in next iteration // TODO: remove safe calls in next iteration
genre = (metadata.genres?.plus(metadata.tags ?: emptySet()) genre = (
?: emptySet()).joinToString(", ") metadata.genres?.plus(metadata.tags ?: emptySet())
?: emptySet()
).joinToString(", ")
description = metadata.summary description = metadata.summary
} }
@ -225,10 +227,10 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
Date().time Date().time
else { else {
try { try {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US).parse(date).time SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.US).parse(date)?.time ?: 0L
} catch (ex: Exception) { } catch (ex: Exception) {
try { try {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S", Locale.US).parse(date).time SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.S", Locale.US).parse(date)?.time ?: 0L
} catch (ex: Exception) { } catch (ex: Exception) {
Date().time Date().time
} }
@ -370,65 +372,80 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ response -> .subscribe(
libraries = try { { response ->
gson.fromJson(response.body()?.charStream()!!) libraries = try {
} catch (e: Exception) { gson.fromJson(response.body()?.charStream()!!)
emptyList() } catch (e: Exception) {
} emptyList()
}, {}) }
},
{}
)
Single.fromCallable { Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/collections?unpaged=true", headers)).execute() client.newCall(GET("$baseUrl/api/v1/collections?unpaged=true", headers)).execute()
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ response -> .subscribe(
collections = try { { response ->
gson.fromJson<PageWrapperDto<CollectionDto>>(response.body()?.charStream()!!).content collections = try {
} catch (e: Exception) { gson.fromJson<PageWrapperDto<CollectionDto>>(response.body()?.charStream()!!).content
emptyList() } catch (e: Exception) {
} emptyList()
}, {}) }
},
{}
)
Single.fromCallable { Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/genres", headers)).execute() client.newCall(GET("$baseUrl/api/v1/genres", headers)).execute()
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ response -> .subscribe(
genres = try { { response ->
gson.fromJson(response.body()?.charStream()!!) genres = try {
} catch (e: Exception) { gson.fromJson(response.body()?.charStream()!!)
emptySet() } catch (e: Exception) {
} emptySet()
}, {}) }
},
{}
)
Single.fromCallable { Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute() client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute()
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ response -> .subscribe(
tags = try { { response ->
gson.fromJson(response.body()?.charStream()!!) tags = try {
} catch (e: Exception) { gson.fromJson(response.body()?.charStream()!!)
emptySet() } catch (e: Exception) {
} emptySet()
}, {}) }
},
{}
)
Single.fromCallable { Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute() client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute()
} }
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe({ response -> .subscribe(
publishers = try { { response ->
gson.fromJson(response.body()?.charStream()!!) publishers = try {
} catch (e: Exception) { gson.fromJson(response.body()?.charStream()!!)
emptySet() } catch (e: Exception) {
} emptySet()
}, {}) }
},
{}
)
} }
companion object { companion object {

View File

@ -59,7 +59,8 @@ open class LANraragi : ConfigurableSource, HttpSource() {
url = "${uriBuild.encodedPath}?${uriBuild.encodedQuery}" url = "${uriBuild.encodedPath}?${uriBuild.encodedQuery}"
chapter_number = 1F chapter_number = 1F
name = "Chapter" name = "Chapter"
}) }
)
} }
override fun pageListParse(response: Response): List<Page> { override fun pageListParse(response: Response): List<Page> {
@ -118,7 +119,9 @@ open class LANraragi : ConfigurableSource, HttpSource() {
artist = getArtist(it.tags) artist = getArtist(it.tags)
author = artist author = artist
} }
}, currentStart + jsonResult.data.size < jsonResult.recordsFiltered) },
currentStart + jsonResult.data.size < jsonResult.recordsFiltered
)
} }
// Preferences // Preferences

View File

@ -11,13 +11,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import kotlin.math.absoluteValue
import kotlin.random.Random
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
@ -29,6 +22,13 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import kotlin.math.absoluteValue
import kotlin.random.Random
abstract class Madara( abstract class Madara(
override val name: String, override val name: String,
@ -189,19 +189,25 @@ abstract class Madara(
private class ArtistFilter : Filter.Text("Artist") private class ArtistFilter : Filter.Text("Artist")
private class YearFilter : Filter.Text("Year of Released") private class YearFilter : Filter.Text("Year of Released")
private class StatusFilter(status: List<Tag>) : Filter.Group<Tag>("Status", status) private class StatusFilter(status: List<Tag>) : Filter.Group<Tag>("Status", status)
private class OrderByFilter : UriPartFilter("Order By", arrayOf( private class OrderByFilter : UriPartFilter(
Pair("<select>", ""), "Order By",
Pair("Latest", "latest"), arrayOf(
Pair("A-Z", "alphabet"), Pair("<select>", ""),
Pair("Rating", "rating"), Pair("Latest", "latest"),
Pair("Trending", "trending"), Pair("A-Z", "alphabet"),
Pair("Most Views", "views"), Pair("Rating", "rating"),
Pair("New", "new-manga") Pair("Trending", "trending"),
)) Pair("Most Views", "views"),
private class GenreConditionFilter : UriPartFilter("Genre condition", arrayOf( Pair("New", "new-manga")
Pair("or", ""), )
Pair("and", "1") )
)) private class GenreConditionFilter : UriPartFilter(
"Genre condition",
arrayOf(
Pair("or", ""),
Pair("and", "1")
)
)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
class Genre(name: String, val id: String = name) : Filter.CheckBox(name) class Genre(name: String, val id: String = name) : Filter.CheckBox(name)
@ -385,7 +391,7 @@ abstract class Madara(
.let { elements -> .let { elements ->
if (elements.isEmpty() && !document.select(dataIdSelector).isNullOrEmpty()) if (elements.isEmpty() && !document.select(dataIdSelector).isNullOrEmpty())
getXhrChapters(document.select(dataIdSelector).attr("data-id")).select(chapterListSelector()) getXhrChapters(document.select(dataIdSelector).attr("data-id")).select(chapterListSelector())
else elements else elements
} }
.map { chapterFromElement(it) } .map { chapterFromElement(it) }
} }
@ -491,9 +497,13 @@ abstract class Madara(
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
return document.select(pageListParseSelector).mapIndexed { index, element -> return document.select(pageListParseSelector).mapIndexed { index, element ->
Page(index, document.location(), element.select("img").first()?.let { Page(
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src") index,
}) document.location(),
element.select("img").first()?.let {
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
}
)
} }
} }

View File

@ -12,8 +12,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.Headers import okhttp3.Headers
@ -23,6 +21,8 @@ import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MadaraFactory : SourceFactory { class MadaraFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(
@ -197,13 +197,21 @@ class MangaRawr : Madara("MangaRawr", "https://mangarawr.com", "en")
class NinjaScans : Madara("NinjaScans", "https://ninjascans.com", "en") class NinjaScans : Madara("NinjaScans", "https://ninjascans.com", "en")
class ReadManhua : Madara("ReadManhua", "https://readmanhua.net", "en", class ReadManhua : Madara(
dateFormat = SimpleDateFormat("dd MMM yy", Locale.US)) "ReadManhua",
"https://readmanhua.net",
"en",
dateFormat = SimpleDateFormat("dd MMM yy", Locale.US)
)
class IsekaiScanCom : Madara("IsekaiScan.com", "https://isekaiscan.com", "en") class IsekaiScanCom : Madara("IsekaiScan.com", "https://isekaiscan.com", "en")
class JustForFun : Madara("Just For Fun", "https://just-for-fun.ru", "ru", class JustForFun : Madara(
dateFormat = SimpleDateFormat("yy.MM.dd", Locale.US)) "Just For Fun",
"https://just-for-fun.ru",
"ru",
dateFormat = SimpleDateFormat("yy.MM.dd", Locale.US)
)
class AoCTranslations : Madara("Agent of Change Translations", "https://aoc.moe", "en") { class AoCTranslations : Madara("Agent of Change Translations", "https://aoc.moe", "en") {
override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl) override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl)
@ -243,11 +251,19 @@ class KomikGo : Madara("KomikGo", "https://komikgo.com", "id")
class LuxyScans : Madara("Luxy Scans", "https://luxyscans.com", "en") class LuxyScans : Madara("Luxy Scans", "https://luxyscans.com", "en")
class TsubakiNoScan : Madara("Tsubaki No Scan", "https://tsubakinoscan.com", "fr", class TsubakiNoScan : Madara(
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)) "Tsubaki No Scan",
"https://tsubakinoscan.com",
"fr",
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)
)
class YokaiJump : Madara("Yokai Jump", "https://yokaijump.fr", "fr", class YokaiJump : Madara(
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)) "Yokai Jump",
"https://yokaijump.fr",
"fr",
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)
)
class ZManga : Madara("ZManga", "https://zmanga.org", "es") class ZManga : Madara("ZManga", "https://zmanga.org", "es")
@ -261,8 +277,12 @@ class MangazukiClubJP : Madara("Mangazuki.club", "https://mangazuki.club", "ja")
class MangazukiClubKO : Madara("Mangazuki.club", "https://mangazuki.club", "ko") class MangazukiClubKO : Madara("Mangazuki.club", "https://mangazuki.club", "ko")
class FirstKissManga : Madara("1st Kiss", "https://1stkissmanga.com", "en", class FirstKissManga : Madara(
dateFormat = SimpleDateFormat("dd MMM yyyy", Locale.US)) { "1st Kiss",
"https://1stkissmanga.com",
"en",
dateFormat = SimpleDateFormat("dd MMM yyyy", Locale.US)
) {
override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl) override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl)
} }
@ -287,8 +307,12 @@ class ManyToonMe : Madara("ManyToon.me", "https://manytoon.me", "en")
class BoysLove : Madara("BoysLove", "https://boyslove.me", "en") class BoysLove : Madara("BoysLove", "https://boyslove.me", "en")
class ChibiManga : Madara("Chibi Manga", "http://www.cmreader.info", "en", class ChibiManga : Madara(
dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)) { "Chibi Manga",
"http://www.cmreader.info",
"en",
dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)
) {
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
response.asJsoup().let { documet -> response.asJsoup().let { documet ->
documet.select("li.parent.has-child").let { volumes -> documet.select("li.parent.has-child").let { volumes ->
@ -562,41 +586,43 @@ class DoujinHentai : Madara("DoujinHentai", "https://doujinhentai.net", "es", Si
GenreSelectFilter() GenreSelectFilter()
) )
class GenreSelectFilter : UriPartFilter("Búsqueda de género", arrayOf( class GenreSelectFilter : UriPartFilter(
Pair("<seleccionar>", ""), "Búsqueda de género",
Pair("Ecchi", "ecchi"), arrayOf(
Pair("Yaoi", "yaoi"), Pair("<seleccionar>", ""),
Pair("Yuri", "yuri"), Pair("Ecchi", "ecchi"),
Pair("Anal", "anal"), Pair("Yaoi", "yaoi"),
Pair("Tetonas", "tetonas"), Pair("Yuri", "yuri"),
Pair("Escolares", "escolares"), Pair("Anal", "anal"),
Pair("Incesto", "incesto"), Pair("Tetonas", "tetonas"),
Pair("Virgenes", "virgenes"), Pair("Escolares", "escolares"),
Pair("Masturbacion", "masturbacion"), Pair("Incesto", "incesto"),
Pair("Maduras", "maduras"), Pair("Virgenes", "virgenes"),
Pair("Lolicon", "lolicon"), Pair("Masturbacion", "masturbacion"),
Pair("Bikini", "bikini"), Pair("Maduras", "maduras"),
Pair("Sirvientas", "sirvientas"), Pair("Lolicon", "lolicon"),
Pair("Enfermera", "enfermera"), Pair("Bikini", "bikini"),
Pair("Embarazada", "embarazada"), Pair("Sirvientas", "sirvientas"),
Pair("Ahegao", "ahegao"), Pair("Enfermera", "enfermera"),
Pair("Casadas", "casadas"), Pair("Embarazada", "embarazada"),
Pair("Chica Con Pene", "chica-con-pene"), Pair("Ahegao", "ahegao"),
Pair("Juguetes Sexuales", "juguetes-sexuales"), Pair("Casadas", "casadas"),
Pair("Orgias", "orgias"), Pair("Chica Con Pene", "chica-con-pene"),
Pair("Harem", "harem"), Pair("Juguetes Sexuales", "juguetes-sexuales"),
Pair("Romance", "romance"), Pair("Orgias", "orgias"),
Pair("Profesores", "profesores"), Pair("Harem", "harem"),
Pair("Tentaculos", "tentaculos"), Pair("Romance", "romance"),
Pair("Mamadas", "mamadas"), Pair("Profesores", "profesores"),
Pair("Shota", "shota"), Pair("Tentaculos", "tentaculos"),
Pair("Interracial", "interracial"), Pair("Mamadas", "mamadas"),
Pair("Full Color", "full-colo"), Pair("Shota", "shota"),
Pair("Sin Censura", "sin-censura"), Pair("Interracial", "interracial"),
Pair("Futanari", "futanari"), Pair("Full Color", "full-colo"),
Pair("Doble Penetracion", "doble-penetracion"), Pair("Sin Censura", "sin-censura"),
Pair("Cosplay", "cosplay") Pair("Futanari", "futanari"),
) Pair("Doble Penetracion", "doble-penetracion"),
Pair("Cosplay", "cosplay")
)
) )
} }

View File

@ -9,11 +9,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -21,6 +16,11 @@ import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
// Based off of Mangakakalot 1.2.8 // Based off of Mangakakalot 1.2.8

View File

@ -7,12 +7,12 @@ import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaBoxFactory : SourceFactory { class MangaBoxFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(

View File

@ -28,10 +28,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.net.URLEncoder
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.collections.set
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
@ -45,6 +41,10 @@ import org.jsoup.parser.Parser
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.net.URLEncoder
import java.util.Date
import java.util.concurrent.TimeUnit
import kotlin.collections.set
abstract class MangaDex( abstract class MangaDex(
override val lang: String, override val lang: String,
@ -421,7 +421,8 @@ abstract class MangaDex(
// Remove bbcode tags as well as parses any html characters in description or chapter name to actual characters for example &hearts; will show ♥ // Remove bbcode tags as well as parses any html characters in description or chapter name to actual characters for example &hearts; will show ♥
private fun cleanString(string: String): String { private fun cleanString(string: String): String {
val bbRegex = """\[(\w+)[^]]*](.*?)\[/\1]""".toRegex() val bbRegex =
"""\[(\w+)[^]]*](.*?)\[/\1]""".toRegex()
var intermediate = string var intermediate = string
.replace("[list]", "") .replace("[list]", "")
.replace("[/list]", "") .replace("[/list]", "")
@ -801,9 +802,11 @@ abstract class MangaDex(
private class TagExclusionMode : Filter.Select<String>("Tag exclusion mode", arrayOf("All (and)", "Any (or)"), 1) private class TagExclusionMode : Filter.Select<String>("Tag exclusion mode", arrayOf("All (and)", "Any (or)"), 1)
// default selection (Rating Descending) matches popularMangaRequest url // default selection (Rating Descending) matches popularMangaRequest url
class SortFilter : Filter.Sort("Sort", class SortFilter : Filter.Sort(
"Sort",
sortables.map { it.first }.toTypedArray(), sortables.map { it.first }.toTypedArray(),
Selection(3, false)) Selection(3, false)
)
private class OriginalLanguage : Filter.Select<String>("Original Language", SOURCE_LANG_LIST.map { it.first }.toTypedArray()) private class OriginalLanguage : Filter.Select<String>("Original Language", SOURCE_LANG_LIST.map { it.first }.toTypedArray())
@ -955,7 +958,8 @@ abstract class MangaDex(
Triple("Number of comments", 4, 5), Triple("Number of comments", 4, 5),
Triple("Rating", 6, 7), Triple("Rating", 6, 7),
Triple("Views", 8, 9), Triple("Views", 8, 9),
Triple("Follows", 10, 11)) Triple("Follows", 10, 11)
)
private val SOURCE_LANG_LIST = listOf( private val SOURCE_LANG_LIST = listOf(
Pair("All", "0"), Pair("All", "0"),
@ -970,7 +974,8 @@ abstract class MangaDex(
Pair("Korean", "28"), Pair("Korean", "28"),
Pair("Spanish (LATAM)", "29"), Pair("Spanish (LATAM)", "29"),
Pair("Thai", "32"), Pair("Thai", "32"),
Pair("Filipino", "34")) Pair("Filipino", "34")
)
private var hasMangaPlus = false private var hasMangaPlus = false
} }

View File

@ -12,14 +12,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
/** /**
* MangAdventure base source. * MangAdventure base source.
@ -88,9 +88,11 @@ abstract class MangAdventure(
when (it) { when (it) {
is Person -> uri.appendQueryParameter("author", it.state) is Person -> uri.appendQueryParameter("author", it.state)
is Status -> uri.appendQueryParameter("status", it.string()) is Status -> uri.appendQueryParameter("status", it.string())
is CategoryList -> cat.addAll(it.state.mapNotNull { c -> is CategoryList -> cat.addAll(
Uri.encode(c.optString()) it.state.mapNotNull { c ->
}) Uri.encode(c.optString())
}
)
else -> Unit else -> Unit
} }
} }
@ -99,18 +101,21 @@ abstract class MangAdventure(
override fun latestUpdatesParse(response: Response) = override fun latestUpdatesParse(response: Response) =
JSONArray(response.asString()).run { JSONArray(response.asString()).run {
MangasPage((0 until length()).map { MangasPage(
val obj = getJSONObject(it) (0 until length()).map {
SManga.create().apply { val obj = getJSONObject(it)
url = obj.getString("url") SManga.create().apply {
title = obj.getString("title") url = obj.getString("url")
thumbnail_url = obj.getString("cover") title = obj.getString("title")
// A bit of a hack to sort by date thumbnail_url = obj.getString("cover")
description = httpDateToTimestamp( // A bit of a hack to sort by date
obj.getJSONObject("latest_chapter").getString("date") description = httpDateToTimestamp(
).toString() obj.getJSONObject("latest_chapter").getString("date")
} ).toString()
}.sortedByDescending(SManga::description), false) }
}.sortedByDescending(SManga::description),
false
)
} }
override fun chapterListParse(response: Response) = override fun chapterListParse(response: Response) =
@ -143,9 +148,12 @@ abstract class MangAdventure(
override fun searchMangaParse(response: Response) = override fun searchMangaParse(response: Response) =
JSONArray(response.asString()).run { JSONArray(response.asString()).run {
MangasPage((0 until length()).map { MangasPage(
SManga.create().fromJSON(getJSONObject(it)) (0 until length()).map {
}.sortedBy(SManga::title), false) SManga.create().fromJSON(getJSONObject(it))
}.sortedBy(SManga::title),
false
)
} }
override fun getFilterList() = override fun getFilterList() =
@ -226,7 +234,7 @@ abstract class MangAdventure(
* @return The timestamp of the date. * @return The timestamp of the date.
*/ */
fun httpDateToTimestamp(date: String) = fun httpDateToTimestamp(date: String) =
SimpleDateFormat(HTTP_DATE, Locale.US).parse(date).time SimpleDateFormat(HTTP_DATE, Locale.US).parse(date)?.time ?: 0L
} }
/** /**
@ -260,7 +268,8 @@ abstract class MangAdventure(
* @constructor Creates a [Filter.Group] object with categories. * @constructor Creates a [Filter.Group] object with categories.
*/ */
inner class CategoryList : Filter.Group<Category>( inner class CategoryList : Filter.Group<Category>(
"Categories", categories.map(::Category) "Categories",
categories.map(::Category)
) )
/** /**

View File

@ -16,11 +16,13 @@ class MangAdventureActivity : Activity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
intent?.data?.pathSegments?.takeIf { it.size > 1 }?.let { intent?.data?.pathSegments?.takeIf { it.size > 1 }?.let {
try { try {
startActivity(Intent().apply { startActivity(
action = "eu.kanade.tachiyomi.SEARCH" Intent().apply {
putExtra("query", MangAdventure.SLUG_QUERY + it[1]) action = "eu.kanade.tachiyomi.SEARCH"
putExtra("filter", packageName) putExtra("query", MangAdventure.SLUG_QUERY + it[1])
}) putExtra("filter", packageName)
}
)
} catch (ex: ActivityNotFoundException) { } catch (ex: ActivityNotFoundException) {
Log.e("MangAdventureActivity", ex.message, ex) Log.e("MangAdventureActivity", ex.message, ex)
} }
@ -30,6 +32,7 @@ class MangAdventureActivity : Activity() {
} }
private fun logInvalidIntent(intent: Intent) = Log.e( private fun logInvalidIntent(intent: Intent) = Log.e(
"MangAdventureActivity", "Failed to parse URI from intent: $intent" "MangAdventureActivity",
"Failed to parse URI from intent: $intent"
) )
} }

View File

@ -3,10 +3,10 @@ package eu.kanade.tachiyomi.extension.all.mangadventure
import android.net.Uri import android.net.Uri
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import java.text.DecimalFormat
import okhttp3.Response import okhttp3.Response
import org.json.JSONArray import org.json.JSONArray
import org.json.JSONObject import org.json.JSONObject
import java.text.DecimalFormat
/** Returns the body of a response as a `String`. */ /** Returns the body of a response as a `String`. */
fun Response.asString(): String = body()!!.string() fun Response.asString(): String = body()!!.string()
@ -62,9 +62,9 @@ fun SManga.fromJSON(obj: JSONObject) = apply {
title = obj.getString("title") title = obj.getString("title")
description = obj.getString("description") description = obj.getString("description")
thumbnail_url = obj.getString("cover") thumbnail_url = obj.getString("cover")
author = obj.getJSONArray("authors")?.joinField(0) author = obj.getJSONArray("authors").joinField(0)
artist = obj.getJSONArray("artists")?.joinField(0) artist = obj.getJSONArray("artists").joinField(0)
genre = obj.getJSONArray("categories")?.joinField("name") genre = obj.getJSONArray("categories").joinField("name")
status = if (obj.getBoolean("completed")) status = if (obj.getBoolean("completed"))
SManga.COMPLETED else SManga.ONGOING SManga.COMPLETED else SManga.ONGOING
} }
@ -82,11 +82,14 @@ fun SChapter.fromJSON(obj: JSONObject) = apply {
url = obj.getString("url") url = obj.getString("url")
chapter_number = obj.optString("chapter", "0").toFloat() chapter_number = obj.optString("chapter", "0").toFloat()
date_upload = MangAdventure.httpDateToTimestamp(obj.getString("date")) date_upload = MangAdventure.httpDateToTimestamp(obj.getString("date"))
scanlator = obj.getJSONArray("groups")?.joinField("name", " & ") scanlator = obj.getJSONArray("groups").joinField("name", " & ")
name = obj.optString("full_title", buildString { name = obj.optString(
obj.optInt("volume").let { if (it != 0) append("Vol. $it, ") } "full_title",
append("Ch. ${chapter_number.format("#.#")}: ") buildString {
append(obj.getString("title")) obj.optInt("volume").let { if (it != 0) append("Vol. $it, ") }
}) append("Ch. ${chapter_number.format("#.#")}: ")
append(obj.getString("title"))
}
)
if (obj.getBoolean("final")) name += " [END]" if (obj.getBoolean("final")) name += " [END]"
} }

View File

@ -10,7 +10,9 @@ class MangAdventureFactory : SourceFactory {
/** Arc-Relight source. */ /** Arc-Relight source. */
class ArcRelight : MangAdventure( class ArcRelight : MangAdventure(
"Arc-Relight", "https://arc-relight.com", arrayOf( "Arc-Relight",
"https://arc-relight.com",
arrayOf(
"4-Koma", "4-Koma",
"Chaos;Head", "Chaos;Head",
"Collection", "Collection",

View File

@ -6,13 +6,14 @@ ext {
extName = 'MANGA Plus by SHUEISHA' extName = 'MANGA Plus by SHUEISHA'
pkgNameSuffix = 'all.mangaplus' pkgNameSuffix = 'all.mangaplus'
extClass = '.MangaPlusFactory' extClass = '.MangaPlusFactory'
extVersionCode = 11 extVersionCode = 12
libVersion = '1.2' libVersion = '1.2'
} }
dependencies { dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-protobuf:0.20.0' final serialization_version = '1.0.0-RC'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0' implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$serialization_version"
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -6,9 +6,6 @@ import android.os.Build
import android.support.v7.preference.CheckBoxPreference import android.support.v7.preference.CheckBoxPreference
import android.support.v7.preference.ListPreference import android.support.v7.preference.ListPreference
import android.support.v7.preference.PreferenceScreen import android.support.v7.preference.PreferenceScreen
import androidx.preference.CheckBoxPreference as AndroidXCheckBoxPreference
import androidx.preference.ListPreference as AndroidXListPreference
import androidx.preference.PreferenceScreen as AndroidXPreferenceScreen
import com.google.gson.Gson import com.google.gson.Gson
import com.squareup.duktape.Duktape import com.squareup.duktape.Duktape
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
@ -20,7 +17,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import java.util.UUID
import kotlinx.serialization.protobuf.ProtoBuf import kotlinx.serialization.protobuf.ProtoBuf
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
@ -33,6 +29,10 @@ import okhttp3.ResponseBody
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.util.UUID
import androidx.preference.CheckBoxPreference as AndroidXCheckBoxPreference
import androidx.preference.ListPreference as AndroidXListPreference
import androidx.preference.PreferenceScreen as AndroidXPreferenceScreen
abstract class MangaPlus( abstract class MangaPlus(
override val lang: String, override val lang: String,
@ -428,7 +428,7 @@ abstract class MangaPlus(
private fun Response.asProto(): MangaPlusResponse { private fun Response.asProto(): MangaPlusResponse {
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT)
return ProtoBuf.load(MangaPlusSerializer, body()!!.bytes()) return ProtoBuf.decodeFromByteArray(MangaPlusSerializer, body()!!.bytes())
// Apparently, the version used of Kotlinx Serialization lib causes a crash // Apparently, the version used of Kotlinx Serialization lib causes a crash
// on KitKat devices (see #1678). So, if the device is running KitKat or lower, // on KitKat devices (see #1678). So, if the device is running KitKat or lower,
@ -438,9 +438,13 @@ abstract class MangaPlus(
val messageBytes = "var BYTE_ARR = new Uint8Array([${bytes.joinToString()}]);" val messageBytes = "var BYTE_ARR = new Uint8Array([${bytes.joinToString()}]);"
val res = Duktape.create().use { val res = Duktape.create().use {
it.set("helper", DuktapeHelper::class.java, object : DuktapeHelper { it.set(
override fun getProtobuf(): String = protobufJs "helper",
}) DuktapeHelper::class.java,
object : DuktapeHelper {
override fun getProtobuf(): String = protobufJs
}
)
it.evaluate(messageBytes + DECODE_SCRIPT) as String it.evaluate(messageBytes + DECODE_SCRIPT) as String
} }

View File

@ -3,128 +3,129 @@ package eu.kanade.tachiyomi.extension.all.mangaplus
import com.google.gson.annotations.SerializedName import com.google.gson.annotations.SerializedName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer import kotlinx.serialization.Serializer
import kotlinx.serialization.protobuf.ProtoId import kotlinx.serialization.protobuf.ProtoNumber
@Serializer(forClass = MangaPlusResponse::class) @Serializer(forClass = MangaPlusResponse::class)
object MangaPlusSerializer object MangaPlusSerializer
@Serializable @Serializable
data class MangaPlusResponse( data class MangaPlusResponse(
@ProtoId(1) val success: SuccessResult? = null, @ProtoNumber(1) val success: SuccessResult? = null,
@ProtoId(2) val error: ErrorResult? = null @ProtoNumber(2) val error: ErrorResult? = null
) )
@Serializable @Serializable
data class ErrorResult( data class ErrorResult(
@ProtoId(1) val action: Action, @ProtoNumber(1) val action: Action,
@ProtoId(2) val englishPopup: Popup, @ProtoNumber(2) val englishPopup: Popup,
@ProtoId(3) val spanishPopup: Popup @ProtoNumber(3) val spanishPopup: Popup
) )
enum class Action { DEFAULT, UNAUTHORIZED, MAINTAINENCE, GEOIP_BLOCKING } enum class Action { DEFAULT, UNAUTHORIZED, MAINTAINENCE, GEOIP_BLOCKING }
@Serializable @Serializable
data class Popup( data class Popup(
@ProtoId(1) val subject: String, @ProtoNumber(1) val subject: String,
@ProtoId(2) val body: String @ProtoNumber(2) val body: String
) )
@Serializable @Serializable
data class SuccessResult( data class SuccessResult(
@ProtoId(1) val isFeaturedUpdated: Boolean? = false, @ProtoNumber(1) val isFeaturedUpdated: Boolean? = false,
@ProtoId(5) val allTitlesView: AllTitlesView? = null, @ProtoNumber(5) val allTitlesView: AllTitlesView? = null,
@ProtoId(6) val titleRankingView: TitleRankingView? = null, @ProtoNumber(6) val titleRankingView: TitleRankingView? = null,
@ProtoId(8) val titleDetailView: TitleDetailView? = null, @ProtoNumber(8) val titleDetailView: TitleDetailView? = null,
@ProtoId(10) val mangaViewer: MangaViewer? = null, @ProtoNumber(10) val mangaViewer: MangaViewer? = null,
@ProtoId(11) val webHomeView: WebHomeView? = null @ProtoNumber(11) val webHomeView: WebHomeView? = null
) )
@Serializable @Serializable
data class TitleRankingView(@ProtoId(1) val titles: List<Title> = emptyList()) data class TitleRankingView(@ProtoNumber(1) val titles: List<Title> = emptyList())
@Serializable @Serializable
data class AllTitlesView(@ProtoId(1) val titles: List<Title> = emptyList()) data class AllTitlesView(@ProtoNumber(1) val titles: List<Title> = emptyList())
@Serializable @Serializable
data class WebHomeView(@ProtoId(2) val groups: List<UpdatedTitleGroup> = emptyList()) data class WebHomeView(@ProtoNumber(2) val groups: List<UpdatedTitleGroup> = emptyList())
@Serializable @Serializable
data class TitleDetailView( data class TitleDetailView(
@ProtoId(1) val title: Title, @ProtoNumber(1) val title: Title,
@ProtoId(2) val titleImageUrl: String, @ProtoNumber(2) val titleImageUrl: String,
@ProtoId(3) val overview: String, @ProtoNumber(3) val overview: String,
@ProtoId(4) val backgroundImageUrl: String, @ProtoNumber(4) val backgroundImageUrl: String,
@ProtoId(5) val nextTimeStamp: Int = 0, @ProtoNumber(5) val nextTimeStamp: Int = 0,
@ProtoId(6) val updateTiming: UpdateTiming? = UpdateTiming.DAY, @ProtoNumber(6) val updateTiming: UpdateTiming? = UpdateTiming.DAY,
@ProtoId(7) val viewingPeriodDescription: String = "", @ProtoNumber(7) val viewingPeriodDescription: String = "",
@ProtoId(8) val nonAppearanceInfo: String = "", @ProtoNumber(8) val nonAppearanceInfo: String = "",
@ProtoId(9) val firstChapterList: List<Chapter> = emptyList(), @ProtoNumber(9) val firstChapterList: List<Chapter> = emptyList(),
@ProtoId(10) val lastChapterList: List<Chapter> = emptyList(), @ProtoNumber(10) val lastChapterList: List<Chapter> = emptyList(),
@ProtoId(14) val isSimulReleased: Boolean = true, @ProtoNumber(14) val isSimulReleased: Boolean = true,
@ProtoId(17) val chaptersDescending: Boolean = true @ProtoNumber(17) val chaptersDescending: Boolean = true
) )
enum class UpdateTiming { NOT_REGULARLY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY, DAY } enum class UpdateTiming { NOT_REGULARLY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY, DAY }
@Serializable @Serializable
data class MangaViewer(@ProtoId(1) val pages: List<MangaPlusPage> = emptyList()) data class MangaViewer(@ProtoNumber(1) val pages: List<MangaPlusPage> = emptyList())
@Serializable @Serializable
data class Title( data class Title(
@ProtoId(1) val titleId: Int, @ProtoNumber(1) val titleId: Int,
@ProtoId(2) val name: String, @ProtoNumber(2) val name: String,
@ProtoId(3) val author: String, @ProtoNumber(3) val author: String,
@ProtoId(4) val portraitImageUrl: String, @ProtoNumber(4) val portraitImageUrl: String,
@ProtoId(5) val landscapeImageUrl: String, @ProtoNumber(5) val landscapeImageUrl: String,
@ProtoId(6) val viewCount: Int = 0, @ProtoNumber(6) val viewCount: Int = 0,
@ProtoId(7) val language: Language? = Language.ENGLISH @ProtoNumber(7) val language: Language? = Language.ENGLISH
) )
@Serializable @Serializable
enum class Language(val id: Int) { enum class Language(val id: Int) {
@ProtoId(0) @ProtoNumber(0)
@SerializedName("0") @SerializedName("0")
ENGLISH(0), ENGLISH(0),
@ProtoId(1) @ProtoNumber(1)
@SerializedName("1") @SerializedName("1")
SPANISH(1) SPANISH(1)
} }
@Serializable @Serializable
data class UpdatedTitleGroup( data class UpdatedTitleGroup(
@ProtoId(1) val groupName: String, @ProtoNumber(1) val groupName: String,
@ProtoId(2) val titles: List<UpdatedTitle> = emptyList() @ProtoNumber(2) val titles: List<UpdatedTitle> = emptyList()
) )
@Serializable @Serializable
data class UpdatedTitle( data class UpdatedTitle(
@ProtoId(1) val title: Title? = null @ProtoNumber(1) val title: Title? = null
) )
@Serializable @Serializable
data class Chapter( data class Chapter(
@ProtoId(1) val titleId: Int, @ProtoNumber(1) val titleId: Int,
@ProtoId(2) val chapterId: Int, @ProtoNumber(2) val chapterId: Int,
@ProtoId(3) val name: String, @ProtoNumber(3) val name: String,
@ProtoId(4) val subTitle: String? = null, @ProtoNumber(4) val subTitle: String? = null,
@ProtoId(6) val startTimeStamp: Int, @ProtoNumber(6) val startTimeStamp: Int,
@ProtoId(7) val endTimeStamp: Int @ProtoNumber(7) val endTimeStamp: Int
) )
@Serializable @Serializable
data class MangaPlusPage(@ProtoId(1) val page: MangaPage? = null) data class MangaPlusPage(@ProtoNumber(1) val page: MangaPage? = null)
@Serializable @Serializable
data class MangaPage( data class MangaPage(
@ProtoId(1) val imageUrl: String, @ProtoNumber(1) val imageUrl: String,
@ProtoId(2) val width: Int, @ProtoNumber(2) val width: Int,
@ProtoId(3) val height: Int, @ProtoNumber(3) val height: Int,
@ProtoId(5) val encryptionKey: String? = null @ProtoNumber(5) val encryptionKey: String? = null
) )
// Used for the deserialization on KitKat devices. // Used for the deserialization on KitKat devices.
const val DECODE_SCRIPT: String = """ const val DECODE_SCRIPT: String =
"""
Duktape.modSearch = function(id) { Duktape.modSearch = function(id) {
if (id == "protobufjs") if (id == "protobufjs")
return helper.getProtobuf(); return helper.getProtobuf();

View File

@ -7,13 +7,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
open class MangaToon( open class MangaToon(
override val lang: String, override val lang: String,
@ -73,16 +73,16 @@ open class MangaToon(
override fun chapterFromElement(element: Element): SChapter { override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.url = element.select("a").first().attr("href") chapter.url = element.select("a").first().attr("href")
chapter.chapter_number = element.select("div.item-left").text().trim().toFloat() chapter.chapter_number = element.select("div.item-left").text().trim().toFloat()
val date = element.select("div.episode-date").text() val date = element.select("div.episode-date").text()
chapter.date_upload = parseDate(date) chapter.date_upload = parseDate(date)
chapter.name = if (chapter.chapter_number> 20) { "\uD83D\uDD12 " } else { "" } + element.select("div.episode-title").text().trim() chapter.name = if (chapter.chapter_number> 20) { "\uD83D\uDD12 " } else { "" } + element.select("div.episode-title").text().trim()
return chapter return chapter
} }
private fun parseDate(date: String): Long { private fun parseDate(date: String): Long {
return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(date).time return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(date)?.time ?: 0L
} }
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {

View File

@ -14,11 +14,11 @@ class MangaToonFactory : SourceFactory {
TH() TH()
) )
class ZH : MangaToon("zh", "cn") class ZH : MangaToon("zh", "cn")
class EN : MangaToon("en", "en") class EN : MangaToon("en", "en")
class ID : MangaToon("id", "id") class ID : MangaToon("id", "id")
class VI : MangaToon("vi", "vi") class VI : MangaToon("vi", "vi")
class ES : MangaToon("es", "es") class ES : MangaToon("es", "es")
class PT : MangaToon("pt", "pt") class PT : MangaToon("pt", "pt")
class TH : MangaToon("th", "th") class TH : MangaToon("th", "th")
} }

View File

@ -4,6 +4,10 @@ import android.annotation.SuppressLint
import android.annotation.TargetApi import android.annotation.TargetApi
import android.os.Build import android.os.Build
import com.google.gson.Gson import com.google.gson.Gson
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import java.io.File import java.io.File
import java.io.PrintWriter import java.io.PrintWriter
import java.security.cert.CertificateException import java.security.cert.CertificateException
@ -13,10 +17,6 @@ import java.util.concurrent.TimeUnit
import javax.net.ssl.SSLContext import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager import javax.net.ssl.X509TrustManager
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
/** /**
* This class generates the sources for MMRCMS. * This class generates the sources for MMRCMS.
@ -195,21 +195,23 @@ class Generator {
@Throws(Exception::class) @Throws(Exception::class)
private fun getOkHttpClient(): OkHttpClient { private fun getOkHttpClient(): OkHttpClient {
val trustAllCerts = arrayOf<TrustManager>(object : X509TrustManager { val trustAllCerts = arrayOf<TrustManager>(
@SuppressLint("TrustAllX509TrustManager") object : X509TrustManager {
@Throws(CertificateException::class) @SuppressLint("TrustAllX509TrustManager")
override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) { @Throws(CertificateException::class)
} override fun checkClientTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
}
@SuppressLint("TrustAllX509TrustManager") @SuppressLint("TrustAllX509TrustManager")
@Throws(CertificateException::class) @Throws(CertificateException::class)
override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) { override fun checkServerTrusted(chain: Array<java.security.cert.X509Certificate>, authType: String) {
} }
override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> { override fun getAcceptedIssuers(): Array<java.security.cert.X509Certificate> {
return arrayOf() return arrayOf()
}
} }
}) )
// Install the all-trusting trust manager // Install the all-trusting trust manager
@ -272,61 +274,62 @@ class Generator {
SourceData("fr", "Op-VF", "https://www.op-vf.com"), SourceData("fr", "Op-VF", "https://www.op-vf.com"),
SourceData("fr", "FR Scan", "https://www.frscan.me"), SourceData("fr", "FR Scan", "https://www.frscan.me"),
// NOTE: THIS SOURCE CONTAINS A CUSTOM LANGUAGE SYSTEM (which will be ignored)! // NOTE: THIS SOURCE CONTAINS A CUSTOM LANGUAGE SYSTEM (which will be ignored)!
SourceData("other", "HentaiShark", "https://www.hentaishark.com", true)) SourceData("other", "HentaiShark", "https://www.hentaishark.com", true)
// Changed CMS )
// SourceData("en", "MangaTreat Scans", "http://www.mangatreat.com"), // Changed CMS
// SourceData("en", "Chibi Manga Reader", "https://www.cmreader.info"), // SourceData("en", "MangaTreat Scans", "http://www.mangatreat.com"),
// SourceData("tr", "Epikmanga", "https://www.epikmanga.com"), // SourceData("en", "Chibi Manga Reader", "https://www.cmreader.info"),
// SourceData("en", "Hatigarm Scans", "https://hatigarmscans.net"), // SourceData("tr", "Epikmanga", "https://www.epikmanga.com"),
// Went offline // SourceData("en", "Hatigarm Scans", "https://hatigarmscans.net"),
// SourceData("en", "Mangawww Reader", "https://mangawww.club"), // Went offline
// SourceData("ru", "Anigai clan", "http://anigai.ru"), // SourceData("en", "Mangawww Reader", "https://mangawww.club"),
// SourceData("en", "ZXComic", "http://zxcomic.com"), // SourceData("ru", "Anigai clan", "http://anigai.ru"),
// SourceData("es", "SOS Scanlation", "https://sosscanlation.com"), // SourceData("en", "ZXComic", "http://zxcomic.com"),
// SourceData("es", "MangaCasa", "https://mangacasa.com")) // SourceData("es", "SOS Scanlation", "https://sosscanlation.com"),
// SourceData("ja", "RAW MANGA READER", "https://rawmanga.site"), // SourceData("es", "MangaCasa", "https://mangacasa.com"))
// SourceData("ar", "Manga FYI", "http://mangafyi.com/manga/arabic"), // SourceData("ja", "RAW MANGA READER", "https://rawmanga.site"),
// SourceData("en", "MangaRoot", "http://mangaroot.com"), // SourceData("ar", "Manga FYI", "http://mangafyi.com/manga/arabic"),
// SourceData("en", "MangaForLife", "http://manga4ever.com"), // SourceData("en", "MangaRoot", "http://mangaroot.com"),
// SourceData("en", "Manga Spoil", "http://mangaspoil.com"), // SourceData("en", "MangaForLife", "http://manga4ever.com"),
// SourceData("en", "MangaBlue", "http://mangablue.com"), // SourceData("en", "Manga Spoil", "http://mangaspoil.com"),
// SourceData("en", "Manga Forest", "https://mangaforest.com"), // SourceData("en", "MangaBlue", "http://mangablue.com"),
// SourceData("en", "DManga", "http://dmanga.website"), // SourceData("en", "Manga Forest", "https://mangaforest.com"),
// SourceData("en", "DB Manga", "http://dbmanga.com"), // SourceData("en", "DManga", "http://dmanga.website"),
// SourceData("en", "Mangacox", "http://mangacox.com"), // SourceData("en", "DB Manga", "http://dbmanga.com"),
// SourceData("en", "GO Manhwa", "http://gomanhwa.xyz"), // SourceData("en", "Mangacox", "http://mangacox.com"),
// SourceData("en", "KoManga", "https://komanga.net"), // SourceData("en", "GO Manhwa", "http://gomanhwa.xyz"),
// SourceData("en", "Manganimecan", "http://manganimecan.com"), // SourceData("en", "KoManga", "https://komanga.net"),
// SourceData("en", "Hentai2Manga", "http://hentai2manga.com"), // SourceData("en", "Manganimecan", "http://manganimecan.com"),
// SourceData("en", "4 Manga", "http://4-manga.com"), // SourceData("en", "Hentai2Manga", "http://hentai2manga.com"),
// SourceData("en", "XYXX.INFO", "http://xyxx.info"), // SourceData("en", "4 Manga", "http://4-manga.com"),
// SourceData("en", "Isekai Manga Reader", "https://isekaimanga.club"), // SourceData("en", "XYXX.INFO", "http://xyxx.info"),
// SourceData("fa", "TrinityReader", "http://trinityreader.pw"), // SourceData("en", "Isekai Manga Reader", "https://isekaimanga.club"),
// SourceData("fr", "Manga-LEL", "https://www.manga-lel.com"), // SourceData("fa", "TrinityReader", "http://trinityreader.pw"),
// SourceData("fr", "Manga Etonnia", "https://www.etonnia.com"), // SourceData("fr", "Manga-LEL", "https://www.manga-lel.com"),
// SourceData("fr", "ScanFR.com"), "http://scanfr.com"), // SourceData("fr", "Manga Etonnia", "https://www.etonnia.com"),
// SourceData("fr", "Manga FYI", "http://mangafyi.com/manga/french"), // SourceData("fr", "ScanFR.com"), "http://scanfr.com"),
// SourceData("fr", "scans-manga", "http://scans-manga.com"), // SourceData("fr", "Manga FYI", "http://mangafyi.com/manga/french"),
// SourceData("fr", "Henka no Kaze", "http://henkanokazelel.esy.es/upload"), // SourceData("fr", "scans-manga", "http://scans-manga.com"),
// SourceData("fr", "Tous Vos Scans", "http://www.tous-vos-scans.com"), // SourceData("fr", "Henka no Kaze", "http://henkanokazelel.esy.es/upload"),
// SourceData("id", "Manga Desu", "http://mangadesu.net"), // SourceData("fr", "Tous Vos Scans", "http://www.tous-vos-scans.com"),
// SourceData("id", "Komik Mangafire.ID", "http://go.mangafire.id"), // SourceData("id", "Manga Desu", "http://mangadesu.net"),
// SourceData("id", "MangaOnline", "https://mangaonline.web.id"), // SourceData("id", "Komik Mangafire.ID", "http://go.mangafire.id"),
// SourceData("id", "MangaNesia", "https://manganesia.com"), // SourceData("id", "MangaOnline", "https://mangaonline.web.id"),
// SourceData("id", "MangaID", "https://mangaid.me" // SourceData("id", "MangaNesia", "https://manganesia.com"),
// SourceData("id", "Manga Seru", "http://www.mangaseru.top" // SourceData("id", "MangaID", "https://mangaid.me"
// SourceData("id", "Manga FYI", "http://mangafyi.com/manga/indonesian" // SourceData("id", "Manga Seru", "http://www.mangaseru.top"
// SourceData("id", "Bacamangaku", "http://www.bacamangaku.com"), // SourceData("id", "Manga FYI", "http://mangafyi.com/manga/indonesian"
// SourceData("id", "Indo Manga Reader", "http://indomangareader.com"), // SourceData("id", "Bacamangaku", "http://www.bacamangaku.com"),
// SourceData("it", "Kingdom Italia Reader", "http://kireader.altervista.org"), // SourceData("id", "Indo Manga Reader", "http://indomangareader.com"),
// SourceData("ja", "IchigoBook", "http://ichigobook.com"), // SourceData("it", "Kingdom Italia Reader", "http://kireader.altervista.org"),
// SourceData("ja", "Mangaraw Online", "http://mangaraw.online" // SourceData("ja", "IchigoBook", "http://ichigobook.com"),
// SourceData("ja", "Mangazuki RAWS", "https://raws.mangazuki.co"), // SourceData("ja", "Mangaraw Online", "http://mangaraw.online"
// SourceData("ja", "MangaRAW", "https://www.mgraw.com"), // SourceData("ja", "Mangazuki RAWS", "https://raws.mangazuki.co"),
// SourceData("ja", "マンガ/漫画 マガジン/雑誌 raw", "http://netabare-manga-raw.com"), // SourceData("ja", "MangaRAW", "https://www.mgraw.com"),
// SourceData("ru", "NAKAMA", "http://nakama.ru"), // SourceData("ja", "マンガ/漫画 マガジン/雑誌 raw", "http://netabare-manga-raw.com"),
// SourceData("tr", "MangAoi", "http://mangaoi.com"), // SourceData("ru", "NAKAMA", "http://nakama.ru"),
// SourceData("tr", "ManhuaTR", "http://www.manhua-tr.com"), // SourceData("tr", "MangAoi", "http://mangaoi.com"),
// SourceData("tr", "ManhuaTR", "http://www.manhua-tr.com"),
val relativePath = System.getProperty("user.dir") + "/src/all/mmrcms/src/eu/kanade/tachiyomi/extension/all/mmrcms/GeneratedSources.kt" val relativePath = System.getProperty("user.dir") + "/src/all/mmrcms/src/eu/kanade/tachiyomi/extension/all/mmrcms/GeneratedSources.kt"

View File

@ -18,16 +18,16 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.net.URLDecoder
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.net.URLDecoder
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
open class MyMangaReaderCMSSource( open class MyMangaReaderCMSSource(
final override val lang: String, final override val lang: String,
@ -114,17 +114,20 @@ open class MyMangaReaderCMSSource(
val jsonArray = jsonParser.parse(response.body()!!.string()).let { val jsonArray = jsonParser.parse(response.body()!!.string()).let {
if (name == "Mangas.pw") it.array else it["suggestions"].array if (name == "Mangas.pw") it.array else it["suggestions"].array
} }
MangasPage(jsonArray MangasPage(
.map { jsonArray
SManga.create().apply { .map {
val segment = it["data"].string SManga.create().apply {
url = getUrlWithoutBaseUrl(itemUrl + segment) val segment = it["data"].string
title = it["value"].string url = getUrlWithoutBaseUrl(itemUrl + segment)
title = it["value"].string
// Guess thumbnails // Guess thumbnails
// thumbnail_url = "$baseUrl/uploads/manga/$segment/cover/cover_250x350.jpg" // thumbnail_url = "$baseUrl/uploads/manga/$segment/cover/cover_250x350.jpg"
} }
}, false) },
false
)
} else { } else {
internalMangaParse(response) internalMangaParse(response)
} }
@ -184,27 +187,30 @@ open class MyMangaReaderCMSSource(
"Utsukushii" -> "div.content div.col-sm-6" "Utsukushii" -> "div.content div.col-sm-6"
else -> "div[class^=col-sm], div.col-xs-6" else -> "div[class^=col-sm], div.col-xs-6"
} }
return MangasPage(document.select(internalMangaSelector).map { return MangasPage(
SManga.create().apply { document.select(internalMangaSelector).map {
val urlElement = it.getElementsByClass("chart-title") SManga.create().apply {
if (urlElement.size == 0) { val urlElement = it.getElementsByClass("chart-title")
url = getUrlWithoutBaseUrl(it.select("a").attr("href")) if (urlElement.size == 0) {
title = it.select("div.caption").text() url = getUrlWithoutBaseUrl(it.select("a").attr("href"))
it.select("div.caption div").text().let { if (it.isNotEmpty()) title = title.substringBefore(it) } // To clean submanga's titles without breaking hentaishark's title = it.select("div.caption").text()
} else { it.select("div.caption div").text().let { if (it.isNotEmpty()) title = title.substringBefore(it) } // To clean submanga's titles without breaking hentaishark's
url = getUrlWithoutBaseUrl(urlElement.attr("href")) } else {
title = urlElement.text().trim() url = getUrlWithoutBaseUrl(urlElement.attr("href"))
} title = urlElement.text().trim()
}
it.select("img").let { img -> it.select("img").let { img ->
thumbnail_url = when { thumbnail_url = when {
it.hasAttr("data-background-image") -> it.attr("data-background-image") // Utsukushii it.hasAttr("data-background-image") -> it.attr("data-background-image") // Utsukushii
img.hasAttr("data-src") -> coverGuess(img.attr("abs:data-src"), url) img.hasAttr("data-src") -> coverGuess(img.attr("abs:data-src"), url)
else -> coverGuess(img.attr("abs:src"), url) else -> coverGuess(img.attr("abs:src"), url)
}
} }
} }
} },
}, document.select(".pagination a[rel=next]").isNotEmpty()) document.select(".pagination a[rel=next]").isNotEmpty()
)
} }
// Guess thumbnails on broken websites // Guess thumbnails on broken websites
@ -364,39 +370,43 @@ open class MyMangaReaderCMSSource(
} }
override fun pageListParse(response: Response) = response.asJsoup().select("#all > .img-responsive") override fun pageListParse(response: Response) = response.asJsoup().select("#all > .img-responsive")
.mapIndexed { i, e -> .mapIndexed { i, e ->
var url = (if (e.hasAttr("data-src")) e.attr("abs:data-src") else e.attr("abs:src")).trim() var url = (if (e.hasAttr("data-src")) e.attr("abs:data-src") else e.attr("abs:src")).trim()
// Mangas.pw encodes some of their urls, decode them // Mangas.pw encodes some of their urls, decode them
if (name.contains("Mangas.pw") && !url.contains(".")) { if (name.contains("Mangas.pw") && !url.contains(".")) {
url = Base64.decode(url.substringAfter("//"), Base64.DEFAULT).toString(Charsets.UTF_8).substringBefore("=") url = Base64.decode(url.substringAfter("//"), Base64.DEFAULT).toString(Charsets.UTF_8).substringBefore("=")
url = URLDecoder.decode(url, "UTF-8") url = URLDecoder.decode(url, "UTF-8")
}
Page(i, "", url)
} }
Page(i, "", url)
}
override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Unused method called!") override fun imageUrlParse(response: Response) = throw UnsupportedOperationException("Unused method called!")
private fun getInitialFilterList() = listOf<Filter<*>>( private fun getInitialFilterList() = listOf<Filter<*>>(
Filter.Header("NOTE: Ignored if using text search!"), Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(), Filter.Separator(),
AuthorFilter(), AuthorFilter(),
UriSelectFilter("Category", UriSelectFilter(
"cat", "Category",
arrayOf("" to "Any", "cat",
*categoryMappings.toTypedArray() arrayOf(
) "" to "Any",
), *categoryMappings.toTypedArray()
UriSelectFilter("Begins with", )
"alpha", ),
arrayOf("" to "Any", UriSelectFilter(
*"#ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray().map { "Begins with",
Pair(it.toString(), it.toString()) "alpha",
}.toTypedArray() arrayOf(
) "" to "Any",
), *"#ABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray().map {
SortFilter() Pair(it.toString(), it.toString())
}.toTypedArray()
)
),
SortFilter()
) )
/** /**
@ -406,11 +416,16 @@ open class MyMangaReaderCMSSource(
return when { return when {
name == "Mangas.pw" -> FilterList() name == "Mangas.pw" -> FilterList()
tagMappings != null -> { tagMappings != null -> {
FilterList(getInitialFilterList() + UriSelectFilter("Tag", FilterList(
"tag", getInitialFilterList() + UriSelectFilter(
arrayOf("" to "Any", "Tag",
*tagMappings.toTypedArray() "tag",
))) arrayOf(
"" to "Any",
*tagMappings.toTypedArray()
)
)
)
} }
else -> FilterList(getInitialFilterList()) else -> FilterList(getInitialFilterList())
} }
@ -429,7 +444,7 @@ open class MyMangaReaderCMSSource(
private val firstIsUnspecified: Boolean = true, private val firstIsUnspecified: Boolean = true,
defaultValue: Int = 0 defaultValue: Int = 0
) : ) :
Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter { Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter {
override fun addToUri(uri: Uri.Builder) { override fun addToUri(uri: Uri.Builder) {
if (state != 0 || !firstIsUnspecified) if (state != 0 || !firstIsUnspecified)
uri.appendQueryParameter(uriParam, vals[state].first) uri.appendQueryParameter(uriParam, vals[state].first)
@ -442,9 +457,13 @@ open class MyMangaReaderCMSSource(
} }
} }
class SortFilter : Filter.Sort("Sort", class SortFilter :
Filter.Sort(
"Sort",
sortables.map { it.second }.toTypedArray(), sortables.map { it.second }.toTypedArray(),
Selection(0, true)), UriFilter { Selection(0, true)
),
UriFilter {
override fun addToUri(uri: Uri.Builder) { override fun addToUri(uri: Uri.Builder) {
uri.appendQueryParameter("sortBy", sortables[state!!.index].first) uri.appendQueryParameter("sortBy", sortables[state!!.index].first)
uri.appendQueryParameter("asc", state!!.ascending.toString()) uri.appendQueryParameter("asc", state!!.ascending.toString())
@ -452,9 +471,9 @@ open class MyMangaReaderCMSSource(
companion object { companion object {
private val sortables = arrayOf( private val sortables = arrayOf(
"name" to "Name", "name" to "Name",
"views" to "Popularity", "views" to "Popularity",
"last_release" to "Last update" "last_release" to "Last update"
) )
} }
} }

View File

@ -13,9 +13,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -24,6 +21,9 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
open class MyReadingManga(override val lang: String, private val siteLang: String, private val latestLang: String) : ParsedHttpSource() { open class MyReadingManga(override val lang: String, private val siteLang: String, private val latestLang: String) : ParsedHttpSource() {
@ -159,8 +159,12 @@ open class MyReadingManga(override val lang: String, private val siteLang: Strin
} }
if (needCover) { if (needCover) {
thumbnail_url = getThumbnail(getImage(client.newCall(GET("$baseUrl/search/?search=${document.location()}", headers)) thumbnail_url = getThumbnail(
.execute().asJsoup().select("div.wdm_results div.p_content img").first())) getImage(
client.newCall(GET("$baseUrl/search/?search=${document.location()}", headers))
.execute().asJsoup().select("div.wdm_results div.p_content img").first()
)
)
} }
} }
} }

View File

@ -1,8 +1,8 @@
package eu.kanade.tachiyomi.extension.all.nhentai package eu.kanade.tachiyomi.extension.all.nhentai
import java.text.SimpleDateFormat
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
object NHUtils { object NHUtils {
fun getArtists(document: Document): String { fun getArtists(document: Document): String {
@ -57,7 +57,7 @@ object NHUtils {
fun getTime(document: Document): Long { fun getTime(document: Document): Long {
val timeString = document.toString().substringAfter("datetime=\"").substringBefore("\">").replace("T", " ") val timeString = document.toString().substringAfter("datetime=\"").substringBefore("\">").replace("T", " ")
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSZ").parse(timeString).time return SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSSZ").parse(timeString)?.time ?: 0L
} }
private fun Element.cleanTag(): String = text().replace(Regex("\\(.*\\)"), "").trim() private fun Element.cleanTag(): String = text().replace(Regex("\\(.*\\)"), "").trim()

View File

@ -251,12 +251,14 @@ open class NHentai(
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup() val document = response.asJsoup()
return listOf(SChapter.create().apply { return listOf(
name = "Chapter" SChapter.create().apply {
scanlator = getGroups(document) name = "Chapter"
date_upload = getTime(document) scanlator = getGroups(document)
setUrlWithoutDomain(response.request().url().encodedPath()) date_upload = getTime(document)
}) setUrlWithoutDomain(response.request().url().encodedPath())
}
)
} }
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException("Not used") override fun chapterFromElement(element: Element) = throw UnsupportedOperationException("Not used")

View File

@ -18,13 +18,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.util.Date
import okhttp3.MediaType import okhttp3.MediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import java.util.Date
@Nsfw @Nsfw
class NineHentai : HttpSource() { class NineHentai : HttpSource() {
@ -51,26 +51,26 @@ class NineHentai : HttpSource() {
override fun fetchPopularManga(page: Int): Observable<MangasPage> { override fun fetchPopularManga(page: Int): Observable<MangasPage> {
return client.newCall(popularMangaRequest(page)) return client.newCall(popularMangaRequest(page))
.asObservableSuccess() .asObservableSuccess()
.map { response -> .map { response ->
getMangaList(response, page) getMangaList(response, page)
} }
} }
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> { override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
return client.newCall(latestUpdatesRequest(page)) return client.newCall(latestUpdatesRequest(page))
.asObservableSuccess() .asObservableSuccess()
.map { response -> .map { response ->
getMangaList(response, page) getMangaList(response, page)
} }
} }
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return client.newCall(searchMangaRequest(page, query, filters)) return client.newCall(searchMangaRequest(page, query, filters))
.asObservableSuccess() .asObservableSuccess()
.map { response -> .map { response ->
getMangaList(response, page) getMangaList(response, page)
} }
} }
private fun getMangaList(response: Response, page: Int): MangasPage { private fun getMangaList(response: Response, page: Int): MangasPage {
@ -180,13 +180,15 @@ class NineHentai : HttpSource() {
private class GenreList(tags: List<Tag>) : Filter.Group<Tag>("Tags", tags) private class GenreList(tags: List<Tag>) : Filter.Group<Tag>("Tags", tags)
private class Sorting : Filter.Sort("Sorting", private class Sorting : Filter.Sort(
arrayOf("Newest", "Popular Right now", "Most Fapped", "Most Viewed", "By Title"), "Sorting",
Selection(1, false)) arrayOf("Newest", "Popular Right now", "Most Fapped", "Most Viewed", "By Title"),
Selection(1, false)
)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
Sorting(), Sorting(),
GenreList(NHTags.getTagsList()) GenreList(NHTags.getTagsList())
) )
override fun imageUrlParse(response: Response): String = throw Exception("Not Used") override fun imageUrlParse(response: Response): String = throw Exception("Not Used")

View File

@ -7,15 +7,15 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
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
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
open class NineManga(override val name: String, override val baseUrl: String, override val lang: String) : ParsedHttpSource() { open class NineManga(override val name: String, override val baseUrl: String, override val lang: String) : ParsedHttpSource() {
@ -84,7 +84,7 @@ open class NineManga(override val name: String, override val baseUrl: String, ov
if (dateWords.size == 3) { if (dateWords.size == 3) {
if (dateWords[1].contains(",")) { if (dateWords[1].contains(",")) {
return try { return try {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) { } catch (e: ParseException) {
0L 0L
} }
@ -161,21 +161,27 @@ open class NineManga(override val name: String, override val baseUrl: String, ov
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
protected open class ContainBeginEndFilter(name: String) : UriPartFilter(name, arrayOf( protected open class ContainBeginEndFilter(name: String) : UriPartFilter(
Pair("Contain", "contain"), name,
Pair("Begin", "begin"), arrayOf(
Pair("End", "end") Pair("Contain", "contain"),
)) Pair("Begin", "begin"),
Pair("End", "end")
)
)
private class QueryCBEFilter : ContainBeginEndFilter("Query") private class QueryCBEFilter : ContainBeginEndFilter("Query")
private class AuthorCBEFilter : ContainBeginEndFilter("Author") private class AuthorCBEFilter : ContainBeginEndFilter("Author")
private class ArtistCBEFilter : ContainBeginEndFilter("Artist") private class ArtistCBEFilter : ContainBeginEndFilter("Artist")
private class CompletedFilter : UriPartFilter("Completed", arrayOf( private class CompletedFilter : UriPartFilter(
Pair("Either", "either"), "Completed",
Pair("Yes", "yes"), arrayOf(
Pair("No", "no") Pair("Either", "either"),
)) Pair("Yes", "yes"),
Pair("No", "no")
)
)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
QueryCBEFilter(), QueryCBEFilter(),

View File

@ -4,12 +4,12 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.Request
import org.jsoup.nodes.Element
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
import okhttp3.Request
import org.jsoup.nodes.Element
class NineMangaFactory : SourceFactory { class NineMangaFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(
@ -756,7 +756,7 @@ fun parseChapterDateByLang(date: String): Long {
if (dateWords.size == 3) { if (dateWords.size == 3) {
if (dateWords[1].contains(",")) { if (dateWords[1].contains(",")) {
return try { return try {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) { } catch (e: ParseException) {
0L 0L
} }

View File

@ -8,9 +8,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -18,6 +15,9 @@ import okhttp3.Response
import org.jsoup.Jsoup import org.jsoup.Jsoup
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
abstract class Paprika( abstract class Paprika(
override val name: String, override val name: String,
@ -161,8 +161,9 @@ abstract class Paprika(
else -> null else -> null
}?.timeInMillis ?: 0L }?.timeInMillis ?: 0L
} }
else -> SimpleDateFormat("MMM d yy", Locale.US) else ->
.parse("${this.substringBefore(",")} $currentYear")?.time ?: 0 SimpleDateFormat("MMM d yy", Locale.US)
.parse("${this.substringBefore(",")} $currentYear")?.time ?: 0
} }
} catch (_: Exception) { } catch (_: Exception) {
0L 0L

View File

@ -9,14 +9,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
class TheLibraryOfOhara(override val lang: String, private val siteLang: String) : ParsedHttpSource() { class TheLibraryOfOhara(override val lang: String, private val siteLang: String) : ParsedHttpSource() {
@ -36,15 +36,16 @@ class TheLibraryOfOhara(override val lang: String, private val siteLang: String)
// only show entries which contain pictures only. // only show entries which contain pictures only.
override fun popularMangaSelector() = when (lang) { override fun popularMangaSelector() = when (lang) {
"en" -> "#categories-7 ul li.cat-item-589813936," + // Chapter Secrets "en" ->
"#categories-7 ul li.cat-item-607613583, " + // Chapter Secrets Specials "#categories-7 ul li.cat-item-589813936," + // Chapter Secrets
"#categories-7 ul li.cat-item-43972770, " + // Charlotte Family "#categories-7 ul li.cat-item-607613583, " + // Chapter Secrets Specials
"#categories-7 ul li.cat-item-9363667, " + // Complete Guides "#categories-7 ul li.cat-item-43972770, " + // Charlotte Family
"#categories-7 ul li.cat-item-634609261, " + // Parody Chapter "#categories-7 ul li.cat-item-9363667, " + // Complete Guides
"#categories-7 ul li.cat-item-699200615, " + // Return to the Reverie "#categories-7 ul li.cat-item-634609261, " + // Parody Chapter
"#categories-7 ul li.cat-item-139757, " + // SBS "#categories-7 ul li.cat-item-699200615, " + // Return to the Reverie
"#categories-7 ul li.cat-item-22695, " + // Timeline "#categories-7 ul li.cat-item-139757, " + // SBS
"#categories-7 ul li.cat-item-648324575" // Vivre Card Databook "#categories-7 ul li.cat-item-22695, " + // Timeline
"#categories-7 ul li.cat-item-648324575" // Vivre Card Databook
"id" -> "#categories-7 ul li.cat-item-702404482, #categories-7 ul li.cat-item-699200615" // Chapter Secrets Bahasa Indonesia, Return to the Reverie "id" -> "#categories-7 ul li.cat-item-702404482, #categories-7 ul li.cat-item-699200615" // Chapter Secrets Bahasa Indonesia, Return to the Reverie
"fr" -> "#categories-7 ul li.cat-item-699200615" // Return to the Reverie "fr" -> "#categories-7 ul li.cat-item-699200615" // Return to the Reverie
"ar" -> "#categories-7 ul li.cat-item-699200615" // Return to the Reverie "ar" -> "#categories-7 ul li.cat-item-699200615" // Return to the Reverie
@ -144,7 +145,7 @@ class TheLibraryOfOhara(override val lang: String, private val siteLang: String)
private fun parseChapterDate(date: String): Long { private fun parseChapterDate(date: String): Long {
val parsedDate = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()).parse(date.replace("+00:00", "+0000")) val parsedDate = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()).parse(date.replace("+00:00", "+0000"))
return parsedDate?.time ?: 0L return parsedDate?.time ?: 0L
} }
private fun chapterNextPageSelector() = "div.nav-previous a" private fun chapterNextPageSelector() = "div.nav-previous a"
@ -180,7 +181,8 @@ class TheLibraryOfOhara(override val lang: String, private val siteLang: String)
!it.name.contains("Arabic") && !it.name.contains("Arabic") &&
!it.name.contains("Italian") && !it.name.contains("Italian") &&
!it.name.contains("Indonesia") && !it.name.contains("Indonesia") &&
!it.name.contains("Spanish") }.toMutableList() !it.name.contains("Spanish")
}.toMutableList()
} }
} }

View File

@ -7,10 +7,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.net.URLDecoder
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -18,6 +14,10 @@ import okhttp3.RequestBody
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.net.URLDecoder
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.concurrent.TimeUnit
abstract class ToomicsGlobal( abstract class ToomicsGlobal(
private val siteLang: String, private val siteLang: String,
@ -153,7 +153,7 @@ abstract class ToomicsGlobal(
private fun parseChapterDate(date: String): Long { private fun parseChapterDate(date: String): Long {
return try { return try {
dateFormat.parse(date).time dateFormat.parse(date)?.time ?: 0L
} catch (e: ParseException) { } catch (e: ParseException) {
0L 0L
} }

View File

@ -5,13 +5,13 @@ import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class DongmanManhua : WebtoonsDefault("zh", "", dateFormat = SimpleDateFormat("yyyy-M-d", Locale.ENGLISH)) { class DongmanManhua : WebtoonsDefault("zh", "", dateFormat = SimpleDateFormat("yyyy-M-d", Locale.ENGLISH)) {
override val baseUrl = "https://www.dongmanmanhua.cn" override val baseUrl = "https://www.dongmanmanhua.cn"

View File

@ -9,7 +9,6 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.util.Calendar
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.Headers import okhttp3.Headers
@ -19,6 +18,7 @@ import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.Calendar
abstract class Webtoons( abstract class Webtoons(
override val lang: String, override val lang: String,
@ -33,21 +33,23 @@ abstract class Webtoons(
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.cookieJar(object : CookieJar { .cookieJar(
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {} object : CookieJar {
override fun loadForRequest(url: HttpUrl): List<Cookie> { override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {}
return listOf<Cookie>( override fun loadForRequest(url: HttpUrl): List<Cookie> {
Cookie.Builder() return listOf<Cookie>(
.domain("www.webtoons.com") Cookie.Builder()
.path("/") .domain("www.webtoons.com")
.name("ageGatePass") .path("/")
.value("true") .name("ageGatePass")
.name("locale") .value("true")
.value(localeForCookie) .name("locale")
.build() .value(localeForCookie)
) .build()
)
}
} }
}) )
.build() .build()
private val day: String private val day: String
@ -71,11 +73,11 @@ abstract class Webtoons(
override fun latestUpdatesSelector() = "div#dailyList > $day li > a" override fun latestUpdatesSelector() = "div#dailyList > $day li > a"
override fun headersBuilder(): Headers.Builder = super.headersBuilder() override fun headersBuilder(): Headers.Builder = super.headersBuilder()
.add("Referer", "https://www.webtoons.com/$langCode/") .add("Referer", "https://www.webtoons.com/$langCode/")
protected val mobileHeaders: Headers = super.headersBuilder() protected val mobileHeaders: Headers = super.headersBuilder()
.add("Referer", "https://m.webtoons.com") .add("Referer", "https://m.webtoons.com")
.build() .build()
override fun popularMangaRequest(page: Int) = GET("$baseUrl/$langCode/dailySchedule", headers) override fun popularMangaRequest(page: Int) = GET("$baseUrl/$langCode/dailySchedule", headers)

View File

@ -4,11 +4,11 @@ import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import java.text.SimpleDateFormat
import java.util.Locale
import org.json.JSONObject import org.json.JSONObject
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
open class WebtoonsDefault( open class WebtoonsDefault(
override val lang: String, override val lang: String,

View File

@ -58,7 +58,8 @@ class WebtoonsIndonesian : WebtoonsDefault("in", "id") {
// Android seems to be unable to parse Indonesian dates; we'll use a short hard-coded table // Android seems to be unable to parse Indonesian dates; we'll use a short hard-coded table
// instead. // instead.
private val dateMap: Array<String> = arrayOf( private val dateMap: Array<String> = arrayOf(
"Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des") "Jan", "Feb", "Mar", "Apr", "Mei", "Jun", "Jul", "Agu", "Sep", "Okt", "Nov", "Des"
)
override fun chapterParseDate(date: String): Long { override fun chapterParseDate(date: String): Long {
val expr = Regex("""(\d{4}) ([A-Z][a-z]{2}) (\d+)""").find(date) ?: return 0 val expr = Regex("""(\d{4}) ([A-Z][a-z]{2}) (\d+)""").find(date) ?: return 0

View File

@ -7,7 +7,6 @@ import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.Page import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import java.util.ArrayList
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
@ -16,6 +15,7 @@ import org.json.JSONObject
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.util.ArrayList
open class WebtoonsTranslate(override val lang: String, private val translateLangCode: String, languageNameExtra: String = "") : Webtoons(lang) { open class WebtoonsTranslate(override val lang: String, private val translateLangCode: String, languageNameExtra: String = "") : Webtoons(lang) {
// popularMangaRequest already returns manga sorted by latest update // popularMangaRequest already returns manga sorted by latest update
@ -80,20 +80,20 @@ open class WebtoonsTranslate(override val lang: String, private val translateLan
?: json.getString("thumbnailMobileUrl") ?: json.getString("thumbnailMobileUrl")
return SManga.create().apply { return SManga.create().apply {
title = json.getString("representTitle") title = json.getString("representTitle")
author = json.getString("writeAuthorName") author = json.getString("writeAuthorName")
artist = json.getString("pictureAuthorName") ?: author artist = json.getString("pictureAuthorName") ?: author
thumbnail_url = if (relativeThumnailURL != null) "$thumbnailBaseUrl$relativeThumnailURL" else null thumbnail_url = if (relativeThumnailURL != null) "$thumbnailBaseUrl$relativeThumnailURL" else null
status = SManga.UNKNOWN status = SManga.UNKNOWN
url = mobileBaseUrl url = mobileBaseUrl
.resolve("/translate/episodeList")!! .resolve("/translate/episodeList")!!
.newBuilder() .newBuilder()
.addQueryParameter("titleNo", json.getInt("titleNo").toString()) .addQueryParameter("titleNo", json.getInt("titleNo").toString())
.addQueryParameter("languageCode", translateLangCode) .addQueryParameter("languageCode", translateLangCode)
.addQueryParameter("teamVersion", json.optInt("teamVersion", 0).toString()) .addQueryParameter("teamVersion", json.optInt("teamVersion", 0).toString())
.build() .build()
.toString() .toString()
} }
} }
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> { override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {

View File

@ -7,14 +7,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
abstract class WPComics( abstract class WPComics(
override val name: String, override val name: String,

View File

@ -9,12 +9,12 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class WPComicsFactory : SourceFactory { class WPComicsFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(
@ -113,9 +113,9 @@ private class ComicLatest : WPComics("ComicLatest", "https://comiclatest.com", "
override fun popularMangaFromElement(element: Element) = SManga.create().apply { override fun popularMangaFromElement(element: Element) = SManga.create().apply {
element.select("h3 a").let { element.select("h3 a").let {
title = it.text() title = it.text()
setUrlWithoutDomain(it.attr("href")) setUrlWithoutDomain(it.attr("href"))
} }
thumbnail_url = element.select("img").attr("data-original") thumbnail_url = element.select("img").attr("data-original")
} }

View File

@ -13,10 +13,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -26,6 +22,10 @@ import org.jsoup.nodes.Element
import org.jsoup.select.Elements import org.jsoup.select.Elements
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
abstract class WPMangaStream( abstract class WPMangaStream(
override val name: String, override val name: String,
@ -273,28 +273,37 @@ abstract class WPMangaStream(
private class YearFilter : Filter.Text("Year") private class YearFilter : Filter.Text("Year")
protected class TypeFilter : UriPartFilter("Type", arrayOf( protected class TypeFilter : UriPartFilter(
Pair("Default", ""), "Type",
Pair("Manga", "Manga"), arrayOf(
Pair("Manhwa", "Manhwa"), Pair("Default", ""),
Pair("Manhua", "Manhua"), Pair("Manga", "Manga"),
Pair("Comic", "Comic") Pair("Manhwa", "Manhwa"),
)) Pair("Manhua", "Manhua"),
Pair("Comic", "Comic")
)
)
protected class SortByFilter : UriPartFilter("Sort By", arrayOf( protected class SortByFilter : UriPartFilter(
Pair("Default", ""), "Sort By",
Pair("A-Z", "title"), arrayOf(
Pair("Z-A", "titlereverse"), Pair("Default", ""),
Pair("Latest Update", "update"), Pair("A-Z", "title"),
Pair("Latest Added", "latest"), Pair("Z-A", "titlereverse"),
Pair("Popular", "popular") Pair("Latest Update", "update"),
)) Pair("Latest Added", "latest"),
Pair("Popular", "popular")
)
)
protected class StatusFilter : UriPartFilter("Status", arrayOf( protected class StatusFilter : UriPartFilter(
Pair("All", ""), "Status",
Pair("Ongoing", "ongoing"), arrayOf(
Pair("Completed", "completed") Pair("All", ""),
)) Pair("Ongoing", "ongoing"),
Pair("Completed", "completed")
)
)
protected class Genre(name: String, val id: String = name) : Filter.TriState(name) protected class Genre(name: String, val id: String = name) : Filter.TriState(name)
protected class GenreListFilter(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres) protected class GenreListFilter(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres)

View File

@ -10,7 +10,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.io.IOException
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Interceptor import okhttp3.Interceptor
@ -20,6 +19,7 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.io.IOException
class WPMangaStreamFactory : SourceFactory { class WPMangaStreamFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(
@ -198,66 +198,72 @@ class WestManga : WPMangaStream("West Manga (WP Manga Stream)", "https://westman
return manga return manga
} }
private class SortByFilter : UriPartFilter("Sort By", arrayOf( private class SortByFilter : UriPartFilter(
Pair("Default", ""), "Sort By",
Pair("A-Z", "A-Z"), arrayOf(
Pair("Latest Added", "latest"), Pair("Default", ""),
Pair("Popular", "popular") Pair("A-Z", "A-Z"),
)) Pair("Latest Added", "latest"),
Pair("Popular", "popular")
)
)
private class GenreListFilter : UriPartFilter("Genre", arrayOf( private class GenreListFilter : UriPartFilter(
Pair("Default", ""), "Genre",
Pair("4-Koma", "4-koma"), arrayOf(
Pair("Action", "action"), Pair("Default", ""),
Pair("Adventure", "adventure"), Pair("4-Koma", "4-koma"),
Pair("Comedy", "comedy"), Pair("Action", "action"),
Pair("Cooking", "cooking"), Pair("Adventure", "adventure"),
Pair("Demons", "demons"), Pair("Comedy", "comedy"),
Pair("Drama", "drama"), Pair("Cooking", "cooking"),
Pair("Ecchi", "ecchi"), Pair("Demons", "demons"),
Pair("Fantasy", "fantasy"), Pair("Drama", "drama"),
Pair("FantasyAction", "fantasyaction"), Pair("Ecchi", "ecchi"),
Pair("Game", "game"), Pair("Fantasy", "fantasy"),
Pair("Gender Bender", "gender-bender"), Pair("FantasyAction", "fantasyaction"),
Pair("Gore", "gore"), Pair("Game", "game"),
Pair("Harem", "harem"), Pair("Gender Bender", "gender-bender"),
Pair("Historical", "historical"), Pair("Gore", "gore"),
Pair("Horro", "horro"), Pair("Harem", "harem"),
Pair("Horror", "horror"), Pair("Historical", "historical"),
Pair("Isekai", "isekai"), Pair("Horro", "horro"),
Pair("Isekai Action", "isekai-action"), Pair("Horror", "horror"),
Pair("Josei", "josei"), Pair("Isekai", "isekai"),
Pair("Magic", "magic"), Pair("Isekai Action", "isekai-action"),
Pair("Manga", "manga"), Pair("Josei", "josei"),
Pair("Manhua", "manhua"), Pair("Magic", "magic"),
Pair("Martial arts", "martial-arts"), Pair("Manga", "manga"),
Pair("Mature", "mature"), Pair("Manhua", "manhua"),
Pair("Mecha", "mecha"), Pair("Martial arts", "martial-arts"),
Pair("Medical", "medical"), Pair("Mature", "mature"),
Pair("Music", "music"), Pair("Mecha", "mecha"),
Pair("Mystery", "mystery"), Pair("Medical", "medical"),
Pair("Oneshot", "oneshot"), Pair("Music", "music"),
Pair("Project", "project"), Pair("Mystery", "mystery"),
Pair("Psychological", "psychological"), Pair("Oneshot", "oneshot"),
Pair("Romance", "romance"), Pair("Project", "project"),
Pair("School", "school"), Pair("Psychological", "psychological"),
Pair("School life", "school-life"), Pair("Romance", "romance"),
Pair("Sci fi", "sci-fi"), Pair("School", "school"),
Pair("Seinen", "seinen"), Pair("School life", "school-life"),
Pair("Shoujo", "shoujo"), Pair("Sci fi", "sci-fi"),
Pair("Shoujo Ai", "shoujo-ai"), Pair("Seinen", "seinen"),
Pair("Shounen", "shounen"), Pair("Shoujo", "shoujo"),
Pair("Slice of Life", "slice-of-life"), Pair("Shoujo Ai", "shoujo-ai"),
Pair("Sports", "sports"), Pair("Shounen", "shounen"),
Pair("Super Power", "super-power"), Pair("Slice of Life", "slice-of-life"),
Pair("Supernatural", "supernatural"), Pair("Sports", "sports"),
Pair("Suspense", "suspense"), Pair("Super Power", "super-power"),
Pair("Thriller", "thriller"), Pair("Supernatural", "supernatural"),
Pair("Tragedy", "tragedy"), Pair("Suspense", "suspense"),
Pair("Vampire", "vampire"), Pair("Thriller", "thriller"),
Pair("Webtoons", "webtoons"), Pair("Tragedy", "tragedy"),
Pair("Yuri", "yuri") Pair("Vampire", "vampire"),
)) Pair("Webtoons", "webtoons"),
Pair("Yuri", "yuri")
)
)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
Filter.Header("NOTE: sort and genre can't be combined and ignored when using text search!"), Filter.Header("NOTE: sort and genre can't be combined and ignored when using text search!"),
@ -384,15 +390,18 @@ class KomikGo : WPMangaStream("Komik GO (WP Manga Stream)", "https://komikgo.com
private class TextField(name: String, val key: String) : Filter.Text(name) private class TextField(name: String, val key: String) : Filter.Text(name)
private class SortBy : UriPartFilter("Sort by", arrayOf( private class SortBy : UriPartFilter(
Pair("Relevance", ""), "Sort by",
Pair("Latest", "latest"), arrayOf(
Pair("A-Z", "alphabet"), Pair("Relevance", ""),
Pair("Rating", "rating"), Pair("Latest", "latest"),
Pair("Trending", "trending"), Pair("A-Z", "alphabet"),
Pair("Most View", "views"), Pair("Rating", "rating"),
Pair("New", "new-manga") Pair("Trending", "trending"),
)) Pair("Most View", "views"),
Pair("New", "new-manga")
)
)
private class Status(name: String, val id: String = name) : Filter.TriState(name) private class Status(name: String, val id: String = name) : Filter.TriState(name)
private class StatusList(statuses: List<Status>) : Filter.Group<Status>("Status", statuses) private class StatusList(statuses: List<Status>) : Filter.Group<Status>("Status", statuses)

View File

@ -8,15 +8,15 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
abstract class Zbulu( abstract class Zbulu(
override val name: String, override val name: String,
@ -82,9 +82,9 @@ abstract class Zbulu(
filters.forEach { filter -> filters.forEach { filter ->
when (filter) { when (filter) {
is AuthorField -> { is AuthorField -> {
if (filter.state.isNotBlank()) { if (filter.state.isNotBlank()) {
ret = "$baseUrl/author/${filter.state.replace(" ", "-")}/page-$page" ret = "$baseUrl/author/${filter.state.replace(" ", "-")}/page-$page"
} }
} }
is GenreFilter -> { is GenreFilter -> {
if (filter.toUriPart().isNotBlank() && filter.state != 0) { if (filter.toUriPart().isNotBlank() && filter.state != 0) {
@ -193,7 +193,8 @@ abstract class Zbulu(
// [...document.querySelectorAll('.sub-menu li a')].map(a => `Pair("${a.textContent}", "${a.getAttribute('href')}")`).join(',\n') // [...document.querySelectorAll('.sub-menu li a')].map(a => `Pair("${a.textContent}", "${a.getAttribute('href')}")`).join(',\n')
// from $baseUrl // from $baseUrl
private class GenreFilter : UriPartFilter("Genres", private class GenreFilter : UriPartFilter(
"Genres",
arrayOf( arrayOf(
Pair("Choose a genre", ""), Pair("Choose a genre", ""),
Pair("Action", "action"), Pair("Action", "action"),

View File

@ -7,13 +7,13 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.MediaType import okhttp3.MediaType
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class AndromedaScans : ParsedHttpSource() { class AndromedaScans : ParsedHttpSource() {
override val name = "AndromedaScans" override val name = "AndromedaScans"

View File

@ -147,13 +147,16 @@ class MangaAe : ParsedHttpSource() {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
private class OrderByFilter : UriPartFilter("الترتيب حسب", arrayOf( private class OrderByFilter : UriPartFilter(
Pair("اختيار", ""), "الترتيب حسب",
Pair("اسم المانجا", "english_name"), arrayOf(
Pair("تاريخ النشر", "release_date"), Pair("اختيار", ""),
Pair("عدد الفصول", "chapter_count"), Pair("اسم المانجا", "english_name"),
Pair("الحالة", "status") Pair("تاريخ النشر", "release_date"),
)) Pair("عدد الفصول", "chapter_count"),
Pair("الحالة", "status")
)
)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
OrderByFilter() OrderByFilter()

View File

@ -6,10 +6,10 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaZen : ParsedHttpSource() { class MangaZen : ParsedHttpSource() {

View File

@ -8,12 +8,12 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.util.concurrent.TimeUnit
class TeamX : ParsedHttpSource() { class TeamX : ParsedHttpSource() {
@ -44,8 +44,10 @@ class TeamX : ParsedHttpSource() {
return SManga.create().apply { return SManga.create().apply {
title = element.select(titleSelector).text() title = element.select(titleSelector).text()
setUrlWithoutDomain(element.select("a").first().attr("href")) setUrlWithoutDomain(element.select("a").first().attr("href"))
thumbnail_url = element.select("img").let { if (it.hasAttr("data-src")) thumbnail_url = element.select("img").let {
it.attr("abs:data-src") else it.attr("abs:src") } if (it.hasAttr("data-src"))
it.attr("abs:data-src") else it.attr("abs:src")
}
} }
} }
@ -106,8 +108,10 @@ class TeamX : ParsedHttpSource() {
title = info.select("div.col-md-9").text() title = info.select("div.col-md-9").text()
description = info.select("div.story p").text() description = info.select("div.story p").text()
genre = info.select("div.genre a").joinToString { it.text() } genre = info.select("div.genre a").joinToString { it.text() }
thumbnail_url = info.select("img").let { if (it.hasAttr("data-src")) thumbnail_url = info.select("img").let {
it.attr("abs:data-src") else it.attr("abs:src") } if (it.hasAttr("data-src"))
it.attr("abs:data-src") else it.attr("abs:src")
}
} }
} }
} }
@ -128,8 +132,14 @@ class TeamX : ParsedHttpSource() {
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
return document.select("div#translationPageall img").mapIndexed { i, img -> return document.select("div#translationPageall img").mapIndexed { i, img ->
Page(i, "", img.let { if (it.hasAttr("data-src")) Page(
it.attr("abs:data-src") else it.attr("abs:src") }) i,
"",
img.let {
if (it.hasAttr("data-src"))
it.attr("abs:data-src") else it.attr("abs:src")
}
)
} }
} }

View File

@ -14,10 +14,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -26,6 +22,10 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class MangaTube : ParsedHttpSource() { class MangaTube : ParsedHttpSource() {
@ -156,7 +156,7 @@ class MangaTube : ParsedHttpSource() {
} }
date_upload = element.select("p.chapter-date").text().let { date_upload = element.select("p.chapter-date").text().let {
try { try {
SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).parse(it.substringAfter(" ")).time SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).parse(it.substringAfter(" "))?.time ?: 0L
} catch (_: ParseException) { } catch (_: ParseException) {
0L 0L
} }

View File

@ -6,13 +6,13 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.text.SimpleDateFormat
import java.util.Locale
class WieManga : ParsedHttpSource() { class WieManga : ParsedHttpSource() {
@ -119,7 +119,7 @@ class WieManga : ParsedHttpSource() {
} }
private fun parseChapterDate(date: String): Long { private fun parseChapterDate(date: String): Long {
return SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefault()).parse(date).time return SimpleDateFormat("yyyy-MM-dd hh:mm:ss", Locale.getDefault()).parse(date)?.time ?: 0L
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {

View File

@ -47,8 +47,10 @@ class CloneManga : ParsedHttpSource() {
status = SManga.UNKNOWN status = SManga.UNKNOWN
url = element.select("a").first().attr("href") url = element.select("a").first().attr("href")
description = element.select("h4").first()?.text() ?: "" description = element.select("h4").first()?.text() ?: ""
thumbnail_url = baseUrl + attr.substring(attr.indexOf("site/themes"), thumbnail_url = baseUrl + attr.substring(
attr.indexOf(")")) attr.indexOf("site/themes"),
attr.indexOf(")")
)
} }
} }
@ -65,8 +67,10 @@ class CloneManga : ParsedHttpSource() {
val document = response.asJsoup() val document = response.asJsoup()
val series = document.location() val series = document.location()
val numChapters = Regex( val numChapters = Regex(
pattern = "&page=(.*)&lang=").findAll( pattern = "&page=(.*)&lang="
input = document.getElementsByTag("script")[3].toString()) ).findAll(
input = document.getElementsByTag("script")[3].toString()
)
.elementAt(3).destructured.component1() .elementAt(3).destructured.component1()
.toInt() .toInt()
val chapters = ArrayList<SChapter>() val chapters = ArrayList<SChapter>()

View File

@ -8,9 +8,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.net.URLEncoder
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.MediaType import okhttp3.MediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -19,6 +16,9 @@ import okhttp3.RequestBody
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URLEncoder
import java.util.Calendar
import java.util.Locale
class Comicastle : ParsedHttpSource() { class Comicastle : ParsedHttpSource() {

View File

@ -8,6 +8,11 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.ParseException import java.text.ParseException
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.ArrayList import java.util.ArrayList
@ -15,11 +20,6 @@ import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.regex.Pattern import java.util.regex.Pattern
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
class ComicExtra : ParsedHttpSource() { class ComicExtra : ParsedHttpSource() {
@ -141,15 +141,13 @@ class ComicExtra : ParsedHttpSource() {
} }
private fun dateParse(dateAsString: String): Long { private fun dateParse(dateAsString: String): Long {
val date: Date val date: Date? = try {
date = try {
SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).parse(dateAsString.replace(Regex("(st|nd|rd|th)"), "")) SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).parse(dateAsString.replace(Regex("(st|nd|rd|th)"), ""))
} catch (e: ParseException) { } catch (e: ParseException) {
val m = datePattern.matcher(dateAsString) val m = datePattern.matcher(dateAsString)
if (dateAsString != "Today" && m.matches()) { if (dateAsString != "Today" && m.matches()) {
val amount = m.group(1).toInt() val amount = m.group(1)!!.toInt()
Calendar.getInstance().apply { Calendar.getInstance().apply {
add(Calendar.DATE, -amount) add(Calendar.DATE, -amount)
}.time }.time
@ -158,7 +156,7 @@ class ComicExtra : ParsedHttpSource() {
} else return 0 } else return 0
} }
return date.time return date?.time ?: 0L
} }
override fun pageListRequest(chapter: SChapter): Request { override fun pageListRequest(chapter: SChapter): Request {

View File

@ -11,14 +11,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Dilbert : ParsedHttpSource() { class Dilbert : ParsedHttpSource() {
@ -46,20 +46,26 @@ class Dilbert : ParsedHttpSource() {
override fun fetchPopularManga(page: Int): Observable<MangasPage> { override fun fetchPopularManga(page: Int): Observable<MangasPage> {
val currentYear = Calendar.getInstance().get(Calendar.YEAR) val currentYear = Calendar.getInstance().get(Calendar.YEAR)
return Observable.just(MangasPage((currentYear downTo 1989).map { return Observable.just(
SManga.create().apply { MangasPage(
url = "?$it" (currentYear downTo 1989).map {
title = "$name ($it)" SManga.create().apply {
artist = "Scott Adams" url = "?$it"
author = "Scott Adams" title = "$name ($it)"
status = if (it < currentYear) SManga.COMPLETED else SManga.ONGOING artist = "Scott Adams"
description = """ author = "Scott Adams"
status = if (it < currentYear) SManga.COMPLETED else SManga.ONGOING
description =
"""
A satirical comic strip featuring Dilbert, a competent, but seldom recognized engineer. A satirical comic strip featuring Dilbert, a competent, but seldom recognized engineer.
(This entry includes all the chapters published in $it.) (This entry includes all the chapters published in $it.)
""".trimIndent() """.trimIndent()
thumbnail_url = "https://dilbert.com/assets/favicon/favicon-196x196-cf4d86b485e628a034ab8b961c1c3520b5969252400a80b9eed544d99403e037.png" thumbnail_url = "https://dilbert.com/assets/favicon/favicon-196x196-cf4d86b485e628a034ab8b961c1c3520b5969252400a80b9eed544d99403e037.png"
} }
}, false)) },
false
)
)
} }
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) = fetchPopularManga(page) override fun fetchSearchManga(page: Int, query: String, filters: FilterList) = fetchPopularManga(page)
@ -74,7 +80,7 @@ class Dilbert : ParsedHttpSource() {
val date = element.first(".comic-title-date").text() val date = element.first(".comic-title-date").text()
url = element.first(".img-comic-link").attr("href") url = element.first(".img-comic-link").attr("href")
name = element.first(".comic-title-name").text().ifBlank { date } name = element.first(".comic-title-name").text().ifBlank { date }
date_upload = dateFormat.parse(date).time date_upload = dateFormat.parse(date)?.time ?: 0L
} }
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
@ -93,7 +99,8 @@ class Dilbert : ParsedHttpSource() {
if (pages != null) for (page in 2..pages) getChapters(page) if (pages != null) for (page in 2..pages) getChapters(page)
return Observable.just( return Observable.just(
chapters.sortedBy(SChapter::date_upload).mapIndexed { chapters.sortedBy(SChapter::date_upload).mapIndexed {
i, ch -> ch.apply { chapter_number = i + 1f } i, ch ->
ch.apply { chapter_number = i + 1f }
}.reversed() }.reversed()
) )
} }

View File

@ -50,10 +50,12 @@ class DynastyDoujins : DynastyScans() {
val chapters = document.select(chapterListSelector()).map { chapterFromElement(it) }.toMutableList() val chapters = document.select(chapterListSelector()).map { chapterFromElement(it) }.toMutableList()
document.select("a.thumbnail img").let { images -> document.select("a.thumbnail img").let { images ->
if (images.isNotEmpty()) chapters.add(SChapter.create().apply { if (images.isNotEmpty()) chapters.add(
name = "Images" SChapter.create().apply {
setUrlWithoutDomain(document.location() + "/images") name = "Images"
}) setUrlWithoutDomain(document.location() + "/images")
}
)
} }
return chapters return chapters

View File

@ -8,9 +8,10 @@ class DynastyFactory : SourceFactory {
} }
fun getAllDynasty() = fun getAllDynasty() =
listOf( listOf(
DynastyAnthologies(), DynastyAnthologies(),
DynastyChapters(), DynastyChapters(),
DynastyDoujins(), DynastyDoujins(),
DynastyIssues(), DynastyIssues(),
DynastySeries()) DynastySeries()
)

View File

@ -8,9 +8,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Locale
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.json.JSONArray import org.json.JSONArray
@ -19,6 +16,9 @@ import org.jsoup.nodes.Element
import org.jsoup.nodes.Node import org.jsoup.nodes.Node
import org.jsoup.nodes.TextNode import org.jsoup.nodes.TextNode
import org.jsoup.select.Elements import org.jsoup.select.Elements
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Locale
abstract class DynastyScans : ParsedHttpSource() { abstract class DynastyScans : ParsedHttpSource() {
@ -70,8 +70,10 @@ abstract class DynastyScans : ParsedHttpSource() {
override fun searchMangaNextPageSelector() = "div.pagination > ul > li.active + li > a" override fun searchMangaNextPageSelector() = "div.pagination > ul > li.active + li > a"
private fun buildListfromResponse(): List<Node> { private fun buildListfromResponse(): List<Node> {
return client.newCall(Request.Builder().headers(headers) return client.newCall(
.url(popularMangaInitialUrl()).build()).execute().asJsoup() Request.Builder().headers(headers)
.url(popularMangaInitialUrl()).build()
).execute().asJsoup()
.select("div#main").first { it.hasText() }.childNodes() .select("div#main").first { it.hasText() }.childNodes()
} }
@ -170,9 +172,9 @@ abstract class DynastyScans : ParsedHttpSource() {
val imageUrls = JSONArray("[$imageUrl]") val imageUrls = JSONArray("[$imageUrl]")
(0 until imageUrls.length()) (0 until imageUrls.length())
.map { imageUrls.getJSONObject(it) } .map { imageUrls.getJSONObject(it) }
.map { baseUrl + it.get("image") } .map { baseUrl + it.get("image") }
.forEach { pages.add(Page(pages.size, "", it)) } .forEach { pages.add(Page(pages.size, "", it)) }
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() e.printStackTrace()
} }
@ -193,32 +195,32 @@ abstract class DynastyScans : ParsedHttpSource() {
} }
if (type == "src") { if (type == "src") {
nodes nodes
.filter { it is Element && it.hasClass("thumbnails") } .filter { it is Element && it.hasClass("thumbnails") }
.flatMap { it.childNodes() } .flatMap { it.childNodes() }
.filterIsInstance<Element>() .filterIsInstance<Element>()
.filter { it.hasClass("span2") } .filter { it.hasClass("span2") }
.forEach { this.add(it.child(0).child(0).attr(type)) } .forEach { this.add(it.child(0).child(0).attr(type)) }
} }
if (type == "href") { if (type == "href") {
nodes nodes
.filter { it is Element && it.hasClass("thumbnails") } .filter { it is Element && it.hasClass("thumbnails") }
.flatMap { it.childNodes() } .flatMap { it.childNodes() }
.filterIsInstance<Element>() .filterIsInstance<Element>()
.filter { it.hasClass("span2") } .filter { it.hasClass("span2") }
.forEach { this.add(it.child(0).attr(type)) } .forEach { this.add(it.child(0).attr(type)) }
} }
} }
fun indexOfPartial(partial: String): Int { fun indexOfPartial(partial: String): Int {
return (0..this.lastIndex).firstOrNull { this[it].contains(partial) } return (0..this.lastIndex).firstOrNull { this[it].contains(partial) }
?: -1 ?: -1
} }
fun getItem(partial: String): String { fun getItem(partial: String): String {
return (0..this.lastIndex) return (0..this.lastIndex)
.firstOrNull { super.get(it).contains(partial) } .firstOrNull { super.get(it).contains(partial) }
?.let { super.get(it) } ?.let { super.get(it) }
?: "" ?: ""
} }
} }

View File

@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.util.Calendar
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -19,6 +18,7 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.util.Calendar
@Nsfw @Nsfw
class Eggporncomics : ParsedHttpSource() { class Eggporncomics : ParsedHttpSource() {
@ -129,21 +129,25 @@ class Eggporncomics : ParsedHttpSource() {
override fun mangaDetailsParse(document: Document): SManga { override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply { return SManga.create().apply {
thumbnail_url = document.select(pageListSelector).first().toFullSizeImage() thumbnail_url = document.select(pageListSelector).first().toFullSizeImage()
description = document.select("div.links ul").joinToString("\n") { element -> element.select("a") description = document.select("div.links ul").joinToString("\n") { element ->
.joinToString(prefix = element.select("span").text().replace(descriptionPrefixRegex, ": ")) { it.text() } } element.select("a")
.joinToString(prefix = element.select("span").text().replace(descriptionPrefixRegex, ": ")) { it.text() }
}
} }
} }
// Chapters // Chapters
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
return listOf(SChapter.create().apply { return listOf(
setUrlWithoutDomain(response.request().url().toString()) SChapter.create().apply {
name = "Chapter" setUrlWithoutDomain(response.request().url().toString())
date_upload = response.asJsoup().select("div.info > div.meta li:contains(days ago)").firstOrNull() name = "Chapter"
?.let { Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -(it.text().substringBefore(" ").toIntOrNull() ?: 0)) }.timeInMillis } date_upload = response.asJsoup().select("div.info > div.meta li:contains(days ago)").firstOrNull()
?: 0 ?.let { Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -(it.text().substringBefore(" ").toIntOrNull() ?: 0)) }.timeInMillis }
}) ?: 0
}
)
} }
override fun chapterListSelector() = throw UnsupportedOperationException("Not used") override fun chapterListSelector() = throw UnsupportedOperationException("Not used")

View File

@ -8,14 +8,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
class Explosm : HttpSource() { class Explosm : HttpSource() {
@ -92,7 +92,7 @@ class Explosm : HttpSource() {
element.select("div#comic-author").text().let { cName -> element.select("div#comic-author").text().let { cName ->
name = cName name = cName
date_upload = SimpleDateFormat("yyyy.MM.dd", Locale.getDefault()) date_upload = SimpleDateFormat("yyyy.MM.dd", Locale.getDefault())
.parse(cName.substringBefore(" ")).time .parse(cName.substringBefore(" "))?.time ?: 0L
} }
} }
} }

View File

@ -46,7 +46,8 @@ class GunnerkriggCourt : ParsedHttpSource() {
return Observable.just(manga) return Observable.just(manga)
} }
override fun chapterListSelector() = """div.chapters option[value~=\d*]""" override fun chapterListSelector() =
"""div.chapters option[value~=\d*]"""
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
return super.chapterListParse(response).reversed() return super.chapterListParse(response).reversed()

View File

@ -15,9 +15,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import java.io.IOException
import java.util.HashMap
import java.util.concurrent.TimeUnit
import okhttp3.Call import okhttp3.Call
import okhttp3.Callback import okhttp3.Callback
import okhttp3.Headers import okhttp3.Headers
@ -29,6 +26,9 @@ import org.json.JSONObject
import rx.Observable import rx.Observable
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.util.HashMap
import java.util.concurrent.TimeUnit
open class Guya : ConfigurableSource, HttpSource() { open class Guya : ConfigurableSource, HttpSource() {
@ -40,10 +40,13 @@ open class Guya : ConfigurableSource, HttpSource() {
private val scanlatorCacheUrl = "$baseUrl/api/get_all_groups" private val scanlatorCacheUrl = "$baseUrl/api/get_all_groups"
override fun headersBuilder() = Headers.Builder().apply { override fun headersBuilder() = Headers.Builder().apply {
add("User-Agent", "(Android ${Build.VERSION.RELEASE}; " + add(
"${Build.MANUFACTURER} ${Build.MODEL}) " + "User-Agent",
"Tachiyomi/${BuildConfig.VERSION_NAME} " + "(Android ${Build.VERSION.RELEASE}; " +
Build.ID) "${Build.MANUFACTURER} ${Build.MODEL}) " +
"Tachiyomi/${BuildConfig.VERSION_NAME} " +
Build.ID
)
} }
private val scanlators: ScanlatorStore = ScanlatorStore() private val scanlators: ScanlatorStore = ScanlatorStore()
@ -131,9 +134,12 @@ open class Guya : ConfigurableSource, HttpSource() {
metadata.put("chapter", chapterNum) metadata.put("chapter", chapterNum)
metadata.put("scanlator", scanlators.getKeyFromValue(chapter.scanlator.toString())) metadata.put("scanlator", scanlators.getKeyFromValue(chapter.scanlator.toString()))
metadata.put("slug", json.getString("slug")) metadata.put("slug", json.getString("slug"))
metadata.put("folder", json.getJSONObject("chapters") metadata.put(
.getJSONObject(chapterNum) "folder",
.getString("folder")) json.getJSONObject("chapters")
.getJSONObject(chapterNum)
.getString("folder")
)
return parsePageFromJson(pages, metadata) return parsePageFromJson(pages, metadata)
} }
@ -320,10 +326,16 @@ open class Guya : ConfigurableSource, HttpSource() {
val pageArray = ArrayList<Page>() val pageArray = ArrayList<Page>()
for (i in 0 until pages.length()) { for (i in 0 until pages.length()) {
val page = Page(i + 1, "", pageBuilder(metadata.getString("slug"), val page = Page(
metadata.getString("folder"), i + 1,
pages[i].toString(), "",
metadata.getString("scanlator"))) pageBuilder(
metadata.getString("slug"),
metadata.getString("folder"),
pages[i].toString(),
metadata.getString("scanlator")
)
)
pageArray.add(page) pageArray.add(page)
} }

View File

@ -9,13 +9,13 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.io.IOException
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.io.IOException
@Nsfw @Nsfw
class HBrowse : ParsedHttpSource() { class HBrowse : ParsedHttpSource() {
@ -185,7 +185,7 @@ class HBrowse : ParsedHttpSource() {
override fun getFilterList(): FilterList { override fun getFilterList(): FilterList {
return FilterList( return FilterList(
listOf(Filter.Header("Can't combine with text search!"), Filter.Separator()) + listOf(Filter.Header("Can't combine with text search!"), Filter.Separator()) +
advFilterMap.map { AdvancedFilter(getAdvTriStateList(it.key, it.value.split(", "))) } advFilterMap.map { AdvancedFilter(getAdvTriStateList(it.key, it.value.split(", "))) }
) )
} }

View File

@ -12,9 +12,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.lang.UnsupportedOperationException
import java.util.Calendar
import java.util.regex.Pattern
import okhttp3.FormBody import okhttp3.FormBody
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -22,6 +19,9 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.lang.UnsupportedOperationException
import java.util.Calendar
import java.util.regex.Pattern
@Nsfw @Nsfw
class Hentai2Read : ParsedHttpSource() { class Hentai2Read : ParsedHttpSource() {
@ -182,7 +182,7 @@ class Hentai2Read : ParsedHttpSource() {
chapter.date_upload = element.select("div > small").text()?.let { chapter.date_upload = element.select("div > small").text()?.let {
val matcher = chapterDatePattern.matcher(it) val matcher = chapterDatePattern.matcher(it)
if (matcher.find()) { if (matcher.find()) {
parseChapterDate(matcher.group(1)) parseChapterDate(matcher.group(1)!!)
} else { } else {
0L 0L
} }
@ -216,7 +216,7 @@ class Hentai2Read : ParsedHttpSource() {
val m = pagesUrlPattern.matcher(response.body()!!.string()) val m = pagesUrlPattern.matcher(response.body()!!.string())
var i = 0 var i = 0
while (m.find()) { while (m.find()) {
m.group(1).split(",").forEach { m.group(1)?.split(",")?.forEach {
pages.add(Page(i++, "", imageBaseUrl + it.trim('"').replace("""\/""", "/"))) pages.add(Page(i++, "", imageBaseUrl + it.trim('"').replace("""\/""", "/")))
} }
} }
@ -245,27 +245,27 @@ class Hentai2Read : ParsedHttpSource() {
} }
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
SortOrder(getSortOrder()), SortOrder(getSortOrder()),
MangaNameSelect(), MangaNameSelect(),
Filter.Separator(), Filter.Separator(),
ArtistName(), ArtistName(),
ArtistNameSelect(), ArtistNameSelect(),
Filter.Separator(), Filter.Separator(),
CharacterName(), CharacterName(),
CharacterNameSelect(), CharacterNameSelect(),
Filter.Separator(), Filter.Separator(),
ReleaseYear(), ReleaseYear(),
ReleaseYearSelect(), ReleaseYearSelect(),
Filter.Separator(), Filter.Separator(),
Status(), Status(),
Filter.Separator(), Filter.Separator(),
TagSearchMode(), TagSearchMode(),
Filter.Separator(), Filter.Separator(),
TagList("Categories", getCategoryList()), TagList("Categories", getCategoryList()),
Filter.Separator(), Filter.Separator(),
TagList("Tags", getTagList()), TagList("Tags", getTagList()),
Filter.Separator(), Filter.Separator(),
TagList("Doujins", getDoujinList()) TagList("Doujins", getDoujinList())
) )
private fun getSortOrder() = arrayOf( private fun getSortOrder() = arrayOf(

View File

@ -109,13 +109,15 @@ class HentaiFox : ParsedHttpSource() {
// Chapters // Chapters
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
return listOf(SChapter.create().apply { return listOf(
name = "Chapter" SChapter.create().apply {
// page path with a marker at the end name = "Chapter"
url = "${response.request().url().toString().replace("/gallery/", "/g/")}#" // page path with a marker at the end
// number of pages url = "${response.request().url().toString().replace("/gallery/", "/g/")}#"
url += response.asJsoup().select("[id=load_pages]").attr("value") // number of pages
}) url += response.asJsoup().select("[id=load_pages]").attr("value")
}
)
} }
override fun chapterListSelector() = throw UnsupportedOperationException("Not used") override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
@ -146,59 +148,62 @@ class HentaiFox : ParsedHttpSource() {
) )
// Top 50 tags // Top 50 tags
private class GenreFilter : UriPartFilter("Category", arrayOf( private class GenreFilter : UriPartFilter(
Pair("<select>", "---"), "Category",
Pair("Big breasts", "big-breasts"), arrayOf(
Pair("Sole female", "sole-female"), Pair("<select>", "---"),
Pair("Sole male", "sole-male"), Pair("Big breasts", "big-breasts"),
Pair("Anal", "anal"), Pair("Sole female", "sole-female"),
Pair("Nakadashi", "nakadashi"), Pair("Sole male", "sole-male"),
Pair("Group", "group"), Pair("Anal", "anal"),
Pair("Stockings", "stockings"), Pair("Nakadashi", "nakadashi"),
Pair("Blowjob", "blowjob"), Pair("Group", "group"),
Pair("Schoolgirl uniform", "schoolgirl-uniform"), Pair("Stockings", "stockings"),
Pair("Rape", "rape"), Pair("Blowjob", "blowjob"),
Pair("Lolicon", "lolicon"), Pair("Schoolgirl uniform", "schoolgirl-uniform"),
Pair("Glasses", "glasses"), Pair("Rape", "rape"),
Pair("Defloration", "defloration"), Pair("Lolicon", "lolicon"),
Pair("Ahegao", "ahegao"), Pair("Glasses", "glasses"),
Pair("Incest", "incest"), Pair("Defloration", "defloration"),
Pair("Shotacon", "shotacon"), Pair("Ahegao", "ahegao"),
Pair("X-ray", "x-ray"), Pair("Incest", "incest"),
Pair("Bondage", "bondage"), Pair("Shotacon", "shotacon"),
Pair("Full color", "full-color"), Pair("X-ray", "x-ray"),
Pair("Double penetration", "double-penetration"), Pair("Bondage", "bondage"),
Pair("Femdom", "femdom"), Pair("Full color", "full-color"),
Pair("Milf", "milf"), Pair("Double penetration", "double-penetration"),
Pair("Yaoi", "yaoi"), Pair("Femdom", "femdom"),
Pair("Multi-work series", "multi-work-series"), Pair("Milf", "milf"),
Pair("Schoolgirl", "schoolgirl"), Pair("Yaoi", "yaoi"),
Pair("Mind break", "mind-break"), Pair("Multi-work series", "multi-work-series"),
Pair("Paizuri", "paizuri"), Pair("Schoolgirl", "schoolgirl"),
Pair("Mosaic censorship", "mosaic-censorship"), Pair("Mind break", "mind-break"),
Pair("Impregnation", "impregnation"), Pair("Paizuri", "paizuri"),
Pair("Males only", "males-only"), Pair("Mosaic censorship", "mosaic-censorship"),
Pair("Sex toys", "sex-toys"), Pair("Impregnation", "impregnation"),
Pair("Sister", "sister"), Pair("Males only", "males-only"),
Pair("Dark skin", "dark-skin"), Pair("Sex toys", "sex-toys"),
Pair("Ffm threesome", "ffm-threesome"), Pair("Sister", "sister"),
Pair("Hairy", "hairy"), Pair("Dark skin", "dark-skin"),
Pair("Cheating", "cheating"), Pair("Ffm threesome", "ffm-threesome"),
Pair("Sweating", "sweating"), Pair("Hairy", "hairy"),
Pair("Yuri", "yuri"), Pair("Cheating", "cheating"),
Pair("Netorare", "netorare"), Pair("Sweating", "sweating"),
Pair("Full censorship", "full-censorship"), Pair("Yuri", "yuri"),
Pair("Schoolboy uniform", "schoolboy-uniform"), Pair("Netorare", "netorare"),
Pair("Dilf", "dilf"), Pair("Full censorship", "full-censorship"),
Pair("Big penis", "big-penis"), Pair("Schoolboy uniform", "schoolboy-uniform"),
Pair("Futanari", "futanari"), Pair("Dilf", "dilf"),
Pair("Swimsuit", "swimsuit"), Pair("Big penis", "big-penis"),
Pair("Collar", "collar"), Pair("Futanari", "futanari"),
Pair("Uncensored", "uncensored"), Pair("Swimsuit", "swimsuit"),
Pair("Big ass", "big-ass"), Pair("Collar", "collar"),
Pair("Story arc", "story-arc"), Pair("Uncensored", "uncensored"),
Pair("Teacher", "teacher") Pair("Big ass", "big-ass"),
)) Pair("Story arc", "story-arc"),
Pair("Teacher", "teacher")
)
)
private open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {

View File

@ -8,11 +8,11 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.net.URLEncoder
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.net.URLEncoder
@Nsfw @Nsfw
class HentaiNexus : ParsedHttpSource() { class HentaiNexus : ParsedHttpSource() {

View File

@ -11,10 +11,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Call import okhttp3.Call
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -22,6 +18,10 @@ import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
class Hiveworks : ParsedHttpSource() { class Hiveworks : ParsedHttpSource() {
@ -290,84 +290,104 @@ class Hiveworks : ParsedHttpSource() {
fun addToUri(uri: Uri.Builder) fun addToUri(uri: Uri.Builder)
} }
private class UpdateDay : UriSelectFilter("Update Day", "update-day", arrayOf( private class UpdateDay : UriSelectFilter(
Pair("all", "All"), "Update Day",
Pair("monday", "Monday"), "update-day",
Pair("tuesday", "Tuesday"), arrayOf(
Pair("wednesday", "Wednesday"), Pair("all", "All"),
Pair("thursday", "Thursday"), Pair("monday", "Monday"),
Pair("friday", "Friday"), Pair("tuesday", "Tuesday"),
Pair("saturday", "Saturday"), Pair("wednesday", "Wednesday"),
Pair("sunday", "Sunday") Pair("thursday", "Thursday"),
)) Pair("friday", "Friday"),
Pair("saturday", "Saturday"),
Pair("sunday", "Sunday")
)
)
private class RatingFilter : UriSelectFilter("Rating", "age", arrayOf( private class RatingFilter : UriSelectFilter(
Pair("all", "All"), "Rating",
Pair("everyone", "Everyone"), "age",
Pair("teen", "Teen"), arrayOf(
Pair("young-adult", "Young Adult"), Pair("all", "All"),
Pair("mature", "Mature") Pair("everyone", "Everyone"),
)) Pair("teen", "Teen"),
Pair("young-adult", "Young Adult"),
Pair("mature", "Mature")
)
)
private class GenreFilter : UriSelectFilter("Genre", "genre", arrayOf( private class GenreFilter : UriSelectFilter(
Pair("all", "All"), "Genre",
Pair("action/adventure", "Action/Adventure"), "genre",
Pair("animated", "Animated"), arrayOf(
Pair("autobio", "Autobio"), Pair("all", "All"),
Pair("comedy", "Comedy"), Pair("action/adventure", "Action/Adventure"),
Pair("drama", "Drama"), Pair("animated", "Animated"),
Pair("dystopian", "Dystopian"), Pair("autobio", "Autobio"),
Pair("fairytale", "Fairytale"), Pair("comedy", "Comedy"),
Pair("fantasy", "Fantasy"), Pair("drama", "Drama"),
Pair("finished", "Finished"), Pair("dystopian", "Dystopian"),
Pair("historical-fiction", "Historical Fiction"), Pair("fairytale", "Fairytale"),
Pair("horror", "Horror"), Pair("fantasy", "Fantasy"),
Pair("lgbt", "LGBT"), Pair("finished", "Finished"),
Pair("mystery", "Mystery"), Pair("historical-fiction", "Historical Fiction"),
Pair("romance", "Romance"), Pair("horror", "Horror"),
Pair("sci-fi", "Science Fiction"), Pair("lgbt", "LGBT"),
Pair("slice-of-life", "Slice of Life"), Pair("mystery", "Mystery"),
Pair("steampunk", "Steampunk"), Pair("romance", "Romance"),
Pair("superhero", "Superhero"), Pair("sci-fi", "Science Fiction"),
Pair("urban-fantasy", "Urban Fantasy") Pair("slice-of-life", "Slice of Life"),
)) Pair("steampunk", "Steampunk"),
Pair("superhero", "Superhero"),
Pair("urban-fantasy", "Urban Fantasy")
)
)
private class TitleFilter : UriSelectFilter("Title", "alpha", arrayOf( private class TitleFilter : UriSelectFilter(
Pair("all", "All"), "Title",
Pair("a", "A"), "alpha",
Pair("b", "B"), arrayOf(
Pair("c", "C"), Pair("all", "All"),
Pair("d", "D"), Pair("a", "A"),
Pair("e", "E"), Pair("b", "B"),
Pair("f", "F"), Pair("c", "C"),
Pair("g", "G"), Pair("d", "D"),
Pair("h", "H"), Pair("e", "E"),
Pair("i", "I"), Pair("f", "F"),
Pair("j", "J"), Pair("g", "G"),
Pair("k", "K"), Pair("h", "H"),
Pair("l", "L"), Pair("i", "I"),
Pair("m", "M"), Pair("j", "J"),
Pair("n", "N"), Pair("k", "K"),
Pair("o", "O"), Pair("l", "L"),
Pair("p", "P"), Pair("m", "M"),
Pair("q", "Q"), Pair("n", "N"),
Pair("r", "R"), Pair("o", "O"),
Pair("s", "S"), Pair("p", "P"),
Pair("t", "T"), Pair("q", "Q"),
Pair("u", "U"), Pair("r", "R"),
Pair("v", "V"), Pair("s", "S"),
Pair("w", "W"), Pair("t", "T"),
Pair("x", "X"), Pair("u", "U"),
Pair("y", "Y"), Pair("v", "V"),
Pair("z", "Z"), Pair("w", "W"),
Pair("numbers-symbols", "Numbers / Symbols") Pair("x", "X"),
)) Pair("y", "Y"),
Pair("z", "Z"),
Pair("numbers-symbols", "Numbers / Symbols")
)
)
private class SortFilter : UriSelectFilter("Sort By", "sortby", arrayOf( private class SortFilter : UriSelectFilter(
Pair("none", "None"), "Sort By",
Pair("a-z", "A-Z"), "sortby",
Pair("z-a", "Z-A") arrayOf(
)) Pair("none", "None"),
Pair("a-z", "A-Z"),
Pair("z-a", "Z-A")
)
)
// Other Code // Other Code

View File

@ -13,13 +13,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class Honkaiimpact : ParsedHttpSource() { class Honkaiimpact : ParsedHttpSource() {

View File

@ -15,12 +15,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.io.IOException
import java.net.URLDecoder
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Credentials import okhttp3.Credentials
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -30,6 +24,12 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.io.IOException
import java.net.URLDecoder
import java.net.URLEncoder
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Madokami : ConfigurableSource, ParsedHttpSource() { class Madokami : ConfigurableSource, ParsedHttpSource() {
override val name = "Madokami" override val name = "Madokami"
@ -145,7 +145,7 @@ class Madokami : ConfigurableSource, ParsedHttpSource() {
} }
chapter.date_upload = newDate.time.time chapter.date_upload = newDate.time.time
} else { } else {
chapter.date_upload = dateFormat.parse(date).time chapter.date_upload = dateFormat.parse(date)?.time ?: 0L
} }
return chapter return chapter
} }

View File

@ -8,14 +8,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class mangacruzers : ParsedHttpSource() { class mangacruzers : ParsedHttpSource() {
@ -70,16 +70,16 @@ class mangacruzers : ParsedHttpSource() {
override fun latestUpdatesFromElement(element: Element) = mangaFromElement(element) override fun latestUpdatesFromElement(element: Element) = mangaFromElement(element)
override fun searchMangaFromElement(element: Element) = mangaFromElement(element) override fun searchMangaFromElement(element: Element) = mangaFromElement(element)
private fun mangaFromElement(element: Element): SManga { private fun mangaFromElement(element: Element): SManga {
val manga = SManga.create() val manga = SManga.create()
manga.url = element.select("a").attr("abs:href") manga.url = element.select("a").attr("abs:href")
manga.title = element.select("td").first().text().trim() manga.title = element.select("td").first().text().trim()
return manga return manga
} }
private fun parseDate(date: String): Long { private fun parseDate(date: String): Long {
return SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(date).time return SimpleDateFormat("MMM dd, yyyy", Locale.US).parse(date)?.time ?: 0L
} }
override fun chapterFromElement(element: Element) = SChapter.create().apply { override fun chapterFromElement(element: Element) = SChapter.create().apply {

View File

@ -13,11 +13,11 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import java.text.SimpleDateFormat
import java.util.Locale
class Mangadog : HttpSource() { class Mangadog : HttpSource() {
@ -32,7 +32,7 @@ class Mangadog : HttpSource() {
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/index/latestupdate/getUpdateResult?page=$page", headers) override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/index/latestupdate/getUpdateResult?page=$page", headers)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val uri = Uri.parse("$baseUrl/index/keywordsearch/index").buildUpon() val uri = Uri.parse("$baseUrl/index/keywordsearch/index").buildUpon()
.appendQueryParameter("query", query) .appendQueryParameter("query", query)
return GET(uri.toString(), headers) return GET(uri.toString(), headers)
} }
@ -122,7 +122,7 @@ class Mangadog : HttpSource() {
} }
private fun parseDate(date: String): Long { private fun parseDate(date: String): Long {
return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(date).time return SimpleDateFormat("yyyy-MM-dd", Locale.US).parse(date)?.time ?: 0L
} }
override fun mangaDetailsParse(response: Response): SManga { override fun mangaDetailsParse(response: Response): SManga {

View File

@ -7,15 +7,15 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
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
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangaeden : ParsedHttpSource() { class Mangaeden : ParsedHttpSource() {
@ -52,15 +52,18 @@ class Mangaeden : ParsedHttpSource() {
val url = HttpUrl.parse("$baseUrl/en/en-directory/")?.newBuilder()!!.addQueryParameter("title", query) val url = HttpUrl.parse("$baseUrl/en/en-directory/")?.newBuilder()!!.addQueryParameter("title", query)
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> (if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) { when (filter) {
is StatusList -> filter.state is StatusList ->
filter.state
.filter { it.state } .filter { it.state }
.map { it.id.toString() } .map { it.id.toString() }
.forEach { url.addQueryParameter("status", it) } .forEach { url.addQueryParameter("status", it) }
is Types -> filter.state is Types ->
filter.state
.filter { it.state } .filter { it.state }
.map { it.id.toString() } .map { it.id.toString() }
.forEach { url.addQueryParameter("type", it) } .forEach { url.addQueryParameter("type", it) }
is GenreList -> filter.state is GenreList ->
filter.state
.filter { !it.isIgnored() } .filter { !it.isIgnored() }
.forEach { genre -> url.addQueryParameter(if (genre.isIncluded()) "categoriesInc" else "categoriesExcl", genre.id) } .forEach { genre -> url.addQueryParameter(if (genre.isIncluded()) "categoriesInc" else "categoriesExcl", genre.id) }
is TextField -> url.addQueryParameter(filter.key, filter.state) is TextField -> url.addQueryParameter(filter.key, filter.state)
@ -129,11 +132,12 @@ class Mangaeden : ParsedHttpSource() {
set(Calendar.MILLISECOND, 0) set(Calendar.MILLISECOND, 0)
}.timeInMillis }.timeInMillis
} }
else -> try { else ->
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time try {
} catch (e: ParseException) { SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
0L } catch (e: ParseException) {
} 0L
}
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
@ -147,69 +151,72 @@ class Mangaeden : ParsedHttpSource() {
private class NamedId(name: String, val id: Int) : Filter.CheckBox(name) private class NamedId(name: String, val id: Int) : Filter.CheckBox(name)
private class Genre(name: String, val id: String) : Filter.TriState(name) private class Genre(name: String, val id: String) : Filter.TriState(name)
private class TextField(name: String, val key: String) : Filter.Text(name) private class TextField(name: String, val key: String) : Filter.Text(name)
private class OrderBy : Filter.Sort("Order by", arrayOf("Manga title", "Views", "Chapters", "Latest chapter"), private class OrderBy : Filter.Sort(
Selection(1, false)) "Order by",
arrayOf("Manga title", "Views", "Chapters", "Latest chapter"),
Selection(1, false)
)
private class StatusList(statuses: List<NamedId>) : Filter.Group<NamedId>("Stato", statuses) private class StatusList(statuses: List<NamedId>) : Filter.Group<NamedId>("Stato", statuses)
private class Types(types: List<NamedId>) : Filter.Group<NamedId>("Tipo", types) private class Types(types: List<NamedId>) : Filter.Group<NamedId>("Tipo", types)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
TextField("Author", "author"), TextField("Author", "author"),
TextField("Artist", "artist"), TextField("Artist", "artist"),
OrderBy(), OrderBy(),
Types(types()), Types(types()),
StatusList(statuses()), StatusList(statuses()),
GenreList(genres()) GenreList(genres())
) )
private fun types() = listOf( private fun types() = listOf(
NamedId("Japanese Manga", 0), NamedId("Japanese Manga", 0),
NamedId("Korean Manhwa", 1), NamedId("Korean Manhwa", 1),
NamedId("Chinese Manhua", 2), NamedId("Chinese Manhua", 2),
NamedId("Comic", 3), NamedId("Comic", 3),
NamedId("Doujinshi", 4) NamedId("Doujinshi", 4)
) )
private fun statuses() = listOf( private fun statuses() = listOf(
NamedId("Ongoing", 1), NamedId("Ongoing", 1),
NamedId("Completed", 2), NamedId("Completed", 2),
NamedId("Suspended", 0) NamedId("Suspended", 0)
) )
private fun genres() = listOf( private fun genres() = listOf(
Genre("Action", "4e70e91bc092255ef70016f8"), Genre("Action", "4e70e91bc092255ef70016f8"),
Genre("Adult", "4e70e92fc092255ef7001b94"), Genre("Adult", "4e70e92fc092255ef7001b94"),
Genre("Adventure", "4e70e918c092255ef700168e"), Genre("Adventure", "4e70e918c092255ef700168e"),
Genre("Comedy", "4e70e918c092255ef7001675"), Genre("Comedy", "4e70e918c092255ef7001675"),
Genre("Doujinshi", "4e70e928c092255ef7001a0a"), Genre("Doujinshi", "4e70e928c092255ef7001a0a"),
Genre("Drama", "4e70e918c092255ef7001693"), Genre("Drama", "4e70e918c092255ef7001693"),
Genre("Ecchi", "4e70e91ec092255ef700175e"), Genre("Ecchi", "4e70e91ec092255ef700175e"),
Genre("Fantasy", "4e70e918c092255ef7001676"), Genre("Fantasy", "4e70e918c092255ef7001676"),
Genre("Gender Bender", "4e70e921c092255ef700184b"), Genre("Gender Bender", "4e70e921c092255ef700184b"),
Genre("Harem", "4e70e91fc092255ef7001783"), Genre("Harem", "4e70e91fc092255ef7001783"),
Genre("Historical", "4e70e91ac092255ef70016d8"), Genre("Historical", "4e70e91ac092255ef70016d8"),
Genre("Horror", "4e70e919c092255ef70016a8"), Genre("Horror", "4e70e919c092255ef70016a8"),
Genre("Josei", "4e70e920c092255ef70017de"), Genre("Josei", "4e70e920c092255ef70017de"),
Genre("Martial Arts", "4e70e923c092255ef70018d0"), Genre("Martial Arts", "4e70e923c092255ef70018d0"),
Genre("Mature", "4e70e91bc092255ef7001705"), Genre("Mature", "4e70e91bc092255ef7001705"),
Genre("Mecha", "4e70e922c092255ef7001877"), Genre("Mecha", "4e70e922c092255ef7001877"),
Genre("Mystery", "4e70e918c092255ef7001681"), Genre("Mystery", "4e70e918c092255ef7001681"),
Genre("One Shot", "4e70e91dc092255ef7001747"), Genre("One Shot", "4e70e91dc092255ef7001747"),
Genre("Psychological", "4e70e919c092255ef70016a9"), Genre("Psychological", "4e70e919c092255ef70016a9"),
Genre("Romance", "4e70e918c092255ef7001677"), Genre("Romance", "4e70e918c092255ef7001677"),
Genre("School Life", "4e70e918c092255ef7001688"), Genre("School Life", "4e70e918c092255ef7001688"),
Genre("Sci-fi", "4e70e91bc092255ef7001706"), Genre("Sci-fi", "4e70e91bc092255ef7001706"),
Genre("Seinen", "4e70e918c092255ef700168b"), Genre("Seinen", "4e70e918c092255ef700168b"),
Genre("Shoujo", "4e70e918c092255ef7001667"), Genre("Shoujo", "4e70e918c092255ef7001667"),
Genre("Shounen", "4e70e918c092255ef700166f"), Genre("Shounen", "4e70e918c092255ef700166f"),
Genre("Slice of Life", "4e70e918c092255ef700167e"), Genre("Slice of Life", "4e70e918c092255ef700167e"),
Genre("Smut", "4e70e922c092255ef700185a"), Genre("Smut", "4e70e922c092255ef700185a"),
Genre("Sports", "4e70e91dc092255ef700172e"), Genre("Sports", "4e70e91dc092255ef700172e"),
Genre("Supernatural", "4e70e918c092255ef700166a"), Genre("Supernatural", "4e70e918c092255ef700166a"),
Genre("Tragedy", "4e70e918c092255ef7001672"), Genre("Tragedy", "4e70e918c092255ef7001672"),
Genre("Webtoons", "4e70ea70c092255ef7006d9c"), Genre("Webtoons", "4e70ea70c092255ef7006d9c"),
Genre("Yaoi", "4e70e91ac092255ef70016e5"), Genre("Yaoi", "4e70e91ac092255ef70016e5"),
Genre("Yuri", "4e70e92ac092255ef7001a57") Genre("Yuri", "4e70e92ac092255ef7001a57")
) )
} }

View File

@ -6,10 +6,10 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaFast : ParsedHttpSource() { class MangaFast : ParsedHttpSource() {
override val name = "MangaFast" override val name = "MangaFast"

View File

@ -8,14 +8,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class Mangafreak : ParsedHttpSource() { class Mangafreak : ParsedHttpSource() {
override val name: String = "Mangafreak" override val name: String = "Mangafreak"
@ -76,14 +76,16 @@ class Mangafreak : ParsedHttpSource() {
uri.appendPath("Genre") uri.appendPath("Genre")
when (filter) { when (filter) {
is GenreList -> { is GenreList -> {
uri.appendPath(filter.state.joinToString("") { uri.appendPath(
when (it.state) { filter.state.joinToString("") {
Filter.TriState.STATE_IGNORE -> "0" when (it.state) {
Filter.TriState.STATE_INCLUDE -> "1" Filter.TriState.STATE_IGNORE -> "0"
Filter.TriState.STATE_EXCLUDE -> "2" Filter.TriState.STATE_INCLUDE -> "1"
else -> "0" Filter.TriState.STATE_EXCLUDE -> "2"
else -> "0"
}
} }
}) )
} }
} }
uri.appendEncodedPath("Status/0/Type/0") uri.appendEncodedPath("Status/0/Type/0")
@ -120,7 +122,7 @@ class Mangafreak : ParsedHttpSource() {
date_upload = parseDate(element.select(" td:eq(1)").text()) date_upload = parseDate(element.select(" td:eq(1)").text())
} }
private fun parseDate(date: String): Long { private fun parseDate(date: String): Long {
return SimpleDateFormat("yyyy/MM/dd", Locale.US).parse(date).time return SimpleDateFormat("yyyy/MM/dd", Locale.US).parse(date)?.time ?: 0L
} }
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
return super.chapterListParse(response).reversed() return super.chapterListParse(response).reversed()
@ -144,7 +146,8 @@ class Mangafreak : ParsedHttpSource() {
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
GenreList(getGenreList())) GenreList(getGenreList())
)
private fun getGenreList() = listOf( private fun getGenreList() = listOf(
Genre("Act"), Genre("Act"),
Genre("Adult"), Genre("Adult"),
@ -185,5 +188,5 @@ class Mangafreak : ParsedHttpSource() {
Genre("Vampire"), Genre("Vampire"),
Genre("Yaoi"), Genre("Yaoi"),
Genre("Yuri") Genre("Yuri")
) )
} }

View File

@ -13,14 +13,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers import okhttp3.Headers
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.text.SimpleDateFormat
import java.util.Locale
class Mangahasu : ParsedHttpSource() { class Mangahasu : ParsedHttpSource() {
@ -195,18 +195,24 @@ class Mangahasu : ParsedHttpSource() {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
private class TypeFilter : UriPartFilter("Type", arrayOf( private class TypeFilter : UriPartFilter(
Pair("Any", ""), "Type",
Pair("Manga", "10"), arrayOf(
Pair("Manhwa", "12"), Pair("Any", ""),
Pair("Manhua", "19") Pair("Manga", "10"),
)) Pair("Manhwa", "12"),
Pair("Manhua", "19")
)
)
private class StatusFilter : UriPartFilter("Status", arrayOf( private class StatusFilter : UriPartFilter(
Pair("Any", ""), "Status",
Pair("Completed", "1"), arrayOf(
Pair("Ongoing", "2") Pair("Any", ""),
)) Pair("Completed", "1"),
Pair("Ongoing", "2")
)
)
private class Genre(name: String, val id: String) : Filter.TriState(name) private class Genre(name: String, val id: String) : Filter.TriState(name)
private class GenreFilter(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreFilter(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)

View File

@ -9,10 +9,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Cookie import okhttp3.Cookie
import okhttp3.CookieJar import okhttp3.CookieJar
import okhttp3.HttpUrl import okhttp3.HttpUrl
@ -20,6 +16,10 @@ import okhttp3.OkHttpClient
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
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangahere : ParsedHttpSource() { class Mangahere : ParsedHttpSource() {
@ -34,19 +34,24 @@ class Mangahere : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
override val client: OkHttpClient = super.client.newBuilder() override val client: OkHttpClient = super.client.newBuilder()
.cookieJar(object : CookieJar { .cookieJar(
object : CookieJar {
override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {} override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {}
override fun loadForRequest(url: HttpUrl): MutableList<Cookie> { override fun loadForRequest(url: HttpUrl): MutableList<Cookie> {
return ArrayList<Cookie>().apply { return ArrayList<Cookie>().apply {
add(Cookie.Builder() add(
Cookie.Builder()
.domain("www.mangahere.cc") .domain("www.mangahere.cc")
.path("/") .path("/")
.name("isAdult") .name("isAdult")
.value("1") .value("1")
.build()) } .build()
)
}
} }
}) }
.build() )
.build()
override fun popularMangaSelector() = ".manga-list-1-list li" override fun popularMangaSelector() = ".manga-list-1-list li"
@ -67,7 +72,7 @@ class Mangahere : ParsedHttpSource() {
manga.title = titleElement.attr("title") manga.title = titleElement.attr("title")
manga.setUrlWithoutDomain(titleElement.attr("href")) manga.setUrlWithoutDomain(titleElement.attr("href"))
manga.thumbnail_url = element.select("img.manga-list-1-cover") manga.thumbnail_url = element.select("img.manga-list-1-cover")
?.first()?.attr("src") ?.first()?.attr("src")
return manga return manga
} }
@ -140,7 +145,7 @@ class Mangahere : ParsedHttpSource() {
manga.genre = document.select(".detail-info-right-tag-list > a")?.joinToString { it.text() } manga.genre = document.select(".detail-info-right-tag-list > a")?.joinToString { it.text() }
manga.description = document.select(".fullcontent")?.first()?.text() manga.description = document.select(".fullcontent")?.first()?.text()
manga.thumbnail_url = document.select("img.detail-info-cover-img")?.first() manga.thumbnail_url = document.select("img.detail-info-cover-img")?.first()
?.attr("src") ?.attr("src")
document.select("span.detail-info-right-title-tip")?.first()?.text()?.also { statusText -> document.select("span.detail-info-right-title-tip")?.first()?.text()?.also { statusText ->
when { when {
@ -186,7 +191,7 @@ class Mangahere : ParsedHttpSource() {
}.timeInMillis }.timeInMillis
} else { } else {
try { try {
SimpleDateFormat("MMM dd,yyyy", Locale.ENGLISH).parse(date).time SimpleDateFormat("MMM dd,yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) { } catch (e: ParseException) {
0L 0L
} }
@ -232,8 +237,9 @@ class Mangahere : ParsedHttpSource() {
val chapterIdStartLoc = html.indexOf("chapterid") val chapterIdStartLoc = html.indexOf("chapterid")
val chapterId = html.substring( val chapterId = html.substring(
chapterIdStartLoc + 11, chapterIdStartLoc + 11,
html.indexOf(";", chapterIdStartLoc)).trim() html.indexOf(";", chapterIdStartLoc)
).trim()
val chapterPagesElement = document.select(".pager-list-left > span").first() val chapterPagesElement = document.select(".pager-list-left > span").first()
val pagesLinksElements = chapterPagesElement.select("a") val pagesLinksElements = chapterPagesElement.select("a")
@ -250,15 +256,15 @@ class Mangahere : ParsedHttpSource() {
for (tr in 1..3) { for (tr in 1..3) {
val request = Request.Builder() val request = Request.Builder()
.url(pageLink) .url(pageLink)
.addHeader("Referer", link) .addHeader("Referer", link)
.addHeader("Accept", "*/*") .addHeader("Accept", "*/*")
.addHeader("Accept-Language", "en-US,en;q=0.9") .addHeader("Accept-Language", "en-US,en;q=0.9")
.addHeader("Connection", "keep-alive") .addHeader("Connection", "keep-alive")
.addHeader("Host", "www.mangahere.cc") .addHeader("Host", "www.mangahere.cc")
.addHeader("User-Agent", System.getProperty("http.agent") ?: "") .addHeader("User-Agent", System.getProperty("http.agent") ?: "")
.addHeader("X-Requested-With", "XMLHttpRequest") .addHeader("X-Requested-With", "XMLHttpRequest")
.build() .build()
val response = client.newCall(request).execute() val response = client.newCall(request).execute()
responseText = response.body()!!.string() responseText = response.body()!!.string()
@ -298,7 +304,9 @@ class Mangahere : ParsedHttpSource() {
val secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";") val secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";")
val secretKeyResultScript = secretKeyDeobfuscatedScript.substring( val secretKeyResultScript = secretKeyDeobfuscatedScript.substring(
secretKeyStartLoc, secretKeyEndLoc) secretKeyStartLoc,
secretKeyEndLoc
)
return duktape.evaluate(secretKeyResultScript).toString() return duktape.evaluate(secretKeyResultScript).toString()
} }
@ -312,56 +320,56 @@ class Mangahere : ParsedHttpSource() {
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
TypeList(types.keys.toList().sorted().toTypedArray()), TypeList(types.keys.toList().sorted().toTypedArray()),
CompletionList(completions), CompletionList(completions),
GenreList(genres()) GenreList(genres())
) )
private val types = hashMapOf( private val types = hashMapOf(
"Japanese Manga" to 1, "Japanese Manga" to 1,
"Korean Manhwa" to 2, "Korean Manhwa" to 2,
"Other Manga" to 4, "Other Manga" to 4,
"Any" to 0 "Any" to 0
) )
private val completions = arrayOf("Either", "No", "Yes") private val completions = arrayOf("Either", "No", "Yes")
private fun genres() = arrayListOf( private fun genres() = arrayListOf(
Genre("Action", 1), Genre("Action", 1),
Genre("Adventure", 2), Genre("Adventure", 2),
Genre("Comedy", 3), Genre("Comedy", 3),
Genre("Fantasy", 4), Genre("Fantasy", 4),
Genre("Historical", 5), Genre("Historical", 5),
Genre("Horror", 6), Genre("Horror", 6),
Genre("Martial Arts", 7), Genre("Martial Arts", 7),
Genre("Mystery", 8), Genre("Mystery", 8),
Genre("Romance", 9), Genre("Romance", 9),
Genre("Shounen Ai", 10), Genre("Shounen Ai", 10),
Genre("Supernatural", 11), Genre("Supernatural", 11),
Genre("Drama", 12), Genre("Drama", 12),
Genre("Shounen", 13), Genre("Shounen", 13),
Genre("School Life", 14), Genre("School Life", 14),
Genre("Shoujo", 15), Genre("Shoujo", 15),
Genre("Gender Bender", 16), Genre("Gender Bender", 16),
Genre("Josei", 17), Genre("Josei", 17),
Genre("Psychological", 18), Genre("Psychological", 18),
Genre("Seinen", 19), Genre("Seinen", 19),
Genre("Slice of Life", 20), Genre("Slice of Life", 20),
Genre("Sci-fi", 21), Genre("Sci-fi", 21),
Genre("Ecchi", 22), Genre("Ecchi", 22),
Genre("Harem", 23), Genre("Harem", 23),
Genre("Shoujo Ai", 24), Genre("Shoujo Ai", 24),
Genre("Yuri", 25), Genre("Yuri", 25),
Genre("Mature", 26), Genre("Mature", 26),
Genre("Tragedy", 27), Genre("Tragedy", 27),
Genre("Yaoi", 28), Genre("Yaoi", 28),
Genre("Doujinshi", 29), Genre("Doujinshi", 29),
Genre("Sports", 30), Genre("Sports", 30),
Genre("Adult", 31), Genre("Adult", 31),
Genre("One Shot", 32), Genre("One Shot", 32),
Genre("Smut", 33), Genre("Smut", 33),
Genre("Mecha", 34), Genre("Mecha", 34),
Genre("Shotacon", 35), Genre("Shotacon", 35),
Genre("Lolicon", 36) Genre("Lolicon", 36)
) )
} }

View File

@ -14,17 +14,17 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.net.URL
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.Request import okhttp3.Request
import okhttp3.RequestBody import okhttp3.RequestBody
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URL
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangahub : ParsedHttpSource() { class Mangahub : ParsedHttpSource() {
@ -55,7 +55,7 @@ class Mangahub : ParsedHttpSource() {
manga.title = titleElement.text() manga.title = titleElement.text()
manga.setUrlWithoutDomain(URL(titleElement.attr("href")).path) manga.setUrlWithoutDomain(URL(titleElement.attr("href")).path)
manga.thumbnail_url = element.select("img.manga-thumb.list-item-thumb") manga.thumbnail_url = element.select("img.manga-thumb.list-item-thumb")
?.first()?.attr("src") ?.first()?.attr("src")
return manga return manga
} }
@ -78,7 +78,7 @@ class Mangahub : ParsedHttpSource() {
manga.genre = document.select("._3Czbn a")?.joinToString { it.text() } manga.genre = document.select("._3Czbn a")?.joinToString { it.text() }
manga.description = document.select("div#noanim-content-tab-pane-99 p.ZyMp7")?.first()?.text() manga.description = document.select("div#noanim-content-tab-pane-99 p.ZyMp7")?.first()?.text()
manga.thumbnail_url = document.select("img.img-responsive")?.first() manga.thumbnail_url = document.select("img.img-responsive")?.first()
?.attr("src") ?.attr("src")
document.select("._3QCtP > div:nth-child(2) > div:nth-child(3) > span:nth-child(2)")?.first()?.text()?.also { statusText -> document.select("._3QCtP > div:nth-child(2) > div:nth-child(3) > span:nth-child(2)")?.first()?.text()?.also { statusText ->
when { when {
@ -133,7 +133,7 @@ class Mangahub : ParsedHttpSource() {
// parses: "12-20-2019" and defaults everything that wasn't taken into account to 0 // parses: "12-20-2019" and defaults everything that wasn't taken into account to 0
else -> { else -> {
try { try {
parsedDate = SimpleDateFormat("MM-dd-yyyy", Locale.US).parse(date).time parsedDate = SimpleDateFormat("MM-dd-yyyy", Locale.US).parse(date)?.time ?: 0L
} catch (e: ParseException) { /*nothing to do, parsedDate is initialized with 0L*/ } } catch (e: ParseException) { /*nothing to do, parsedDate is initialized with 0L*/ }
} }
} }
@ -208,16 +208,16 @@ class Mangahub : ParsedHttpSource() {
private class GenreList(genres: Array<Genre>) : Filter.Select<Genre>("Genres", genres, 0) private class GenreList(genres: Array<Genre>) : Filter.Select<Genre>("Genres", genres, 0)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
OrderBy(orderBy), OrderBy(orderBy),
GenreList(genres) GenreList(genres)
) )
private val orderBy = arrayOf( private val orderBy = arrayOf(
Order("Popular", "POPULAR"), Order("Popular", "POPULAR"),
Order("Updates", "LATEST"), Order("Updates", "LATEST"),
Order("A-Z", "ALPHABET"), Order("A-Z", "ALPHABET"),
Order("New", "NEW"), Order("New", "NEW"),
Order("Completed", "COMPLETED") Order("Completed", "COMPLETED")
) )
private val genres = arrayOf( private val genres = arrayOf(

View File

@ -7,14 +7,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class MangaJar : ParsedHttpSource() { class MangaJar : ParsedHttpSource() {
@ -43,8 +43,10 @@ class MangaJar : ParsedHttpSource() {
override fun popularMangaFromElement(element: Element) = SManga.create().apply { override fun popularMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.select("a").attr("href")) setUrlWithoutDomain(element.select("a").attr("href"))
title = element.select("img").attr("title") title = element.select("img").attr("title")
thumbnail_url = element.select("img").let { if (it.hasAttr("data-src")) thumbnail_url = element.select("img").let {
it.attr("data-src") else it.attr("src") } if (it.hasAttr("data-src"))
it.attr("data-src") else it.attr("src")
}
} }
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element) override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
@ -63,16 +65,18 @@ class MangaJar : ParsedHttpSource() {
url.addQueryParameter("q", query) url.addQueryParameter("q", query)
url.addQueryParameter("page", page.toString()) url.addQueryParameter("page", page.toString())
(filters.forEach { filter -> (
when (filter) { filters.forEach { filter ->
is OrderBy -> { when (filter) {
url.addQueryParameter("sortBy", filter.toUriPart()) is OrderBy -> {
} url.addQueryParameter("sortBy", filter.toUriPart())
is SortBy -> { }
url.addQueryParameter("sortAscending", filter.toUriPart()) is SortBy -> {
url.addQueryParameter("sortAscending", filter.toUriPart())
}
} }
} }
}) )
return GET(url.toString(), headers) return GET(url.toString(), headers)
} }
@ -117,7 +121,7 @@ class MangaJar : ParsedHttpSource() {
return if ("ago" in string) { return if ("ago" in string) {
parseRelativeDate(string) ?: 0 parseRelativeDate(string) ?: 0
} else { } else {
dateFormat.parse(string).time dateFormat.parse(string)?.time ?: 0L
} }
} }
@ -146,25 +150,32 @@ class MangaJar : ParsedHttpSource() {
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(
OrderBy(), OrderBy(),
SortBy(), SortBy(),
GenreList() GenreList()
) )
private class SortBy : UriPartFilter("Sort By", arrayOf( private class SortBy : UriPartFilter(
"Sort By",
arrayOf(
Pair("Descending", "0"), Pair("Descending", "0"),
Pair("Ascending", "1") Pair("Ascending", "1")
)) )
)
private class OrderBy : UriPartFilter("Order By", arrayOf( private class OrderBy : UriPartFilter(
"Order By",
arrayOf(
Pair("Popularity", "popular"), Pair("Popularity", "popular"),
Pair("Year", "year"), Pair("Year", "year"),
Pair("Alphabet", "name"), Pair("Alphabet", "name"),
Pair("Date added", "published_at"), Pair("Date added", "published_at"),
Pair("Date updated", "last_chapter_at") Pair("Date updated", "last_chapter_at")
)) )
)
private class GenreList : Filter.Select<String>("Select Genre", private class GenreList : Filter.Select<String>(
"Select Genre",
arrayOf( arrayOf(
"", "",
"Fantasy", "Fantasy",
@ -220,7 +231,7 @@ class MangaJar : ParsedHttpSource() {
private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T private inline fun <reified T> Iterable<*>.findInstance() = find { it is T } as? T
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
} }

View File

@ -6,13 +6,13 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.MediaType import okhttp3.MediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.ResponseBody import okhttp3.ResponseBody
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaKatana : ParsedHttpSource() { class MangaKatana : ParsedHttpSource() {
override val name = "MangaKatana" override val name = "MangaKatana"

View File

@ -17,14 +17,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
/** /**
* Source responds to requests with their full database as a JsonArray, then sorts/filters it client-side * Source responds to requests with their full database as a JsonArray, then sorts/filters it client-side
@ -89,11 +89,13 @@ class MangaLife : HttpSource() {
val endRange = ((page * 24) - 1).let { if (it <= directory.lastIndex) it else directory.lastIndex } val endRange = ((page * 24) - 1).let { if (it <= directory.lastIndex) it else directory.lastIndex }
for (i in (((page - 1) * 24)..endRange)) { for (i in (((page - 1) * 24)..endRange)) {
mangas.add(SManga.create().apply { mangas.add(
title = directory[i]["s"].string SManga.create().apply {
url = "/manga/${directory[i]["i"].string}" title = directory[i]["s"].string
thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg" url = "/manga/${directory[i]["i"].string}"
}) thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg"
}
)
} }
return MangasPage(mangas, endRange < directory.lastIndex) return MangasPage(mangas, endRange < directory.lastIndex)
} }
@ -281,54 +283,54 @@ class MangaLife : HttpSource() {
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
YearField(), YearField(),
AuthorField(), AuthorField(),
SelectField("Scan Status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")), SelectField("Scan Status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")),
SelectField("Publish Status", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")), SelectField("Publish Status", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")),
SelectField("Type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")), SelectField("Type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")),
SelectField("Translation", arrayOf("Any", "Official Only")), SelectField("Translation", arrayOf("Any", "Official Only")),
Sort(), Sort(),
GenreList(getGenreList()) GenreList(getGenreList())
) )
// [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n') // [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n')
// https://manga4life.com/advanced-search/ // https://manga4life.com/advanced-search/
private fun getGenreList() = listOf( private fun getGenreList() = listOf(
Genre("Action"), Genre("Action"),
Genre("Adult"), Genre("Adult"),
Genre("Adventure"), Genre("Adventure"),
Genre("Comedy"), Genre("Comedy"),
Genre("Doujinshi"), Genre("Doujinshi"),
Genre("Drama"), Genre("Drama"),
Genre("Ecchi"), Genre("Ecchi"),
Genre("Fantasy"), Genre("Fantasy"),
Genre("Gender Bender"), Genre("Gender Bender"),
Genre("Harem"), Genre("Harem"),
Genre("Hentai"), Genre("Hentai"),
Genre("Historical"), Genre("Historical"),
Genre("Horror"), Genre("Horror"),
Genre("Josei"), Genre("Josei"),
Genre("Lolicon"), Genre("Lolicon"),
Genre("Martial Arts"), Genre("Martial Arts"),
Genre("Mature"), Genre("Mature"),
Genre("Mecha"), Genre("Mecha"),
Genre("Mystery"), Genre("Mystery"),
Genre("Psychological"), Genre("Psychological"),
Genre("Romance"), Genre("Romance"),
Genre("School Life"), Genre("School Life"),
Genre("Sci-fi"), Genre("Sci-fi"),
Genre("Seinen"), Genre("Seinen"),
Genre("Shotacon"), Genre("Shotacon"),
Genre("Shoujo"), Genre("Shoujo"),
Genre("Shoujo Ai"), Genre("Shoujo Ai"),
Genre("Shounen"), Genre("Shounen"),
Genre("Shounen Ai"), Genre("Shounen Ai"),
Genre("Slice of Life"), Genre("Slice of Life"),
Genre("Smut"), Genre("Smut"),
Genre("Sports"), Genre("Sports"),
Genre("Supernatural"), Genre("Supernatural"),
Genre("Tragedy"), Genre("Tragedy"),
Genre("Yaoi"), Genre("Yaoi"),
Genre("Yuri") Genre("Yuri")
) )
} }

View File

@ -11,13 +11,13 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class MangaLinkz : ParsedHttpSource() { class MangaLinkz : ParsedHttpSource() {
@ -126,11 +126,12 @@ class MangaLinkz : ParsedHttpSource() {
} }
} }
} }
else -> try { else ->
SimpleDateFormat("MMM d, yyyy", Locale.US).parse(this).time try {
} catch (_: Exception) { SimpleDateFormat("MMM d, yyyy", Locale.US).parse(this)?.time ?: 0L
0L } catch (_: Exception) {
} 0L
}
} }
} }

View File

@ -7,11 +7,11 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.util.Calendar
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
import rx.Observable import rx.Observable
import java.util.Calendar
// MangaManiac is a network of sites built by Animemaniac.co. // MangaManiac is a network of sites built by Animemaniac.co.

View File

@ -12,14 +12,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource import eu.kanade.tachiyomi.source.online.HttpSource
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import java.lang.Exception import java.lang.Exception
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Locale import java.util.Locale
import java.util.TimeZone import java.util.TimeZone
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
fun JsonObject.getNullable(key: String): JsonElement? { fun JsonObject.getNullable(key: String): JsonElement? {
val value: JsonElement = this.get(key) ?: return null val value: JsonElement = this.get(key) ?: return null
@ -72,11 +72,13 @@ class MangaMutiny : HttpSource() {
for (singleChapterJsonElement in jsonChapters) { for (singleChapterJsonElement in jsonChapters) {
val singleChapterJsonObject = singleChapterJsonElement.asJsonObject val singleChapterJsonObject = singleChapterJsonElement.asJsonObject
chapterList.add(SChapter.create().apply { chapterList.add(
name = chapterTitleBuilder(singleChapterJsonObject) SChapter.create().apply {
url = singleChapterJsonObject.get("slug").asString name = chapterTitleBuilder(singleChapterJsonObject)
date_upload = parseDate(singleChapterJsonObject.get("releasedAt").asString) url = singleChapterJsonObject.get("slug").asString
}) date_upload = parseDate(singleChapterJsonObject.get("releasedAt").asString)
}
)
} }
} }
@ -211,11 +213,13 @@ class MangaMutiny : HttpSource() {
for (singleItem in itemsArray) { for (singleItem in itemsArray) {
val mangaObject = singleItem.asJsonObject val mangaObject = singleItem.asJsonObject
mangasPage.add(SManga.create().apply { mangasPage.add(
this.title = mangaObject.get("title").asString SManga.create().apply {
this.thumbnail_url = mangaObject.getNullable("thumbnail")?.asString this.title = mangaObject.get("title").asString
this.url = mangaObject.get("slug").asString this.thumbnail_url = mangaObject.getNullable("thumbnail")?.asString
}) this.url = mangaObject.get("slug").asString
}
)
} }
} }
@ -303,19 +307,27 @@ class MangaMutiny : HttpSource() {
} }
} }
private class StatusFilter : UriSelectFilter("Status", "status", arrayOf( private class StatusFilter : UriSelectFilter(
Pair("", "All"), "Status",
Pair("completed", "Completed"), "status",
Pair("ongoing", "Ongoing") arrayOf(
)) Pair("", "All"),
Pair("completed", "Completed"),
Pair("ongoing", "Ongoing")
)
)
private class CategoryFilter : UriSelectFilter("Category", "tags", arrayOf( private class CategoryFilter : UriSelectFilter(
Pair("", "All"), "Category",
Pair("josei", "Josei"), "tags",
Pair("seinen", "Seinen"), arrayOf(
Pair("shoujo", "Shoujo"), Pair("", "All"),
Pair("shounen", "Shounen") Pair("josei", "Josei"),
)) { Pair("seinen", "Seinen"),
Pair("shoujo", "Shoujo"),
Pair("shounen", "Shounen")
)
) {
override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) = override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) =
appendValueToKeyInUriParameterMap(parameterMap, uriParam, vals[state].first) appendValueToKeyInUriParameterMap(parameterMap, uriParam, vals[state].first)
} }
@ -333,92 +345,104 @@ class MangaMutiny : HttpSource() {
} }
} }
// Actual genere filter list // Actual genere filter list
private class GenresFilter : GenreFilterList("Genres", listOf( private class GenresFilter : GenreFilterList(
GenreFilter("action", "action"), "Genres",
GenreFilter("adult", "adult"), listOf(
GenreFilter("adventure", "adventure"), GenreFilter("action", "action"),
GenreFilter("aliens", "aliens"), GenreFilter("adult", "adult"),
GenreFilter("animals", "animals"), GenreFilter("adventure", "adventure"),
GenreFilter("comedy", "comedy"), GenreFilter("aliens", "aliens"),
GenreFilter("cooking", "cooking"), GenreFilter("animals", "animals"),
GenreFilter("crossdressing", "crossdressing"), GenreFilter("comedy", "comedy"),
GenreFilter("delinquents", "delinquents"), GenreFilter("cooking", "cooking"),
GenreFilter("demons", "demons"), GenreFilter("crossdressing", "crossdressing"),
GenreFilter("drama", "drama"), GenreFilter("delinquents", "delinquents"),
GenreFilter("ecchi", "ecchi"), GenreFilter("demons", "demons"),
GenreFilter("fantasy", "fantasy"), GenreFilter("drama", "drama"),
GenreFilter("gender_bender", "gender bender"), GenreFilter("ecchi", "ecchi"),
GenreFilter("genderswap", "genderswap"), GenreFilter("fantasy", "fantasy"),
GenreFilter("ghosts", "ghosts"), GenreFilter("gender_bender", "gender bender"),
GenreFilter("gore", "gore"), GenreFilter("genderswap", "genderswap"),
GenreFilter("gyaru", "gyaru"), GenreFilter("ghosts", "ghosts"),
GenreFilter("harem", "harem"), GenreFilter("gore", "gore"),
GenreFilter("historical", "historical"), GenreFilter("gyaru", "gyaru"),
GenreFilter("horror", "horror"), GenreFilter("harem", "harem"),
GenreFilter("incest", "incest"), GenreFilter("historical", "historical"),
GenreFilter("isekai", "isekai"), GenreFilter("horror", "horror"),
GenreFilter("loli", "loli"), GenreFilter("incest", "incest"),
GenreFilter("magic", "magic"), GenreFilter("isekai", "isekai"),
GenreFilter("magical_girls", "magical girls"), GenreFilter("loli", "loli"),
GenreFilter("mangamutiny", "mangamutiny"), GenreFilter("magic", "magic"),
GenreFilter("martial_arts", "martial arts"), GenreFilter("magical_girls", "magical girls"),
GenreFilter("mature", "mature"), GenreFilter("mangamutiny", "mangamutiny"),
GenreFilter("mecha", "mecha"), GenreFilter("martial_arts", "martial arts"),
GenreFilter("medical", "medical"), GenreFilter("mature", "mature"),
GenreFilter("military", "military"), GenreFilter("mecha", "mecha"),
GenreFilter("monster_girls", "monster girls"), GenreFilter("medical", "medical"),
GenreFilter("monsters", "monsters"), GenreFilter("military", "military"),
GenreFilter("mystery", "mystery"), GenreFilter("monster_girls", "monster girls"),
GenreFilter("ninja", "ninja"), GenreFilter("monsters", "monsters"),
GenreFilter("office_workers", "office workers"), GenreFilter("mystery", "mystery"),
GenreFilter("philosophical", "philosophical"), GenreFilter("ninja", "ninja"),
GenreFilter("psychological", "psychological"), GenreFilter("office_workers", "office workers"),
GenreFilter("reincarnation", "reincarnation"), GenreFilter("philosophical", "philosophical"),
GenreFilter("reverse_harem", "reverse harem"), GenreFilter("psychological", "psychological"),
GenreFilter("romance", "romance"), GenreFilter("reincarnation", "reincarnation"),
GenreFilter("school_life", "school life"), GenreFilter("reverse_harem", "reverse harem"),
GenreFilter("sci_fi", "sci fi"), GenreFilter("romance", "romance"),
GenreFilter("sci-fi", "sci-fi"), GenreFilter("school_life", "school life"),
GenreFilter("sexual_violence", "sexual violence"), GenreFilter("sci_fi", "sci fi"),
GenreFilter("shota", "shota"), GenreFilter("sci-fi", "sci-fi"),
GenreFilter("shoujo_ai", "shoujo ai"), GenreFilter("sexual_violence", "sexual violence"),
GenreFilter("shounen_ai", "shounen ai"), GenreFilter("shota", "shota"),
GenreFilter("slice_of_life", "slice of life"), GenreFilter("shoujo_ai", "shoujo ai"),
GenreFilter("smut", "smut"), GenreFilter("shounen_ai", "shounen ai"),
GenreFilter("sports", "sports"), GenreFilter("slice_of_life", "slice of life"),
GenreFilter("superhero", "superhero"), GenreFilter("smut", "smut"),
GenreFilter("supernatural", "supernatural"), GenreFilter("sports", "sports"),
GenreFilter("survival", "survival"), GenreFilter("superhero", "superhero"),
GenreFilter("time_travel", "time travel"), GenreFilter("supernatural", "supernatural"),
GenreFilter("tragedy", "tragedy"), GenreFilter("survival", "survival"),
GenreFilter("video_games", "video games"), GenreFilter("time_travel", "time travel"),
GenreFilter("virtual_reality", "virtual reality"), GenreFilter("tragedy", "tragedy"),
GenreFilter("webtoons", "webtoons"), GenreFilter("video_games", "video games"),
GenreFilter("wuxia", "wuxia"), GenreFilter("virtual_reality", "virtual reality"),
GenreFilter("zombies", "zombies") GenreFilter("webtoons", "webtoons"),
)) GenreFilter("wuxia", "wuxia"),
GenreFilter("zombies", "zombies")
)
)
// Actual format filter List // Actual format filter List
private class FormatsFilter : GenreFilterList("Formats", listOf( private class FormatsFilter : GenreFilterList(
GenreFilter("4-koma", "4-koma"), "Formats",
GenreFilter("adaptation", "adaptation"), listOf(
GenreFilter("anthology", "anthology"), GenreFilter("4-koma", "4-koma"),
GenreFilter("award_winning", "award winning"), GenreFilter("adaptation", "adaptation"),
GenreFilter("doujinshi", "doujinshi"), GenreFilter("anthology", "anthology"),
GenreFilter("fan_colored", "fan colored"), GenreFilter("award_winning", "award winning"),
GenreFilter("full_color", "full color"), GenreFilter("doujinshi", "doujinshi"),
GenreFilter("long_strip", "long strip"), GenreFilter("fan_colored", "fan colored"),
GenreFilter("official_colored", "official colored"), GenreFilter("full_color", "full color"),
GenreFilter("oneshot", "oneshot"), GenreFilter("long_strip", "long strip"),
GenreFilter("web_comic", "web comic") GenreFilter("official_colored", "official colored"),
)) GenreFilter("oneshot", "oneshot"),
GenreFilter("web_comic", "web comic")
)
)
private class SortFilter : UriSelectFilter("Sort", "sort", arrayOf( private class SortFilter : UriSelectFilter(
Pair("-rating -ratingCount", "Popular"), "Sort",
Pair("-lastReleasedAt", "Last update"), "sort",
Pair("-createdAt", "Newest"), arrayOf(
Pair("title", "Name") Pair("-rating -ratingCount", "Popular"),
), firstIsUnspecified = false, defaultValue = 0) Pair("-lastReleasedAt", "Last update"),
Pair("-createdAt", "Newest"),
Pair("title", "Name")
),
firstIsUnspecified = false,
defaultValue = 0
)
private class AuthorFilter : Filter.Text("Manga Author & Artist"), UriFilter { private class AuthorFilter : Filter.Text("Manga Author & Artist"), UriFilter {
override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) { override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) {
@ -429,8 +453,8 @@ class MangaMutiny : HttpSource() {
} }
/**The scanlator filter exists on the mangamutiny website website, however it doesn't work. /**The scanlator filter exists on the mangamutiny website website, however it doesn't work.
This should stay disabled in the extension until it's properly implemented on the website, This should stay disabled in the extension until it's properly implemented on the website,
otherwise users may be confused by searches that return no results.**/ otherwise users may be confused by searches that return no results.**/
/* /*
private class ScanlatorFilter : Filter.Text("Scanlator Name"), UriFilter { private class ScanlatorFilter : Filter.Text("Scanlator Name"), UriFilter {
override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) { override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) {

View File

@ -6,14 +6,14 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class MangaOwl : ParsedHttpSource() { class MangaOwl : ParsedHttpSource() {

View File

@ -15,9 +15,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.CacheControl import okhttp3.CacheControl
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
@ -26,6 +23,9 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class MangaPark : ConfigurableSource, ParsedHttpSource() { class MangaPark : ConfigurableSource, ParsedHttpSource() {
@ -154,7 +154,7 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
return when (getSourcePref()) { return when (getSourcePref()) {
// source with most chapters along with chapters that source doesn't have // source with most chapters along with chapters that source doesn't have
"most" -> { "most" -> {
val chapters = mangaBySource.maxBy { it.count() }!! val chapters = mangaBySource.maxByOrNull { it.count() }!!
(chapters + chapters.getMissingChapters(mangaBySource.flatten())).sortedByDescending { it.chapter_number } (chapters + chapters.getMissingChapters(mangaBySource.flatten())).sortedByDescending { it.chapter_number }
} }
// "smart list" - try not to miss a chapter and avoid dupes // "smart list" - try not to miss a chapter and avoid dupes
@ -280,21 +280,21 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used") override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
AuthorArtistText(), AuthorArtistText(),
SearchTypeFilter("Title query", "name-match"), SearchTypeFilter("Title query", "name-match"),
SearchTypeFilter("Author/Artist query", "autart-match"), SearchTypeFilter("Author/Artist query", "autart-match"),
SortFilter(), SortFilter(),
GenreGroup(), GenreGroup(),
GenreInclusionFilter(), GenreInclusionFilter(),
ChapterCountFilter(), ChapterCountFilter(),
StatusFilter(), StatusFilter(),
RatingFilter(), RatingFilter(),
TypeFilter(), TypeFilter(),
YearFilter() YearFilter()
) )
private class SearchTypeFilter(name: String, val uriParam: String) : private class SearchTypeFilter(name: String, val uriParam: String) :
Filter.Select<String>(name, STATE_MAP), UriFilter { Filter.Select<String>(name, STATE_MAP), UriFilter {
override fun addToUri(uri: Uri.Builder) { override fun addToUri(uri: Uri.Builder) {
if (STATE_MAP[state] != "contain") { if (STATE_MAP[state] != "contain") {
uri.appendQueryParameter(uriParam, STATE_MAP[state]) uri.appendQueryParameter(uriParam, STATE_MAP[state])
@ -316,107 +316,112 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
private class GenreFilter(val uriParam: String, displayName: String) : Filter.TriState(displayName) private class GenreFilter(val uriParam: String, displayName: String) : Filter.TriState(displayName)
private class GenreGroup : Filter.Group<GenreFilter>("Genres", listOf( private class GenreGroup :
GenreFilter("4-koma", "4 koma"), Filter.Group<GenreFilter>(
GenreFilter("action", "Action"), "Genres",
GenreFilter("adaptation", "Adaptation"), listOf(
GenreFilter("adult", "Adult"), GenreFilter("4-koma", "4 koma"),
GenreFilter("adventure", "Adventure"), GenreFilter("action", "Action"),
GenreFilter("aliens", "Aliens"), GenreFilter("adaptation", "Adaptation"),
GenreFilter("animals", "Animals"), GenreFilter("adult", "Adult"),
GenreFilter("anthology", "Anthology"), GenreFilter("adventure", "Adventure"),
GenreFilter("award-winning", "Award winning"), GenreFilter("aliens", "Aliens"),
GenreFilter("comedy", "Comedy"), GenreFilter("animals", "Animals"),
GenreFilter("cooking", "Cooking"), GenreFilter("anthology", "Anthology"),
GenreFilter("crime", "Crime"), GenreFilter("award-winning", "Award winning"),
GenreFilter("crossdressing", "Crossdressing"), GenreFilter("comedy", "Comedy"),
GenreFilter("delinquents", "Delinquents"), GenreFilter("cooking", "Cooking"),
GenreFilter("demons", "Demons"), GenreFilter("crime", "Crime"),
GenreFilter("doujinshi", "Doujinshi"), GenreFilter("crossdressing", "Crossdressing"),
GenreFilter("drama", "Drama"), GenreFilter("delinquents", "Delinquents"),
GenreFilter("ecchi", "Ecchi"), GenreFilter("demons", "Demons"),
GenreFilter("fan-colored", "Fan colored"), GenreFilter("doujinshi", "Doujinshi"),
GenreFilter("fantasy", "Fantasy"), GenreFilter("drama", "Drama"),
GenreFilter("food", "Food"), GenreFilter("ecchi", "Ecchi"),
GenreFilter("full-color", "Full color"), GenreFilter("fan-colored", "Fan colored"),
GenreFilter("game", "Game"), GenreFilter("fantasy", "Fantasy"),
GenreFilter("gender-bender", "Gender bender"), GenreFilter("food", "Food"),
GenreFilter("genderswap", "Genderswap"), GenreFilter("full-color", "Full color"),
GenreFilter("ghosts", "Ghosts"), GenreFilter("game", "Game"),
GenreFilter("gore", "Gore"), GenreFilter("gender-bender", "Gender bender"),
GenreFilter("gossip", "Gossip"), GenreFilter("genderswap", "Genderswap"),
GenreFilter("gyaru", "Gyaru"), GenreFilter("ghosts", "Ghosts"),
GenreFilter("harem", "Harem"), GenreFilter("gore", "Gore"),
GenreFilter("historical", "Historical"), GenreFilter("gossip", "Gossip"),
GenreFilter("horror", "Horror"), GenreFilter("gyaru", "Gyaru"),
GenreFilter("incest", "Incest"), GenreFilter("harem", "Harem"),
GenreFilter("isekai", "Isekai"), GenreFilter("historical", "Historical"),
GenreFilter("josei", "Josei"), GenreFilter("horror", "Horror"),
GenreFilter("kids", "Kids"), GenreFilter("incest", "Incest"),
GenreFilter("loli", "Loli"), GenreFilter("isekai", "Isekai"),
GenreFilter("lolicon", "Lolicon"), GenreFilter("josei", "Josei"),
GenreFilter("long-strip", "Long strip"), GenreFilter("kids", "Kids"),
GenreFilter("mafia", "Mafia"), GenreFilter("loli", "Loli"),
GenreFilter("magic", "Magic"), GenreFilter("lolicon", "Lolicon"),
GenreFilter("magical-girls", "Magical girls"), GenreFilter("long-strip", "Long strip"),
GenreFilter("manhwa", "Manhwa"), GenreFilter("mafia", "Mafia"),
GenreFilter("martial-arts", "Martial arts"), GenreFilter("magic", "Magic"),
GenreFilter("mature", "Mature"), GenreFilter("magical-girls", "Magical girls"),
GenreFilter("mecha", "Mecha"), GenreFilter("manhwa", "Manhwa"),
GenreFilter("medical", "Medical"), GenreFilter("martial-arts", "Martial arts"),
GenreFilter("military", "Military"), GenreFilter("mature", "Mature"),
GenreFilter("monster-girls", "Monster girls"), GenreFilter("mecha", "Mecha"),
GenreFilter("monsters", "Monsters"), GenreFilter("medical", "Medical"),
GenreFilter("music", "Music"), GenreFilter("military", "Military"),
GenreFilter("mystery", "Mystery"), GenreFilter("monster-girls", "Monster girls"),
GenreFilter("ninja", "Ninja"), GenreFilter("monsters", "Monsters"),
GenreFilter("office-workers", "Office workers"), GenreFilter("music", "Music"),
GenreFilter("official-colored", "Official colored"), GenreFilter("mystery", "Mystery"),
GenreFilter("one-shot", "One shot"), GenreFilter("ninja", "Ninja"),
GenreFilter("parody", "Parody"), GenreFilter("office-workers", "Office workers"),
GenreFilter("philosophical", "Philosophical"), GenreFilter("official-colored", "Official colored"),
GenreFilter("police", "Police"), GenreFilter("one-shot", "One shot"),
GenreFilter("post-apocalyptic", "Post apocalyptic"), GenreFilter("parody", "Parody"),
GenreFilter("psychological", "Psychological"), GenreFilter("philosophical", "Philosophical"),
GenreFilter("reincarnation", "Reincarnation"), GenreFilter("police", "Police"),
GenreFilter("reverse-harem", "Reverse harem"), GenreFilter("post-apocalyptic", "Post apocalyptic"),
GenreFilter("romance", "Romance"), GenreFilter("psychological", "Psychological"),
GenreFilter("samurai", "Samurai"), GenreFilter("reincarnation", "Reincarnation"),
GenreFilter("school-life", "School life"), GenreFilter("reverse-harem", "Reverse harem"),
GenreFilter("sci-fi", "Sci fi"), GenreFilter("romance", "Romance"),
GenreFilter("seinen", "Seinen"), GenreFilter("samurai", "Samurai"),
GenreFilter("shota", "Shota"), GenreFilter("school-life", "School life"),
GenreFilter("shotacon", "Shotacon"), GenreFilter("sci-fi", "Sci fi"),
GenreFilter("shoujo", "Shoujo"), GenreFilter("seinen", "Seinen"),
GenreFilter("shoujo-ai", "Shoujo ai"), GenreFilter("shota", "Shota"),
GenreFilter("shounen", "Shounen"), GenreFilter("shotacon", "Shotacon"),
GenreFilter("shounen-ai", "Shounen ai"), GenreFilter("shoujo", "Shoujo"),
GenreFilter("slice-of-life", "Slice of life"), GenreFilter("shoujo-ai", "Shoujo ai"),
GenreFilter("smut", "Smut"), GenreFilter("shounen", "Shounen"),
GenreFilter("space", "Space"), GenreFilter("shounen-ai", "Shounen ai"),
GenreFilter("sports", "Sports"), GenreFilter("slice-of-life", "Slice of life"),
GenreFilter("super-power", "Super power"), GenreFilter("smut", "Smut"),
GenreFilter("superhero", "Superhero"), GenreFilter("space", "Space"),
GenreFilter("supernatural", "Supernatural"), GenreFilter("sports", "Sports"),
GenreFilter("survival", "Survival"), GenreFilter("super-power", "Super power"),
GenreFilter("suspense", "Suspense"), GenreFilter("superhero", "Superhero"),
GenreFilter("thriller", "Thriller"), GenreFilter("supernatural", "Supernatural"),
GenreFilter("time-travel", "Time travel"), GenreFilter("survival", "Survival"),
GenreFilter("toomics", "Toomics"), GenreFilter("suspense", "Suspense"),
GenreFilter("traditional-games", "Traditional games"), GenreFilter("thriller", "Thriller"),
GenreFilter("tragedy", "Tragedy"), GenreFilter("time-travel", "Time travel"),
GenreFilter("user-created", "User created"), GenreFilter("toomics", "Toomics"),
GenreFilter("vampire", "Vampire"), GenreFilter("traditional-games", "Traditional games"),
GenreFilter("vampires", "Vampires"), GenreFilter("tragedy", "Tragedy"),
GenreFilter("video-games", "Video games"), GenreFilter("user-created", "User created"),
GenreFilter("virtual-reality", "Virtual reality"), GenreFilter("vampire", "Vampire"),
GenreFilter("web-comic", "Web comic"), GenreFilter("vampires", "Vampires"),
GenreFilter("webtoon", "Webtoon"), GenreFilter("video-games", "Video games"),
GenreFilter("wuxia", "Wuxia"), GenreFilter("virtual-reality", "Virtual reality"),
GenreFilter("yaoi", "Yaoi"), GenreFilter("web-comic", "Web comic"),
GenreFilter("yuri", "Yuri"), GenreFilter("webtoon", "Webtoon"),
GenreFilter("zombies", "Zombies") GenreFilter("wuxia", "Wuxia"),
)), UriFilter { GenreFilter("yaoi", "Yaoi"),
GenreFilter("yuri", "Yuri"),
GenreFilter("zombies", "Zombies")
)
),
UriFilter {
override fun addToUri(uri: Uri.Builder) { override fun addToUri(uri: Uri.Builder) {
val genresParameterValue = state.filter { it.isIncluded() }.joinToString(",") { it.uriParam } val genresParameterValue = state.filter { it.isIncluded() }.joinToString(",") { it.uriParam }
if (genresParameterValue.isNotEmpty()) { if (genresParameterValue.isNotEmpty()) {
@ -430,12 +435,19 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
} }
} }
private class GenreInclusionFilter : UriSelectFilter("Genre inclusion", "genres-mode", arrayOf( private class GenreInclusionFilter : UriSelectFilter(
"Genre inclusion",
"genres-mode",
arrayOf(
Pair("and", "And mode"), Pair("and", "And mode"),
Pair("or", "Or mode") Pair("or", "Or mode")
)) )
)
private class ChapterCountFilter : UriSelectFilter("Chapter count", "chapters", arrayOf( private class ChapterCountFilter : UriSelectFilter(
"Chapter count",
"chapters",
arrayOf(
Pair("any", "Any"), Pair("any", "Any"),
Pair("1", "1 +"), Pair("1", "1 +"),
Pair("5", "5 +"), Pair("5", "5 +"),
@ -447,15 +459,23 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
Pair("100", "100 +"), Pair("100", "100 +"),
Pair("150", "150 +"), Pair("150", "150 +"),
Pair("200", "200 +") Pair("200", "200 +")
)) )
)
private class StatusFilter : UriSelectFilter("Status", "status", arrayOf( private class StatusFilter : UriSelectFilter(
"Status",
"status",
arrayOf(
Pair("any", "Any"), Pair("any", "Any"),
Pair("completed", "Completed"), Pair("completed", "Completed"),
Pair("ongoing", "Ongoing") Pair("ongoing", "Ongoing")
)) )
)
private class RatingFilter : UriSelectFilter("Rating", "rating", arrayOf( private class RatingFilter : UriSelectFilter(
"Rating",
"rating",
arrayOf(
Pair("any", "Any"), Pair("any", "Any"),
Pair("5", "5 stars"), Pair("5", "5 stars"),
Pair("4", "4 stars"), Pair("4", "4 stars"),
@ -463,26 +483,37 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
Pair("2", "2 stars"), Pair("2", "2 stars"),
Pair("1", "1 star"), Pair("1", "1 star"),
Pair("0", "0 stars") Pair("0", "0 stars")
)) )
)
private class TypeFilter : UriSelectFilter("Type", "types", arrayOf( private class TypeFilter : UriSelectFilter(
"Type",
"types",
arrayOf(
Pair("any", "Any"), Pair("any", "Any"),
Pair("manga", "Japanese Manga"), Pair("manga", "Japanese Manga"),
Pair("manhwa", "Korean Manhwa"), Pair("manhwa", "Korean Manhwa"),
Pair("manhua", "Chinese Manhua"), Pair("manhua", "Chinese Manhua"),
Pair("unknown", "Unknown") Pair("unknown", "Unknown")
)) )
private class YearFilter : UriSelectFilter("Release year", "years",
arrayOf(Pair("any", "Any"),
// Get all years between today and 1946
*(Calendar.getInstance().get(Calendar.YEAR) downTo 1946).map {
Pair(it.toString(), it.toString())
}.toTypedArray()
)
) )
private class SortFilter : UriSelectFilter("Sort", "orderby", arrayOf( private class YearFilter : UriSelectFilter(
"Release year",
"years",
arrayOf(
Pair("any", "Any"),
// Get all years between today and 1946
*(Calendar.getInstance().get(Calendar.YEAR) downTo 1946).map {
Pair(it.toString(), it.toString())
}.toTypedArray()
)
)
private class SortFilter : UriSelectFilter(
"Sort",
"orderby",
arrayOf(
Pair("a-z", "A-Z"), Pair("a-z", "A-Z"),
Pair("views_a", "Views all-time"), Pair("views_a", "Views all-time"),
Pair("views_y", "Views last 365 days"), Pair("views_y", "Views last 365 days"),
@ -491,7 +522,10 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
Pair("rating", "Rating"), Pair("rating", "Rating"),
Pair("update", "Latest"), Pair("update", "Latest"),
Pair("create", "New manga") Pair("create", "New manga")
), firstIsUnspecified = false, defaultValue = 1) ),
firstIsUnspecified = false,
defaultValue = 1
)
/** /**
* Class that creates a select filter. Each entry in the dropdown has a name and a display name. * Class that creates a select filter. Each entry in the dropdown has a name and a display name.
@ -506,7 +540,7 @@ class MangaPark : ConfigurableSource, ParsedHttpSource() {
val firstIsUnspecified: Boolean = true, val firstIsUnspecified: Boolean = true,
defaultValue: Int = 0 defaultValue: Int = 0
) : ) :
Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter { Filter.Select<String>(displayName, vals.map { it.second }.toTypedArray(), defaultValue), UriFilter {
override fun addToUri(uri: Uri.Builder) { override fun addToUri(uri: Uri.Builder) {
if (state != 0 || !firstIsUnspecified) if (state != 0 || !firstIsUnspecified)
uri.appendQueryParameter(uriParam, vals[state].first) uri.appendQueryParameter(uriParam, vals[state].first)

View File

@ -8,13 +8,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
abstract class MRP( abstract class MRP(
override val name: String, override val name: String,

View File

@ -14,8 +14,9 @@ import org.jsoup.nodes.Element
class MRPFactory : SourceFactory { class MRPFactory : SourceFactory {
override fun createSources(): List<Source> = listOf( override fun createSources(): List<Source> = listOf(
Mangareader(), Mangareader(),
Mangapanda()) Mangapanda()
)
} }
class Mangareader : MRP("Mangareader", "https://www.mangareader.net") { class Mangareader : MRP("Mangareader", "https://www.mangareader.net") {

View File

@ -10,11 +10,6 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import kotlin.experimental.and
import kotlin.experimental.xor
import okhttp3.HttpUrl import okhttp3.HttpUrl
import okhttp3.MediaType import okhttp3.MediaType
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -23,6 +18,11 @@ import okhttp3.Response
import okhttp3.ResponseBody import okhttp3.ResponseBody
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import kotlin.experimental.and
import kotlin.experimental.xor
class MangaRockEs : ParsedHttpSource() { class MangaRockEs : ParsedHttpSource() {
@ -35,16 +35,18 @@ class MangaRockEs : ParsedHttpSource() {
override val supportsLatest = true override val supportsLatest = true
// Handles the page decoding // Handles the page decoding
override val client: OkHttpClient = network.cloudflareClient.newBuilder().addInterceptor(fun(chain): Response { override val client: OkHttpClient = network.cloudflareClient.newBuilder().addInterceptor(
val url = chain.request().url().toString() fun(chain): Response {
val response = chain.proceed(chain.request()) val url = chain.request().url().toString()
if (!url.endsWith(".mri")) return response val response = chain.proceed(chain.request())
if (!url.endsWith(".mri")) return response
val decoded: ByteArray = decodeMri(response) val decoded: ByteArray = decodeMri(response)
val mediaType = MediaType.parse("image/webp") val mediaType = MediaType.parse("image/webp")
val rb = ResponseBody.create(mediaType, decoded) val rb = ResponseBody.create(mediaType, decoded)
return response.newBuilder().body(rb).build() return response.newBuilder().body(rb).build()
}).build() }
).build()
// Popular // Popular
@ -150,7 +152,7 @@ class MangaRockEs : ParsedHttpSource() {
calendar.timeInMillis calendar.timeInMillis
} else { } else {
SimpleDateFormat("MMM d, yyyy", Locale.US).parse(date).time SimpleDateFormat("MMM d, yyyy", Locale.US).parse(date)?.time ?: 0L
} }
} ?: 0 } ?: 0
} }
@ -215,13 +217,18 @@ class MangaRockEs : ParsedHttpSource() {
// Filters // Filters
private class StatusFilter : UriPartFilter("Status", arrayOf( private class StatusFilter : UriPartFilter(
Pair("All", "all"), "Status",
Pair("Completed", "completed"), arrayOf(
Pair("Ongoing", "ongoing") Pair("All", "all"),
)) Pair("Completed", "completed"),
Pair("Ongoing", "ongoing")
)
)
private class RankFilter : UriPartFilter("Rank", arrayOf( private class RankFilter : UriPartFilter(
"Rank",
arrayOf(
Pair("All", "all"), Pair("All", "all"),
Pair("1 - 999", "1-999"), Pair("1 - 999", "1-999"),
Pair("1k - 2k", "1000-2000"), Pair("1k - 2k", "1000-2000"),
@ -234,80 +241,84 @@ class MangaRockEs : ParsedHttpSource() {
Pair("8k - 9k", "8000-9000"), Pair("8k - 9k", "8000-9000"),
Pair("9k - 19k", "9000-10000"), Pair("9k - 19k", "9000-10000"),
Pair("10k - 11k", "10000-11000") Pair("10k - 11k", "10000-11000")
)) )
)
private class SortBy : UriPartFilter("Sort by", arrayOf( private class SortBy : UriPartFilter(
"Sort by",
arrayOf(
Pair("Name", "name"), Pair("Name", "name"),
Pair("Rank", "rank") Pair("Rank", "rank")
)) )
)
private class Genre(name: String, val uriPart: String) : Filter.CheckBox(name) private class Genre(name: String, val uriPart: String) : Filter.CheckBox(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
// Search and filter don't work at the same time // Search and filter don't work at the same time
Filter.Header("NOTE: Ignored if using text search!"), Filter.Header("NOTE: Ignored if using text search!"),
Filter.Separator(), Filter.Separator(),
StatusFilter(), StatusFilter(),
RankFilter(), RankFilter(),
SortBy(), SortBy(),
GenreList(getGenreList()) GenreList(getGenreList())
) )
// [...document.querySelectorAll('._2DMqI .mdl-checkbox')].map(n => `Genre("${n.querySelector('.mdl-checkbox__label').innerText}", "${n.querySelector('input').dataset.oid}")`).sort().join(',\n') // [...document.querySelectorAll('._2DMqI .mdl-checkbox')].map(n => `Genre("${n.querySelector('.mdl-checkbox__label').innerText}", "${n.querySelector('input').dataset.oid}")`).sort().join(',\n')
// on https://mangarock.com/manga // on https://mangarock.com/manga
private fun getGenreList() = listOf( private fun getGenreList() = listOf(
Genre("4-koma", "4-koma"), Genre("4-koma", "4-koma"),
Genre("Action", "action"), Genre("Action", "action"),
Genre("Adult", "adult"), Genre("Adult", "adult"),
Genre("Adventure", "adventure"), Genre("Adventure", "adventure"),
Genre("Comedy", "comedy"), Genre("Comedy", "comedy"),
Genre("Demons", "demons"), Genre("Demons", "demons"),
Genre("Doujinshi", "doujinshi"), Genre("Doujinshi", "doujinshi"),
Genre("Drama", "drama"), Genre("Drama", "drama"),
Genre("Ecchi", "ecchi"), Genre("Ecchi", "ecchi"),
Genre("Fantasy", "fantasy"), Genre("Fantasy", "fantasy"),
Genre("Gender Bender", "gender-bender"), Genre("Gender Bender", "gender-bender"),
Genre("Harem", "harem"), Genre("Harem", "harem"),
Genre("Historical", "historical"), Genre("Historical", "historical"),
Genre("Horror", "horror"), Genre("Horror", "horror"),
Genre("Isekai", "isekai"), Genre("Isekai", "isekai"),
Genre("Josei", "josei"), Genre("Josei", "josei"),
Genre("Kids", "kids"), Genre("Kids", "kids"),
Genre("Magic", "magic"), Genre("Magic", "magic"),
Genre("Martial Arts", "martial-arts"), Genre("Martial Arts", "martial-arts"),
Genre("Mature", "mature"), Genre("Mature", "mature"),
Genre("Mecha", "mecha"), Genre("Mecha", "mecha"),
Genre("Military", "military"), Genre("Military", "military"),
Genre("Music", "music"), Genre("Music", "music"),
Genre("Mystery", "mystery"), Genre("Mystery", "mystery"),
Genre("One Shot", "one-shot"), Genre("One Shot", "one-shot"),
Genre("Parody", "parody"), Genre("Parody", "parody"),
Genre("Police", "police"), Genre("Police", "police"),
Genre("Psychological", "psychological"), Genre("Psychological", "psychological"),
Genre("Romance", "romance"), Genre("Romance", "romance"),
Genre("School Life", "school-life"), Genre("School Life", "school-life"),
Genre("Sci-Fi", "sci-fi"), Genre("Sci-Fi", "sci-fi"),
Genre("Seinen", "seinen"), Genre("Seinen", "seinen"),
Genre("Shoujo Ai", "shoujo-ai"), Genre("Shoujo Ai", "shoujo-ai"),
Genre("Shoujo", "shoujo"), Genre("Shoujo", "shoujo"),
Genre("Shounen Ai", "shounen-ai"), Genre("Shounen Ai", "shounen-ai"),
Genre("Shounen", "shounen"), Genre("Shounen", "shounen"),
Genre("Slice of Life", "slice-of-life"), Genre("Slice of Life", "slice-of-life"),
Genre("Smut", "smut"), Genre("Smut", "smut"),
Genre("Space", "space"), Genre("Space", "space"),
Genre("Sports", "sports"), Genre("Sports", "sports"),
Genre("Super Power", "super-power"), Genre("Super Power", "super-power"),
Genre("Supernatural", "supernatural"), Genre("Supernatural", "supernatural"),
Genre("Tragedy", "tragedy"), Genre("Tragedy", "tragedy"),
Genre("Vampire", "vampire"), Genre("Vampire", "vampire"),
Genre("Webtoons", "webtoons"), Genre("Webtoons", "webtoons"),
Genre("Yaoi", "yaoi"), Genre("Yaoi", "yaoi"),
Genre("Yuri", "yuri") Genre("Yuri", "yuri")
) )
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) : private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) { Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second fun toUriPart() = vals[state].second
} }
} }

View File

@ -12,13 +12,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import org.jsoup.Jsoup.parse import org.jsoup.Jsoup.parse
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class Mangasail : ParsedHttpSource() { class Mangasail : ParsedHttpSource() {
@ -155,7 +155,7 @@ class Mangasail : ParsedHttpSource() {
} }
private fun parseChapterDate(string: String): Long { private fun parseChapterDate(string: String): Long {
return dateFormat.parse(string.substringAfter("on ")).time return dateFormat.parse(string.substringAfter("on "))?.time ?: 0L
} }
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {

View File

@ -17,14 +17,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga 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 java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers import okhttp3.Headers
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import rx.Observable import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
/** /**
* Exact same code as Manga Life except for better chapter names thanks to Regex * Exact same code as Manga Life except for better chapter names thanks to Regex
@ -92,11 +92,13 @@ class Mangasee : HttpSource() {
val endRange = ((page * 24) - 1).let { if (it <= directory.lastIndex) it else directory.lastIndex } val endRange = ((page * 24) - 1).let { if (it <= directory.lastIndex) it else directory.lastIndex }
for (i in (((page - 1) * 24)..endRange)) { for (i in (((page - 1) * 24)..endRange)) {
mangas.add(SManga.create().apply { mangas.add(
title = directory[i]["s"].string SManga.create().apply {
url = "/manga/${directory[i]["i"].string}" title = directory[i]["s"].string
thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg" url = "/manga/${directory[i]["i"].string}"
}) thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg"
}
)
} }
return MangasPage(mangas, endRange < directory.lastIndex) return MangasPage(mangas, endRange < directory.lastIndex)
} }

View File

@ -8,14 +8,14 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Document import org.jsoup.nodes.Document
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangatown : ParsedHttpSource() { class Mangatown : ParsedHttpSource() {
@ -110,7 +110,7 @@ class Mangatown : ParsedHttpSource() {
date.contains("Yesterday") -> Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.timeInMillis date.contains("Yesterday") -> Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.timeInMillis
else -> { else -> {
try { try {
SimpleDateFormat("MMM dd,yyyy", Locale.US).parse(date).time SimpleDateFormat("MMM dd,yyyy", Locale.US).parse(date)?.time ?: 0L
} catch (e: Exception) { } catch (e: Exception) {
0L 0L
} }

View File

@ -6,13 +6,13 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
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
import org.jsoup.select.Elements import org.jsoup.select.Elements
import java.text.SimpleDateFormat
import java.util.Locale
class ManhwaTime : ParsedHttpSource() { class ManhwaTime : ParsedHttpSource() {

Some files were not shown because too many files have changed in this diff Show More