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 {
ext.kotlin_version = '1.3.72'
ext.coroutines_version = '1.3.5'
ext.kotlin_version = '1.4.10'
ext.coroutines_version = '1.3.9'
repositories {
google()
maven { url 'https://plugins.gradle.org/m2/' }
@ -10,7 +10,7 @@ buildscript {
classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$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 kotlin {
const val version = "1.3.72"
const val version = "1.4.10"
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.HttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
open class BoomManga(
override val name: String,
@ -69,11 +69,11 @@ open class BoomManga(
override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create()
chapter.url = element.select("a").attr("href")
chapter.chapter_number = element.select("[data-num]").attr("data-num").toFloat()
val date = element.select(".date").text()
if (date.isNotBlank()) { chapter.date_upload = parseDate(date) }
chapter.name = nameselector(element).trim()
chapter.url = element.select("a").attr("href")
chapter.chapter_number = element.select("[data-num]").attr("data-num").toFloat()
val date = element.select(".date").text()
if (date.isNotBlank()) { chapter.date_upload = parseDate(date) }
chapter.name = nameselector(element).trim()
return chapter
}
@ -84,7 +84,7 @@ open class BoomManga(
}
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 {

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.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
abstract class ComiCake(
override val name: String,
@ -146,7 +146,7 @@ abstract class ComiCake(
private fun parseChapterJson(obj: JSONObject) = SChapter.create().apply {
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()
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)
url = obj.getString("manifest")
}

View File

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

View File

@ -38,8 +38,9 @@ fun ExGalleryMetadata.copyTo(manga: SManga) {
manga.status = SManga.COMPLETED
title?.let { t ->
if (ONGOING_SUFFIX.any {
t.endsWith(it, ignoreCase = true)
}) manga.status = SManga.ONGOING
t.endsWith(it, ignoreCase = true)
}
) manga.status = SManga.ONGOING
}
// 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 {
val json = gson.fromJson<JsonArray>(response.body()!!.string()).asJsonArray
return MangasPage(json.map {
SManga.create().apply {
val id = it["id"].asString
url = id
title = it["name"].asString
thumbnail_url = "https://www.elimangas.com/images/$id.jpg"
}
}, json.size() >= 30)
return MangasPage(
json.map {
SManga.create().apply {
val id = it["id"].asString
url = id
title = it["name"].asString
thumbnail_url = "https://www.elimangas.com/images/$id.jpg"
}
},
json.size() >= 30
)
}
// 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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.util.Calendar
import java.util.concurrent.TimeUnit
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.Calendar
import java.util.concurrent.TimeUnit
open class Emerald(
override val name: String,
@ -76,8 +76,11 @@ open class Emerald(
}
}
if (styleToInclude.isNotEmpty()) {
url.addQueryParameter("styles", styleToInclude
.joinToString(","))
url.addQueryParameter(
"styles",
styleToInclude
.joinToString(",")
)
}
}
is DemographicFilter -> {
@ -88,8 +91,11 @@ open class Emerald(
}
}
if (demographicToInclude.isNotEmpty()) {
url.addQueryParameter("demogs", demographicToInclude
.joinToString(","))
url.addQueryParameter(
"demogs",
demographicToInclude
.joinToString(",")
)
}
}
is StatusFilter -> {
@ -110,8 +116,11 @@ open class Emerald(
}
}
if (genreToInclude.isNotEmpty()) {
url.addQueryParameter("genres", genreToInclude
.joinToString(","))
url.addQueryParameter(
"genres",
genreToInclude
.joinToString(",")
)
}
}
is StarFilter -> {
@ -154,8 +163,10 @@ open class Emerald(
val manga = SManga.create()
val genres = mutableListOf<String>()
val status = infoElement.select("div.attr-item:contains(status) span").text()
infoElement.select("div.attr-item:contains(genres) span").text().split(" / "
.toRegex()).forEach { element ->
infoElement.select("div.attr-item:contains(genres) span").text().split(
" / "
.toRegex()
).forEach { element ->
genres.add(element)
}
manga.title = infoElement.select("h3").text()
@ -259,10 +270,12 @@ open class Emerald(
val imgJson = JSONObject(script)
val imgNames = imgJson.names()
for (i in 0 until imgNames.length()) {
val imgKey = imgNames.getString(i)
val imgUrl = imgJson.getString(imgKey)
pages.add(Page(i, "", imgUrl))
if (imgNames != null) {
for (i in 0 until imgNames.length()) {
val imgKey = imgNames.getString(i)
val imgUrl = imgJson.getString(imgKey)
pages.add(Page(i, "", imgUrl))
}
}
return pages
@ -276,40 +289,49 @@ open class Emerald(
private class GenreFilter(genres: List<Tag>) : Filter.Group<Tag>("Genres", genres)
private class StatusFilter : Filter.TriState("Completed")
private class StarFilter : UriPartFilter("Stars", arrayOf(
Pair("<select>", ""),
Pair("5 Stars", "5"),
Pair("4 Stars", "4"),
Pair("3 Stars", "3"),
Pair("2 Stars", "2"),
Pair("1 Stars", "1")
))
private class StarFilter : UriPartFilter(
"Stars",
arrayOf(
Pair("<select>", ""),
Pair("5 Stars", "5"),
Pair("4 Stars", "4"),
Pair("3 Stars", "3"),
Pair("2 Stars", "2"),
Pair("1 Stars", "1")
)
)
private class ChapterFilter : UriPartFilter("Chapters", arrayOf(
Pair("<select>", ""),
Pair("1 ~ 9", "1-9"),
Pair("10 ~ 29", "10-29"),
Pair("30 ~ 99", "30-99"),
Pair("100 ~ 199", "100-199"),
Pair("200+", "200"),
Pair("100+", "100"),
Pair("50+", "50"),
Pair("10+", "10"),
Pair("1+", "1")
))
private class ChapterFilter : UriPartFilter(
"Chapters",
arrayOf(
Pair("<select>", ""),
Pair("1 ~ 9", "1-9"),
Pair("10 ~ 29", "10-29"),
Pair("30 ~ 99", "30-99"),
Pair("100 ~ 199", "100-199"),
Pair("200+", "200"),
Pair("100+", "100"),
Pair("50+", "50"),
Pair("10+", "10"),
Pair("1+", "1")
)
)
private class SortBy : UriPartFilter("Sorts By", arrayOf(
Pair("<select>", ""),
Pair("Totally", "views_t"),
Pair("365 days", "views_y"),
Pair("30 days", "views_m"),
Pair("7 days", "views_w"),
Pair("24 hours", "views_d"),
Pair("60 minutes", "views_h"),
Pair("A-Z", "title"),
Pair("Update time", "update"),
Pair("Add time", "create")
))
private class SortBy : UriPartFilter(
"Sorts By",
arrayOf(
Pair("<select>", ""),
Pair("Totally", "views_t"),
Pair("365 days", "views_y"),
Pair("30 days", "views_m"),
Pair("7 days", "views_w"),
Pair("24 hours", "views_d"),
Pair("60 minutes", "views_h"),
Pair("A-Z", "title"),
Pair("Update time", "update"),
Pair("Add time", "create")
)
)
override fun getFilterList() = FilterList(
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.nio.charset.Charset
import java.util.Calendar
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
@ -20,6 +18,8 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import java.nio.charset.Charset
import java.util.Calendar
/**
* For sites based on the Flat-Manga CMS
@ -81,11 +81,14 @@ abstract class FMReader(
url.addQueryParameter("ungenre", ungenre)
}
is SortBy -> {
url.addQueryParameter("sort", when (filter.state?.index) {
0 -> "name"
1 -> "views"
else -> "last_update"
})
url.addQueryParameter(
"sort",
when (filter.state?.index) {
0 -> "name"
1 -> "views"
else -> "last_update"
}
)
if (filter.state?.ascending == true)
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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import java.net.URLEncoder
import okhttp3.FormBody
import okhttp3.Interceptor
import okhttp3.OkHttpClient
@ -20,6 +19,7 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.net.URLEncoder
class FMReaderFactory : SourceFactory {
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> {
return response.asJsoup().let { document ->
document.select(chapterListSelector()).map { chapterFromElement(it).apply {
scanlator = document.select("div.row li:has(b:contains(Nhóm dịch)) small").text()
} }
document.select(chapterListSelector()).map {
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() }

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

View File

@ -4,8 +4,6 @@ import android.app.Application
import android.content.SharedPreferences
import android.support.v7.preference.CheckBoxPreference
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.get
import com.github.salomonbrys.kotson.string
@ -28,6 +26,8 @@ import rx.Single
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import androidx.preference.CheckBoxPreference as AndroidXCheckBoxPreference
import androidx.preference.PreferenceScreen as AndroidXPreferenceScreen
/**
* Ported from TachiyomiSy
@ -190,13 +190,13 @@ open class Hitomi(override val lang: String, private val nozomiLang: String) : H
}
}
return base.flatMap { (_, ids) ->
val chunks = ids.chunked(PAGE_SIZE)
return base.flatMap { (_, ids) ->
val chunks = ids.chunked(PAGE_SIZE)
nozomiIdsToMangas(chunks[page - 1]).map { mangas ->
MangasPage(mangas, page < chunks.size)
}
}.toObservable()
nozomiIdsToMangas(chunks[page - 1]).map { mangas ->
MangasPage(mangas, page < chunks.size)
}
}.toObservable()
}
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.asObservable
import eu.kanade.tachiyomi.network.asObservableSuccess
import java.security.MessageDigest
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import rx.Observable
import rx.Single
import java.security.MessageDigest
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.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import okhttp3.Credentials
import okhttp3.Headers
import okhttp3.HttpUrl
@ -38,6 +35,9 @@ import rx.android.schedulers.AndroidSchedulers
import rx.schedulers.Schedulers
import uy.kohesive.injekt.Injekt
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() {
override fun popularMangaRequest(page: Int): Request =
@ -215,8 +215,10 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
else -> SManga.UNKNOWN
}
// TODO: remove safe calls in next iteration
genre = (metadata.genres?.plus(metadata.tags ?: emptySet())
?: emptySet()).joinToString(", ")
genre = (
metadata.genres?.plus(metadata.tags ?: emptySet())
?: emptySet()
).joinToString(", ")
description = metadata.summary
}
@ -225,10 +227,10 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
Date().time
else {
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) {
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) {
Date().time
}
@ -370,65 +372,80 @@ open class Komga(suffix: String = "") : ConfigurableSource, HttpSource() {
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
libraries = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptyList()
}
}, {})
.subscribe(
{ response ->
libraries = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptyList()
}
},
{}
)
Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/collections?unpaged=true", headers)).execute()
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
collections = try {
gson.fromJson<PageWrapperDto<CollectionDto>>(response.body()?.charStream()!!).content
} catch (e: Exception) {
emptyList()
}
}, {})
.subscribe(
{ response ->
collections = try {
gson.fromJson<PageWrapperDto<CollectionDto>>(response.body()?.charStream()!!).content
} catch (e: Exception) {
emptyList()
}
},
{}
)
Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/genres", headers)).execute()
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
genres = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptySet()
}
}, {})
.subscribe(
{ response ->
genres = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptySet()
}
},
{}
)
Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/tags", headers)).execute()
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
tags = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptySet()
}
}, {})
.subscribe(
{ response ->
tags = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptySet()
}
},
{}
)
Single.fromCallable {
client.newCall(GET("$baseUrl/api/v1/publishers", headers)).execute()
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({ response ->
publishers = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptySet()
}
}, {})
.subscribe(
{ response ->
publishers = try {
gson.fromJson(response.body()?.charStream()!!)
} catch (e: Exception) {
emptySet()
}
},
{}
)
}
companion object {

View File

@ -59,7 +59,8 @@ open class LANraragi : ConfigurableSource, HttpSource() {
url = "${uriBuild.encodedPath}?${uriBuild.encodedQuery}"
chapter_number = 1F
name = "Chapter"
})
}
)
}
override fun pageListParse(response: Response): List<Page> {
@ -118,7 +119,9 @@ open class LANraragi : ConfigurableSource, HttpSource() {
artist = getArtist(it.tags)
author = artist
}
}, currentStart + jsonResult.data.size < jsonResult.recordsFiltered)
},
currentStart + jsonResult.data.size < jsonResult.recordsFiltered
)
}
// 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.online.ParsedHttpSource
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.FormBody
import okhttp3.Headers
@ -29,6 +22,13 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
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(
override val name: String,
@ -189,19 +189,25 @@ abstract class Madara(
private class ArtistFilter : Filter.Text("Artist")
private class YearFilter : Filter.Text("Year of Released")
private class StatusFilter(status: List<Tag>) : Filter.Group<Tag>("Status", status)
private class OrderByFilter : UriPartFilter("Order By", arrayOf(
Pair("<select>", ""),
Pair("Latest", "latest"),
Pair("A-Z", "alphabet"),
Pair("Rating", "rating"),
Pair("Trending", "trending"),
Pair("Most Views", "views"),
Pair("New", "new-manga")
))
private class GenreConditionFilter : UriPartFilter("Genre condition", arrayOf(
Pair("or", ""),
Pair("and", "1")
))
private class OrderByFilter : UriPartFilter(
"Order By",
arrayOf(
Pair("<select>", ""),
Pair("Latest", "latest"),
Pair("A-Z", "alphabet"),
Pair("Rating", "rating"),
Pair("Trending", "trending"),
Pair("Most Views", "views"),
Pair("New", "new-manga")
)
)
private class GenreConditionFilter : UriPartFilter(
"Genre condition",
arrayOf(
Pair("or", ""),
Pair("and", "1")
)
)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
class Genre(name: String, val id: String = name) : Filter.CheckBox(name)
@ -385,7 +391,7 @@ abstract class Madara(
.let { elements ->
if (elements.isEmpty() && !document.select(dataIdSelector).isNullOrEmpty())
getXhrChapters(document.select(dataIdSelector).attr("data-id")).select(chapterListSelector())
else elements
else elements
}
.map { chapterFromElement(it) }
}
@ -491,9 +497,13 @@ abstract class Madara(
override fun pageListParse(document: Document): List<Page> {
return document.select(pageListParseSelector).mapIndexed { index, element ->
Page(index, document.location(), element.select("img").first()?.let {
it.absUrl(if (it.hasAttr("data-src")) "data-src" else "src")
})
Page(
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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.CacheControl
import okhttp3.FormBody
import okhttp3.Headers
@ -23,6 +21,8 @@ import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MadaraFactory : SourceFactory {
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 ReadManhua : Madara("ReadManhua", "https://readmanhua.net", "en",
dateFormat = SimpleDateFormat("dd MMM yy", Locale.US))
class ReadManhua : Madara(
"ReadManhua",
"https://readmanhua.net",
"en",
dateFormat = SimpleDateFormat("dd MMM yy", Locale.US)
)
class IsekaiScanCom : Madara("IsekaiScan.com", "https://isekaiscan.com", "en")
class JustForFun : Madara("Just For Fun", "https://just-for-fun.ru", "ru",
dateFormat = SimpleDateFormat("yy.MM.dd", Locale.US))
class JustForFun : Madara(
"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") {
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 TsubakiNoScan : Madara("Tsubaki No Scan", "https://tsubakinoscan.com", "fr",
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US))
class TsubakiNoScan : Madara(
"Tsubaki No Scan",
"https://tsubakinoscan.com",
"fr",
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)
)
class YokaiJump : Madara("Yokai Jump", "https://yokaijump.fr", "fr",
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US))
class YokaiJump : Madara(
"Yokai Jump",
"https://yokaijump.fr",
"fr",
dateFormat = SimpleDateFormat("dd/MM/yy", Locale.US)
)
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 FirstKissManga : Madara("1st Kiss", "https://1stkissmanga.com", "en",
dateFormat = SimpleDateFormat("dd MMM yyyy", Locale.US)) {
class FirstKissManga : Madara(
"1st Kiss",
"https://1stkissmanga.com",
"en",
dateFormat = SimpleDateFormat("dd MMM yyyy", Locale.US)
) {
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 ChibiManga : Madara("Chibi Manga", "http://www.cmreader.info", "en",
dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)) {
class ChibiManga : Madara(
"Chibi Manga",
"http://www.cmreader.info",
"en",
dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.US)
) {
override fun chapterListParse(response: Response): List<SChapter> {
response.asJsoup().let { documet ->
documet.select("li.parent.has-child").let { volumes ->
@ -562,41 +586,43 @@ class DoujinHentai : Madara("DoujinHentai", "https://doujinhentai.net", "es", Si
GenreSelectFilter()
)
class GenreSelectFilter : UriPartFilter("Búsqueda de género", arrayOf(
Pair("<seleccionar>", ""),
Pair("Ecchi", "ecchi"),
Pair("Yaoi", "yaoi"),
Pair("Yuri", "yuri"),
Pair("Anal", "anal"),
Pair("Tetonas", "tetonas"),
Pair("Escolares", "escolares"),
Pair("Incesto", "incesto"),
Pair("Virgenes", "virgenes"),
Pair("Masturbacion", "masturbacion"),
Pair("Maduras", "maduras"),
Pair("Lolicon", "lolicon"),
Pair("Bikini", "bikini"),
Pair("Sirvientas", "sirvientas"),
Pair("Enfermera", "enfermera"),
Pair("Embarazada", "embarazada"),
Pair("Ahegao", "ahegao"),
Pair("Casadas", "casadas"),
Pair("Chica Con Pene", "chica-con-pene"),
Pair("Juguetes Sexuales", "juguetes-sexuales"),
Pair("Orgias", "orgias"),
Pair("Harem", "harem"),
Pair("Romance", "romance"),
Pair("Profesores", "profesores"),
Pair("Tentaculos", "tentaculos"),
Pair("Mamadas", "mamadas"),
Pair("Shota", "shota"),
Pair("Interracial", "interracial"),
Pair("Full Color", "full-colo"),
Pair("Sin Censura", "sin-censura"),
Pair("Futanari", "futanari"),
Pair("Doble Penetracion", "doble-penetracion"),
Pair("Cosplay", "cosplay")
)
class GenreSelectFilter : UriPartFilter(
"Búsqueda de género",
arrayOf(
Pair("<seleccionar>", ""),
Pair("Ecchi", "ecchi"),
Pair("Yaoi", "yaoi"),
Pair("Yuri", "yuri"),
Pair("Anal", "anal"),
Pair("Tetonas", "tetonas"),
Pair("Escolares", "escolares"),
Pair("Incesto", "incesto"),
Pair("Virgenes", "virgenes"),
Pair("Masturbacion", "masturbacion"),
Pair("Maduras", "maduras"),
Pair("Lolicon", "lolicon"),
Pair("Bikini", "bikini"),
Pair("Sirvientas", "sirvientas"),
Pair("Enfermera", "enfermera"),
Pair("Embarazada", "embarazada"),
Pair("Ahegao", "ahegao"),
Pair("Casadas", "casadas"),
Pair("Chica Con Pene", "chica-con-pene"),
Pair("Juguetes Sexuales", "juguetes-sexuales"),
Pair("Orgias", "orgias"),
Pair("Harem", "harem"),
Pair("Romance", "romance"),
Pair("Profesores", "profesores"),
Pair("Tentaculos", "tentaculos"),
Pair("Mamadas", "mamadas"),
Pair("Shota", "shota"),
Pair("Interracial", "interracial"),
Pair("Full Color", "full-colo"),
Pair("Sin Censura", "sin-censura"),
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.online.ParsedHttpSource
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.HttpUrl
import okhttp3.OkHttpClient
@ -21,6 +16,11 @@ import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
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

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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaBoxFactory : SourceFactory {
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.online.ParsedHttpSource
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.Headers
import okhttp3.HttpUrl
@ -45,6 +41,10 @@ import org.jsoup.parser.Parser
import rx.Observable
import uy.kohesive.injekt.Injekt
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(
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 ♥
private fun cleanString(string: String): String {
val bbRegex = """\[(\w+)[^]]*](.*?)\[/\1]""".toRegex()
val bbRegex =
"""\[(\w+)[^]]*](.*?)\[/\1]""".toRegex()
var intermediate = string
.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)
// default selection (Rating Descending) matches popularMangaRequest url
class SortFilter : Filter.Sort("Sort",
class SortFilter : Filter.Sort(
"Sort",
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())
@ -955,7 +958,8 @@ abstract class MangaDex(
Triple("Number of comments", 4, 5),
Triple("Rating", 6, 7),
Triple("Views", 8, 9),
Triple("Follows", 10, 11))
Triple("Follows", 10, 11)
)
private val SOURCE_LANG_LIST = listOf(
Pair("All", "0"),
@ -970,7 +974,8 @@ abstract class MangaDex(
Pair("Korean", "28"),
Pair("Spanish (LATAM)", "29"),
Pair("Thai", "32"),
Pair("Filipino", "34"))
Pair("Filipino", "34")
)
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.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
/**
* MangAdventure base source.
@ -88,9 +88,11 @@ abstract class MangAdventure(
when (it) {
is Person -> uri.appendQueryParameter("author", it.state)
is Status -> uri.appendQueryParameter("status", it.string())
is CategoryList -> cat.addAll(it.state.mapNotNull { c ->
Uri.encode(c.optString())
})
is CategoryList -> cat.addAll(
it.state.mapNotNull { c ->
Uri.encode(c.optString())
}
)
else -> Unit
}
}
@ -99,18 +101,21 @@ abstract class MangAdventure(
override fun latestUpdatesParse(response: Response) =
JSONArray(response.asString()).run {
MangasPage((0 until length()).map {
val obj = getJSONObject(it)
SManga.create().apply {
url = obj.getString("url")
title = obj.getString("title")
thumbnail_url = obj.getString("cover")
// A bit of a hack to sort by date
description = httpDateToTimestamp(
obj.getJSONObject("latest_chapter").getString("date")
).toString()
}
}.sortedByDescending(SManga::description), false)
MangasPage(
(0 until length()).map {
val obj = getJSONObject(it)
SManga.create().apply {
url = obj.getString("url")
title = obj.getString("title")
thumbnail_url = obj.getString("cover")
// A bit of a hack to sort by date
description = httpDateToTimestamp(
obj.getJSONObject("latest_chapter").getString("date")
).toString()
}
}.sortedByDescending(SManga::description),
false
)
}
override fun chapterListParse(response: Response) =
@ -143,9 +148,12 @@ abstract class MangAdventure(
override fun searchMangaParse(response: Response) =
JSONArray(response.asString()).run {
MangasPage((0 until length()).map {
SManga.create().fromJSON(getJSONObject(it))
}.sortedBy(SManga::title), false)
MangasPage(
(0 until length()).map {
SManga.create().fromJSON(getJSONObject(it))
}.sortedBy(SManga::title),
false
)
}
override fun getFilterList() =
@ -226,7 +234,7 @@ abstract class MangAdventure(
* @return The timestamp of the date.
*/
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.
*/
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)
intent?.data?.pathSegments?.takeIf { it.size > 1 }?.let {
try {
startActivity(Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", MangAdventure.SLUG_QUERY + it[1])
putExtra("filter", packageName)
})
startActivity(
Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", MangAdventure.SLUG_QUERY + it[1])
putExtra("filter", packageName)
}
)
} catch (ex: ActivityNotFoundException) {
Log.e("MangAdventureActivity", ex.message, ex)
}
@ -30,6 +32,7 @@ class MangAdventureActivity : Activity() {
}
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 eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import java.text.DecimalFormat
import okhttp3.Response
import org.json.JSONArray
import org.json.JSONObject
import java.text.DecimalFormat
/** Returns the body of a response as a `String`. */
fun Response.asString(): String = body()!!.string()
@ -62,9 +62,9 @@ fun SManga.fromJSON(obj: JSONObject) = apply {
title = obj.getString("title")
description = obj.getString("description")
thumbnail_url = obj.getString("cover")
author = obj.getJSONArray("authors")?.joinField(0)
artist = obj.getJSONArray("artists")?.joinField(0)
genre = obj.getJSONArray("categories")?.joinField("name")
author = obj.getJSONArray("authors").joinField(0)
artist = obj.getJSONArray("artists").joinField(0)
genre = obj.getJSONArray("categories").joinField("name")
status = if (obj.getBoolean("completed"))
SManga.COMPLETED else SManga.ONGOING
}
@ -82,11 +82,14 @@ fun SChapter.fromJSON(obj: JSONObject) = apply {
url = obj.getString("url")
chapter_number = obj.optString("chapter", "0").toFloat()
date_upload = MangAdventure.httpDateToTimestamp(obj.getString("date"))
scanlator = obj.getJSONArray("groups")?.joinField("name", " & ")
name = obj.optString("full_title", buildString {
obj.optInt("volume").let { if (it != 0) append("Vol. $it, ") }
append("Ch. ${chapter_number.format("#.#")}: ")
append(obj.getString("title"))
})
scanlator = obj.getJSONArray("groups").joinField("name", " & ")
name = obj.optString(
"full_title",
buildString {
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]"
}

View File

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

View File

@ -6,13 +6,14 @@ ext {
extName = 'MANGA Plus by SHUEISHA'
pkgNameSuffix = 'all.mangaplus'
extClass = '.MangaPlusFactory'
extVersionCode = 11
extVersionCode = 12
libVersion = '1.2'
}
dependencies {
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-protobuf:0.20.0'
implementation 'org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.20.0'
final serialization_version = '1.0.0-RC'
implementation "org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version"
implementation "org.jetbrains.kotlinx:kotlinx-serialization-protobuf:$serialization_version"
}
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.ListPreference
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.squareup.duktape.Duktape
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.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import java.util.UUID
import kotlinx.serialization.protobuf.ProtoBuf
import okhttp3.Headers
import okhttp3.HttpUrl
@ -33,6 +29,10 @@ import okhttp3.ResponseBody
import rx.Observable
import uy.kohesive.injekt.Injekt
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(
override val lang: String,
@ -428,7 +428,7 @@ abstract class MangaPlus(
private fun Response.asProto(): MangaPlusResponse {
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
// 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 res = Duktape.create().use {
it.set("helper", DuktapeHelper::class.java, object : DuktapeHelper {
override fun getProtobuf(): String = protobufJs
})
it.set(
"helper",
DuktapeHelper::class.java,
object : DuktapeHelper {
override fun getProtobuf(): String = protobufJs
}
)
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 kotlinx.serialization.Serializable
import kotlinx.serialization.Serializer
import kotlinx.serialization.protobuf.ProtoId
import kotlinx.serialization.protobuf.ProtoNumber
@Serializer(forClass = MangaPlusResponse::class)
object MangaPlusSerializer
@Serializable
data class MangaPlusResponse(
@ProtoId(1) val success: SuccessResult? = null,
@ProtoId(2) val error: ErrorResult? = null
@ProtoNumber(1) val success: SuccessResult? = null,
@ProtoNumber(2) val error: ErrorResult? = null
)
@Serializable
data class ErrorResult(
@ProtoId(1) val action: Action,
@ProtoId(2) val englishPopup: Popup,
@ProtoId(3) val spanishPopup: Popup
@ProtoNumber(1) val action: Action,
@ProtoNumber(2) val englishPopup: Popup,
@ProtoNumber(3) val spanishPopup: Popup
)
enum class Action { DEFAULT, UNAUTHORIZED, MAINTAINENCE, GEOIP_BLOCKING }
@Serializable
data class Popup(
@ProtoId(1) val subject: String,
@ProtoId(2) val body: String
@ProtoNumber(1) val subject: String,
@ProtoNumber(2) val body: String
)
@Serializable
data class SuccessResult(
@ProtoId(1) val isFeaturedUpdated: Boolean? = false,
@ProtoId(5) val allTitlesView: AllTitlesView? = null,
@ProtoId(6) val titleRankingView: TitleRankingView? = null,
@ProtoId(8) val titleDetailView: TitleDetailView? = null,
@ProtoId(10) val mangaViewer: MangaViewer? = null,
@ProtoId(11) val webHomeView: WebHomeView? = null
@ProtoNumber(1) val isFeaturedUpdated: Boolean? = false,
@ProtoNumber(5) val allTitlesView: AllTitlesView? = null,
@ProtoNumber(6) val titleRankingView: TitleRankingView? = null,
@ProtoNumber(8) val titleDetailView: TitleDetailView? = null,
@ProtoNumber(10) val mangaViewer: MangaViewer? = null,
@ProtoNumber(11) val webHomeView: WebHomeView? = null
)
@Serializable
data class TitleRankingView(@ProtoId(1) val titles: List<Title> = emptyList())
data class TitleRankingView(@ProtoNumber(1) val titles: List<Title> = emptyList())
@Serializable
data class AllTitlesView(@ProtoId(1) val titles: List<Title> = emptyList())
data class AllTitlesView(@ProtoNumber(1) val titles: List<Title> = emptyList())
@Serializable
data class WebHomeView(@ProtoId(2) val groups: List<UpdatedTitleGroup> = emptyList())
data class WebHomeView(@ProtoNumber(2) val groups: List<UpdatedTitleGroup> = emptyList())
@Serializable
data class TitleDetailView(
@ProtoId(1) val title: Title,
@ProtoId(2) val titleImageUrl: String,
@ProtoId(3) val overview: String,
@ProtoId(4) val backgroundImageUrl: String,
@ProtoId(5) val nextTimeStamp: Int = 0,
@ProtoId(6) val updateTiming: UpdateTiming? = UpdateTiming.DAY,
@ProtoId(7) val viewingPeriodDescription: String = "",
@ProtoId(8) val nonAppearanceInfo: String = "",
@ProtoId(9) val firstChapterList: List<Chapter> = emptyList(),
@ProtoId(10) val lastChapterList: List<Chapter> = emptyList(),
@ProtoId(14) val isSimulReleased: Boolean = true,
@ProtoId(17) val chaptersDescending: Boolean = true
@ProtoNumber(1) val title: Title,
@ProtoNumber(2) val titleImageUrl: String,
@ProtoNumber(3) val overview: String,
@ProtoNumber(4) val backgroundImageUrl: String,
@ProtoNumber(5) val nextTimeStamp: Int = 0,
@ProtoNumber(6) val updateTiming: UpdateTiming? = UpdateTiming.DAY,
@ProtoNumber(7) val viewingPeriodDescription: String = "",
@ProtoNumber(8) val nonAppearanceInfo: String = "",
@ProtoNumber(9) val firstChapterList: List<Chapter> = emptyList(),
@ProtoNumber(10) val lastChapterList: List<Chapter> = emptyList(),
@ProtoNumber(14) val isSimulReleased: Boolean = true,
@ProtoNumber(17) val chaptersDescending: Boolean = true
)
enum class UpdateTiming { NOT_REGULARLY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY, DAY }
@Serializable
data class MangaViewer(@ProtoId(1) val pages: List<MangaPlusPage> = emptyList())
data class MangaViewer(@ProtoNumber(1) val pages: List<MangaPlusPage> = emptyList())
@Serializable
data class Title(
@ProtoId(1) val titleId: Int,
@ProtoId(2) val name: String,
@ProtoId(3) val author: String,
@ProtoId(4) val portraitImageUrl: String,
@ProtoId(5) val landscapeImageUrl: String,
@ProtoId(6) val viewCount: Int = 0,
@ProtoId(7) val language: Language? = Language.ENGLISH
@ProtoNumber(1) val titleId: Int,
@ProtoNumber(2) val name: String,
@ProtoNumber(3) val author: String,
@ProtoNumber(4) val portraitImageUrl: String,
@ProtoNumber(5) val landscapeImageUrl: String,
@ProtoNumber(6) val viewCount: Int = 0,
@ProtoNumber(7) val language: Language? = Language.ENGLISH
)
@Serializable
enum class Language(val id: Int) {
@ProtoId(0)
@ProtoNumber(0)
@SerializedName("0")
ENGLISH(0),
@ProtoId(1)
@ProtoNumber(1)
@SerializedName("1")
SPANISH(1)
}
@Serializable
data class UpdatedTitleGroup(
@ProtoId(1) val groupName: String,
@ProtoId(2) val titles: List<UpdatedTitle> = emptyList()
@ProtoNumber(1) val groupName: String,
@ProtoNumber(2) val titles: List<UpdatedTitle> = emptyList()
)
@Serializable
data class UpdatedTitle(
@ProtoId(1) val title: Title? = null
@ProtoNumber(1) val title: Title? = null
)
@Serializable
data class Chapter(
@ProtoId(1) val titleId: Int,
@ProtoId(2) val chapterId: Int,
@ProtoId(3) val name: String,
@ProtoId(4) val subTitle: String? = null,
@ProtoId(6) val startTimeStamp: Int,
@ProtoId(7) val endTimeStamp: Int
@ProtoNumber(1) val titleId: Int,
@ProtoNumber(2) val chapterId: Int,
@ProtoNumber(3) val name: String,
@ProtoNumber(4) val subTitle: String? = null,
@ProtoNumber(6) val startTimeStamp: Int,
@ProtoNumber(7) val endTimeStamp: Int
)
@Serializable
data class MangaPlusPage(@ProtoId(1) val page: MangaPage? = null)
data class MangaPlusPage(@ProtoNumber(1) val page: MangaPage? = null)
@Serializable
data class MangaPage(
@ProtoId(1) val imageUrl: String,
@ProtoId(2) val width: Int,
@ProtoId(3) val height: Int,
@ProtoId(5) val encryptionKey: String? = null
@ProtoNumber(1) val imageUrl: String,
@ProtoNumber(2) val width: Int,
@ProtoNumber(3) val height: Int,
@ProtoNumber(5) val encryptionKey: String? = null
)
// Used for the deserialization on KitKat devices.
const val DECODE_SCRIPT: String = """
const val DECODE_SCRIPT: String =
"""
Duktape.modSearch = function(id) {
if (id == "protobufjs")
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.HttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
open class MangaToon(
override val lang: String,
@ -73,16 +73,16 @@ open class MangaToon(
override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create()
chapter.url = element.select("a").first().attr("href")
chapter.chapter_number = element.select("div.item-left").text().trim().toFloat()
chapter.url = element.select("a").first().attr("href")
chapter.chapter_number = element.select("div.item-left").text().trim().toFloat()
val date = element.select("div.episode-date").text()
chapter.date_upload = parseDate(date)
chapter.name = if (chapter.chapter_number> 20) { "\uD83D\uDD12 " } else { "" } + element.select("div.episode-title").text().trim()
chapter.date_upload = parseDate(date)
chapter.name = if (chapter.chapter_number> 20) { "\uD83D\uDD12 " } else { "" } + element.select("div.episode-title").text().trim()
return chapter
}
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 {

View File

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

View File

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

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

View File

@ -251,12 +251,14 @@ open class NHentai(
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
return listOf(SChapter.create().apply {
name = "Chapter"
scanlator = getGroups(document)
date_upload = getTime(document)
setUrlWithoutDomain(response.request().url().encodedPath())
})
return listOf(
SChapter.create().apply {
name = "Chapter"
scanlator = getGroups(document)
date_upload = getTime(document)
setUrlWithoutDomain(response.request().url().encodedPath())
}
)
}
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.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.util.Date
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import rx.Observable
import java.util.Date
@Nsfw
class NineHentai : HttpSource() {
@ -51,26 +51,26 @@ class NineHentai : HttpSource() {
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
return client.newCall(popularMangaRequest(page))
.asObservableSuccess()
.map { response ->
getMangaList(response, page)
}
.asObservableSuccess()
.map { response ->
getMangaList(response, page)
}
}
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
return client.newCall(latestUpdatesRequest(page))
.asObservableSuccess()
.map { response ->
getMangaList(response, page)
}
.asObservableSuccess()
.map { response ->
getMangaList(response, page)
}
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return client.newCall(searchMangaRequest(page, query, filters))
.asObservableSuccess()
.map { response ->
getMangaList(response, page)
}
.asObservableSuccess()
.map { response ->
getMangaList(response, page)
}
}
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 Sorting : Filter.Sort("Sorting",
arrayOf("Newest", "Popular Right now", "Most Fapped", "Most Viewed", "By Title"),
Selection(1, false))
private class Sorting : Filter.Sort(
"Sorting",
arrayOf("Newest", "Popular Right now", "Most Fapped", "Most Viewed", "By Title"),
Selection(1, false)
)
override fun getFilterList() = FilterList(
Sorting(),
GenreList(NHTags.getTagsList())
Sorting(),
GenreList(NHTags.getTagsList())
)
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.SManga
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.HttpUrl
import okhttp3.Request
import org.jsoup.nodes.Document
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() {
@ -84,7 +84,7 @@ open class NineManga(override val name: String, override val baseUrl: String, ov
if (dateWords.size == 3) {
if (dateWords[1].contains(",")) {
return try {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) {
0L
}
@ -161,21 +161,27 @@ open class NineManga(override val name: String, override val baseUrl: String, ov
fun toUriPart() = vals[state].second
}
protected open class ContainBeginEndFilter(name: String) : UriPartFilter(name, arrayOf(
Pair("Contain", "contain"),
Pair("Begin", "begin"),
Pair("End", "end")
))
protected open class ContainBeginEndFilter(name: String) : UriPartFilter(
name,
arrayOf(
Pair("Contain", "contain"),
Pair("Begin", "begin"),
Pair("End", "end")
)
)
private class QueryCBEFilter : ContainBeginEndFilter("Query")
private class AuthorCBEFilter : ContainBeginEndFilter("Author")
private class ArtistCBEFilter : ContainBeginEndFilter("Artist")
private class CompletedFilter : UriPartFilter("Completed", arrayOf(
Pair("Either", "either"),
Pair("Yes", "yes"),
Pair("No", "no")
))
private class CompletedFilter : UriPartFilter(
"Completed",
arrayOf(
Pair("Either", "either"),
Pair("Yes", "yes"),
Pair("No", "no")
)
)
override fun getFilterList() = FilterList(
QueryCBEFilter(),

View File

@ -4,12 +4,12 @@ import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.SManga
import okhttp3.Request
import org.jsoup.nodes.Element
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Request
import org.jsoup.nodes.Element
class NineMangaFactory : SourceFactory {
override fun createSources(): List<Source> = listOf(
@ -756,7 +756,7 @@ fun parseChapterDateByLang(date: String): Long {
if (dateWords.size == 3) {
if (dateWords[1].contains(",")) {
return try {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) {
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
@ -18,6 +15,9 @@ import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
abstract class Paprika(
override val name: String,
@ -161,8 +161,9 @@ abstract class Paprika(
else -> null
}?.timeInMillis ?: 0L
}
else -> SimpleDateFormat("MMM d yy", Locale.US)
.parse("${this.substringBefore(",")} $currentYear")?.time ?: 0
else ->
SimpleDateFormat("MMM d yy", Locale.US)
.parse("${this.substringBefore(",")} $currentYear")?.time ?: 0
}
} catch (_: Exception) {
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
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.
override fun popularMangaSelector() = when (lang) {
"en" -> "#categories-7 ul li.cat-item-589813936," + // Chapter Secrets
"#categories-7 ul li.cat-item-607613583, " + // Chapter Secrets Specials
"#categories-7 ul li.cat-item-43972770, " + // Charlotte Family
"#categories-7 ul li.cat-item-9363667, " + // Complete Guides
"#categories-7 ul li.cat-item-634609261, " + // Parody Chapter
"#categories-7 ul li.cat-item-699200615, " + // Return to the Reverie
"#categories-7 ul li.cat-item-139757, " + // SBS
"#categories-7 ul li.cat-item-22695, " + // Timeline
"#categories-7 ul li.cat-item-648324575" // Vivre Card Databook
"en" ->
"#categories-7 ul li.cat-item-589813936," + // Chapter Secrets
"#categories-7 ul li.cat-item-607613583, " + // Chapter Secrets Specials
"#categories-7 ul li.cat-item-43972770, " + // Charlotte Family
"#categories-7 ul li.cat-item-9363667, " + // Complete Guides
"#categories-7 ul li.cat-item-634609261, " + // Parody Chapter
"#categories-7 ul li.cat-item-699200615, " + // Return to the Reverie
"#categories-7 ul li.cat-item-139757, " + // SBS
"#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
"fr" -> "#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 {
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"
@ -180,7 +181,8 @@ class TheLibraryOfOhara(override val lang: String, private val siteLang: String)
!it.name.contains("Arabic") &&
!it.name.contains("Italian") &&
!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.SManga
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.OkHttpClient
import okhttp3.Request
@ -18,6 +14,10 @@ import okhttp3.RequestBody
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.net.URLDecoder
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.concurrent.TimeUnit
abstract class ToomicsGlobal(
private val siteLang: String,
@ -153,7 +153,7 @@ abstract class ToomicsGlobal(
private fun parseChapterDate(date: String): Long {
return try {
dateFormat.parse(date).time
dateFormat.parse(date)?.time ?: 0L
} catch (e: ParseException) {
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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class DongmanManhua : WebtoonsDefault("zh", "", dateFormat = SimpleDateFormat("yyyy-M-d", Locale.ENGLISH)) {
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.util.Calendar
import okhttp3.Cookie
import okhttp3.CookieJar
import okhttp3.Headers
@ -19,6 +18,7 @@ import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.Calendar
abstract class Webtoons(
override val lang: String,
@ -33,21 +33,23 @@ abstract class Webtoons(
override val supportsLatest = true
override val client: OkHttpClient = super.client.newBuilder()
.cookieJar(object : CookieJar {
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return listOf<Cookie>(
Cookie.Builder()
.domain("www.webtoons.com")
.path("/")
.name("ageGatePass")
.value("true")
.name("locale")
.value(localeForCookie)
.build()
)
.cookieJar(
object : CookieJar {
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return listOf<Cookie>(
Cookie.Builder()
.domain("www.webtoons.com")
.path("/")
.name("ageGatePass")
.value("true")
.name("locale")
.value(localeForCookie)
.build()
)
}
}
})
)
.build()
private val day: String
@ -71,11 +73,11 @@ abstract class Webtoons(
override fun latestUpdatesSelector() = "div#dailyList > $day li > a"
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()
.add("Referer", "https://m.webtoons.com")
.build()
.add("Referer", "https://m.webtoons.com")
.build()
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.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import java.text.SimpleDateFormat
import java.util.Locale
import org.json.JSONObject
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
open class WebtoonsDefault(
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
// instead.
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 {
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.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import java.util.ArrayList
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Request
@ -16,6 +15,7 @@ import org.json.JSONObject
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.util.ArrayList
open class WebtoonsTranslate(override val lang: String, private val translateLangCode: String, languageNameExtra: String = "") : Webtoons(lang) {
// 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")
return SManga.create().apply {
title = json.getString("representTitle")
author = json.getString("writeAuthorName")
artist = json.getString("pictureAuthorName") ?: author
thumbnail_url = if (relativeThumnailURL != null) "$thumbnailBaseUrl$relativeThumnailURL" else null
status = SManga.UNKNOWN
url = mobileBaseUrl
.resolve("/translate/episodeList")!!
.newBuilder()
.addQueryParameter("titleNo", json.getInt("titleNo").toString())
.addQueryParameter("languageCode", translateLangCode)
.addQueryParameter("teamVersion", json.optInt("teamVersion", 0).toString())
.build()
.toString()
}
title = json.getString("representTitle")
author = json.getString("writeAuthorName")
artist = json.getString("pictureAuthorName") ?: author
thumbnail_url = if (relativeThumnailURL != null) "$thumbnailBaseUrl$relativeThumnailURL" else null
status = SManga.UNKNOWN
url = mobileBaseUrl
.resolve("/translate/episodeList")!!
.newBuilder()
.addQueryParameter("titleNo", json.getInt("titleNo").toString())
.addQueryParameter("languageCode", translateLangCode)
.addQueryParameter("teamVersion", json.optInt("teamVersion", 0).toString())
.build()
.toString()
}
}
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
abstract class WPComics(
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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class WPComicsFactory : SourceFactory {
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 {
element.select("h3 a").let {
title = it.text()
setUrlWithoutDomain(it.attr("href"))
}
title = it.text()
setUrlWithoutDomain(it.attr("href"))
}
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.SManga
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.HttpUrl
import okhttp3.OkHttpClient
@ -26,6 +22,10 @@ import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import uy.kohesive.injekt.Injekt
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(
override val name: String,
@ -273,28 +273,37 @@ abstract class WPMangaStream(
private class YearFilter : Filter.Text("Year")
protected class TypeFilter : UriPartFilter("Type", arrayOf(
Pair("Default", ""),
Pair("Manga", "Manga"),
Pair("Manhwa", "Manhwa"),
Pair("Manhua", "Manhua"),
Pair("Comic", "Comic")
))
protected class TypeFilter : UriPartFilter(
"Type",
arrayOf(
Pair("Default", ""),
Pair("Manga", "Manga"),
Pair("Manhwa", "Manhwa"),
Pair("Manhua", "Manhua"),
Pair("Comic", "Comic")
)
)
protected class SortByFilter : UriPartFilter("Sort By", arrayOf(
Pair("Default", ""),
Pair("A-Z", "title"),
Pair("Z-A", "titlereverse"),
Pair("Latest Update", "update"),
Pair("Latest Added", "latest"),
Pair("Popular", "popular")
))
protected class SortByFilter : UriPartFilter(
"Sort By",
arrayOf(
Pair("Default", ""),
Pair("A-Z", "title"),
Pair("Z-A", "titlereverse"),
Pair("Latest Update", "update"),
Pair("Latest Added", "latest"),
Pair("Popular", "popular")
)
)
protected class StatusFilter : UriPartFilter("Status", arrayOf(
Pair("All", ""),
Pair("Ongoing", "ongoing"),
Pair("Completed", "completed")
))
protected class StatusFilter : UriPartFilter(
"Status",
arrayOf(
Pair("All", ""),
Pair("Ongoing", "ongoing"),
Pair("Completed", "completed")
)
)
protected class Genre(name: String, val id: String = name) : Filter.TriState(name)
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.SManga
import eu.kanade.tachiyomi.util.asJsoup
import java.io.IOException
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Interceptor
@ -20,6 +19,7 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.io.IOException
class WPMangaStreamFactory : SourceFactory {
override fun createSources(): List<Source> = listOf(
@ -198,66 +198,72 @@ class WestManga : WPMangaStream("West Manga (WP Manga Stream)", "https://westman
return manga
}
private class SortByFilter : UriPartFilter("Sort By", arrayOf(
Pair("Default", ""),
Pair("A-Z", "A-Z"),
Pair("Latest Added", "latest"),
Pair("Popular", "popular")
))
private class SortByFilter : UriPartFilter(
"Sort By",
arrayOf(
Pair("Default", ""),
Pair("A-Z", "A-Z"),
Pair("Latest Added", "latest"),
Pair("Popular", "popular")
)
)
private class GenreListFilter : UriPartFilter("Genre", arrayOf(
Pair("Default", ""),
Pair("4-Koma", "4-koma"),
Pair("Action", "action"),
Pair("Adventure", "adventure"),
Pair("Comedy", "comedy"),
Pair("Cooking", "cooking"),
Pair("Demons", "demons"),
Pair("Drama", "drama"),
Pair("Ecchi", "ecchi"),
Pair("Fantasy", "fantasy"),
Pair("FantasyAction", "fantasyaction"),
Pair("Game", "game"),
Pair("Gender Bender", "gender-bender"),
Pair("Gore", "gore"),
Pair("Harem", "harem"),
Pair("Historical", "historical"),
Pair("Horro", "horro"),
Pair("Horror", "horror"),
Pair("Isekai", "isekai"),
Pair("Isekai Action", "isekai-action"),
Pair("Josei", "josei"),
Pair("Magic", "magic"),
Pair("Manga", "manga"),
Pair("Manhua", "manhua"),
Pair("Martial arts", "martial-arts"),
Pair("Mature", "mature"),
Pair("Mecha", "mecha"),
Pair("Medical", "medical"),
Pair("Music", "music"),
Pair("Mystery", "mystery"),
Pair("Oneshot", "oneshot"),
Pair("Project", "project"),
Pair("Psychological", "psychological"),
Pair("Romance", "romance"),
Pair("School", "school"),
Pair("School life", "school-life"),
Pair("Sci fi", "sci-fi"),
Pair("Seinen", "seinen"),
Pair("Shoujo", "shoujo"),
Pair("Shoujo Ai", "shoujo-ai"),
Pair("Shounen", "shounen"),
Pair("Slice of Life", "slice-of-life"),
Pair("Sports", "sports"),
Pair("Super Power", "super-power"),
Pair("Supernatural", "supernatural"),
Pair("Suspense", "suspense"),
Pair("Thriller", "thriller"),
Pair("Tragedy", "tragedy"),
Pair("Vampire", "vampire"),
Pair("Webtoons", "webtoons"),
Pair("Yuri", "yuri")
))
private class GenreListFilter : UriPartFilter(
"Genre",
arrayOf(
Pair("Default", ""),
Pair("4-Koma", "4-koma"),
Pair("Action", "action"),
Pair("Adventure", "adventure"),
Pair("Comedy", "comedy"),
Pair("Cooking", "cooking"),
Pair("Demons", "demons"),
Pair("Drama", "drama"),
Pair("Ecchi", "ecchi"),
Pair("Fantasy", "fantasy"),
Pair("FantasyAction", "fantasyaction"),
Pair("Game", "game"),
Pair("Gender Bender", "gender-bender"),
Pair("Gore", "gore"),
Pair("Harem", "harem"),
Pair("Historical", "historical"),
Pair("Horro", "horro"),
Pair("Horror", "horror"),
Pair("Isekai", "isekai"),
Pair("Isekai Action", "isekai-action"),
Pair("Josei", "josei"),
Pair("Magic", "magic"),
Pair("Manga", "manga"),
Pair("Manhua", "manhua"),
Pair("Martial arts", "martial-arts"),
Pair("Mature", "mature"),
Pair("Mecha", "mecha"),
Pair("Medical", "medical"),
Pair("Music", "music"),
Pair("Mystery", "mystery"),
Pair("Oneshot", "oneshot"),
Pair("Project", "project"),
Pair("Psychological", "psychological"),
Pair("Romance", "romance"),
Pair("School", "school"),
Pair("School life", "school-life"),
Pair("Sci fi", "sci-fi"),
Pair("Seinen", "seinen"),
Pair("Shoujo", "shoujo"),
Pair("Shoujo Ai", "shoujo-ai"),
Pair("Shounen", "shounen"),
Pair("Slice of Life", "slice-of-life"),
Pair("Sports", "sports"),
Pair("Super Power", "super-power"),
Pair("Supernatural", "supernatural"),
Pair("Suspense", "suspense"),
Pair("Thriller", "thriller"),
Pair("Tragedy", "tragedy"),
Pair("Vampire", "vampire"),
Pair("Webtoons", "webtoons"),
Pair("Yuri", "yuri")
)
)
override fun getFilterList() = FilterList(
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 SortBy : UriPartFilter("Sort by", arrayOf(
Pair("Relevance", ""),
Pair("Latest", "latest"),
Pair("A-Z", "alphabet"),
Pair("Rating", "rating"),
Pair("Trending", "trending"),
Pair("Most View", "views"),
Pair("New", "new-manga")
))
private class SortBy : UriPartFilter(
"Sort by",
arrayOf(
Pair("Relevance", ""),
Pair("Latest", "latest"),
Pair("A-Z", "alphabet"),
Pair("Rating", "rating"),
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 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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
abstract class Zbulu(
override val name: String,
@ -82,9 +82,9 @@ abstract class Zbulu(
filters.forEach { filter ->
when (filter) {
is AuthorField -> {
if (filter.state.isNotBlank()) {
ret = "$baseUrl/author/${filter.state.replace(" ", "-")}/page-$page"
}
if (filter.state.isNotBlank()) {
ret = "$baseUrl/author/${filter.state.replace(" ", "-")}/page-$page"
}
}
is GenreFilter -> {
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')
// from $baseUrl
private class GenreFilter : UriPartFilter("Genres",
private class GenreFilter : UriPartFilter(
"Genres",
arrayOf(
Pair("Choose a genre", ""),
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.MediaType
import okhttp3.Request
import okhttp3.RequestBody
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class AndromedaScans : ParsedHttpSource() {
override val name = "AndromedaScans"

View File

@ -147,13 +147,16 @@ class MangaAe : ParsedHttpSource() {
fun toUriPart() = vals[state].second
}
private class OrderByFilter : UriPartFilter("الترتيب حسب", arrayOf(
Pair("اختيار", ""),
Pair("اسم المانجا", "english_name"),
Pair("تاريخ النشر", "release_date"),
Pair("عدد الفصول", "chapter_count"),
Pair("الحالة", "status")
))
private class OrderByFilter : UriPartFilter(
"الترتيب حسب",
arrayOf(
Pair("اختيار", ""),
Pair("اسم المانجا", "english_name"),
Pair("تاريخ النشر", "release_date"),
Pair("عدد الفصول", "chapter_count"),
Pair("الحالة", "status")
)
)
override fun getFilterList() = FilterList(
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.concurrent.TimeUnit
class TeamX : ParsedHttpSource() {
@ -44,8 +44,10 @@ class TeamX : ParsedHttpSource() {
return SManga.create().apply {
title = element.select(titleSelector).text()
setUrlWithoutDomain(element.select("a").first().attr("href"))
thumbnail_url = element.select("img").let { if (it.hasAttr("data-src"))
it.attr("abs:data-src") else it.attr("abs:src") }
thumbnail_url = element.select("img").let {
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()
description = info.select("div.story p").text()
genre = info.select("div.genre a").joinToString { it.text() }
thumbnail_url = info.select("img").let { if (it.hasAttr("data-src"))
it.attr("abs:data-src") else it.attr("abs:src") }
thumbnail_url = info.select("img").let {
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> {
return document.select("div#translationPageall img").mapIndexed { i, img ->
Page(i, "", img.let { if (it.hasAttr("data-src"))
it.attr("abs:data-src") else it.attr("abs:src") })
Page(
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.SManga
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.OkHttpClient
import okhttp3.Request
@ -26,6 +22,10 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class MangaTube : ParsedHttpSource() {
@ -156,7 +156,7 @@ class MangaTube : ParsedHttpSource() {
}
date_upload = element.select("p.chapter-date").text().let {
try {
SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).parse(it.substringAfter(" ")).time
SimpleDateFormat("dd.MM.yyyy", Locale.getDefault()).parse(it.substringAfter(" "))?.time ?: 0L
} catch (_: ParseException) {
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class WieManga : ParsedHttpSource() {
@ -119,7 +119,7 @@ class WieManga : ParsedHttpSource() {
}
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> {

View File

@ -47,8 +47,10 @@ class CloneManga : ParsedHttpSource() {
status = SManga.UNKNOWN
url = element.select("a").first().attr("href")
description = element.select("h4").first()?.text() ?: ""
thumbnail_url = baseUrl + attr.substring(attr.indexOf("site/themes"),
attr.indexOf(")"))
thumbnail_url = baseUrl + attr.substring(
attr.indexOf("site/themes"),
attr.indexOf(")")
)
}
}
@ -65,8 +67,10 @@ class CloneManga : ParsedHttpSource() {
val document = response.asJsoup()
val series = document.location()
val numChapters = Regex(
pattern = "&page=(.*)&lang=").findAll(
input = document.getElementsByTag("script")[3].toString())
pattern = "&page=(.*)&lang="
).findAll(
input = document.getElementsByTag("script")[3].toString()
)
.elementAt(3).destructured.component1()
.toInt()
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.net.URLEncoder
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl
import okhttp3.MediaType
import okhttp3.OkHttpClient
@ -19,6 +16,9 @@ import okhttp3.RequestBody
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.net.URLEncoder
import java.util.Calendar
import java.util.Locale
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.online.ParsedHttpSource
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.SimpleDateFormat
import java.util.ArrayList
@ -15,11 +20,6 @@ import java.util.Calendar
import java.util.Date
import java.util.Locale
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() {
@ -141,15 +141,13 @@ class ComicExtra : ParsedHttpSource() {
}
private fun dateParse(dateAsString: String): Long {
val date: Date
date = try {
val date: Date? = try {
SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH).parse(dateAsString.replace(Regex("(st|nd|rd|th)"), ""))
} catch (e: ParseException) {
val m = datePattern.matcher(dateAsString)
if (dateAsString != "Today" && m.matches()) {
val amount = m.group(1).toInt()
val amount = m.group(1)!!.toInt()
Calendar.getInstance().apply {
add(Calendar.DATE, -amount)
}.time
@ -158,7 +156,7 @@ class ComicExtra : ParsedHttpSource() {
} else return 0
}
return date.time
return date?.time ?: 0L
}
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.Headers
import okhttp3.OkHttpClient
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Dilbert : ParsedHttpSource() {
@ -46,20 +46,26 @@ class Dilbert : ParsedHttpSource() {
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
val currentYear = Calendar.getInstance().get(Calendar.YEAR)
return Observable.just(MangasPage((currentYear downTo 1989).map {
SManga.create().apply {
url = "?$it"
title = "$name ($it)"
artist = "Scott Adams"
author = "Scott Adams"
status = if (it < currentYear) SManga.COMPLETED else SManga.ONGOING
description = """
return Observable.just(
MangasPage(
(currentYear downTo 1989).map {
SManga.create().apply {
url = "?$it"
title = "$name ($it)"
artist = "Scott Adams"
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.
(This entry includes all the chapters published in $it.)
""".trimIndent()
thumbnail_url = "https://dilbert.com/assets/favicon/favicon-196x196-cf4d86b485e628a034ab8b961c1c3520b5969252400a80b9eed544d99403e037.png"
}
}, false))
""".trimIndent()
thumbnail_url = "https://dilbert.com/assets/favicon/favicon-196x196-cf4d86b485e628a034ab8b961c1c3520b5969252400a80b9eed544d99403e037.png"
}
},
false
)
)
}
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()
url = element.first(".img-comic-link").attr("href")
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>> {
@ -93,7 +99,8 @@ class Dilbert : ParsedHttpSource() {
if (pages != null) for (page in 2..pages) getChapters(page)
return Observable.just(
chapters.sortedBy(SChapter::date_upload).mapIndexed {
i, ch -> ch.apply { chapter_number = i + 1f }
i, ch ->
ch.apply { chapter_number = i + 1f }
}.reversed()
)
}

View File

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

View File

@ -8,9 +8,10 @@ class DynastyFactory : SourceFactory {
}
fun getAllDynasty() =
listOf(
DynastyAnthologies(),
DynastyChapters(),
DynastyDoujins(),
DynastyIssues(),
DynastySeries())
listOf(
DynastyAnthologies(),
DynastyChapters(),
DynastyDoujins(),
DynastyIssues(),
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Locale
import okhttp3.Request
import okhttp3.Response
import org.json.JSONArray
@ -19,6 +16,9 @@ import org.jsoup.nodes.Element
import org.jsoup.nodes.Node
import org.jsoup.nodes.TextNode
import org.jsoup.select.Elements
import java.text.SimpleDateFormat
import java.util.ArrayList
import java.util.Locale
abstract class DynastyScans : ParsedHttpSource() {
@ -70,8 +70,10 @@ abstract class DynastyScans : ParsedHttpSource() {
override fun searchMangaNextPageSelector() = "div.pagination > ul > li.active + li > a"
private fun buildListfromResponse(): List<Node> {
return client.newCall(Request.Builder().headers(headers)
.url(popularMangaInitialUrl()).build()).execute().asJsoup()
return client.newCall(
Request.Builder().headers(headers)
.url(popularMangaInitialUrl()).build()
).execute().asJsoup()
.select("div#main").first { it.hasText() }.childNodes()
}
@ -170,9 +172,9 @@ abstract class DynastyScans : ParsedHttpSource() {
val imageUrls = JSONArray("[$imageUrl]")
(0 until imageUrls.length())
.map { imageUrls.getJSONObject(it) }
.map { baseUrl + it.get("image") }
.forEach { pages.add(Page(pages.size, "", it)) }
.map { imageUrls.getJSONObject(it) }
.map { baseUrl + it.get("image") }
.forEach { pages.add(Page(pages.size, "", it)) }
} catch (e: Exception) {
e.printStackTrace()
}
@ -193,32 +195,32 @@ abstract class DynastyScans : ParsedHttpSource() {
}
if (type == "src") {
nodes
.filter { it is Element && it.hasClass("thumbnails") }
.flatMap { it.childNodes() }
.filterIsInstance<Element>()
.filter { it.hasClass("span2") }
.forEach { this.add(it.child(0).child(0).attr(type)) }
.filter { it is Element && it.hasClass("thumbnails") }
.flatMap { it.childNodes() }
.filterIsInstance<Element>()
.filter { it.hasClass("span2") }
.forEach { this.add(it.child(0).child(0).attr(type)) }
}
if (type == "href") {
nodes
.filter { it is Element && it.hasClass("thumbnails") }
.flatMap { it.childNodes() }
.filterIsInstance<Element>()
.filter { it.hasClass("span2") }
.forEach { this.add(it.child(0).attr(type)) }
.filter { it is Element && it.hasClass("thumbnails") }
.flatMap { it.childNodes() }
.filterIsInstance<Element>()
.filter { it.hasClass("span2") }
.forEach { this.add(it.child(0).attr(type)) }
}
}
fun indexOfPartial(partial: String): Int {
return (0..this.lastIndex).firstOrNull { this[it].contains(partial) }
?: -1
?: -1
}
fun getItem(partial: String): String {
return (0..this.lastIndex)
.firstOrNull { super.get(it).contains(partial) }
?.let { super.get(it) }
?: ""
.firstOrNull { super.get(it).contains(partial) }
?.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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.util.Calendar
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
@ -19,6 +18,7 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.util.Calendar
@Nsfw
class Eggporncomics : ParsedHttpSource() {
@ -129,21 +129,25 @@ class Eggporncomics : ParsedHttpSource() {
override fun mangaDetailsParse(document: Document): SManga {
return SManga.create().apply {
thumbnail_url = document.select(pageListSelector).first().toFullSizeImage()
description = document.select("div.links ul").joinToString("\n") { element -> element.select("a")
.joinToString(prefix = element.select("span").text().replace(descriptionPrefixRegex, ": ")) { it.text() } }
description = document.select("div.links ul").joinToString("\n") { element ->
element.select("a")
.joinToString(prefix = element.select("span").text().replace(descriptionPrefixRegex, ": ")) { it.text() }
}
}
}
// Chapters
override fun chapterListParse(response: Response): List<SChapter> {
return listOf(SChapter.create().apply {
setUrlWithoutDomain(response.request().url().toString())
name = "Chapter"
date_upload = response.asJsoup().select("div.info > div.meta li:contains(days ago)").firstOrNull()
?.let { Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -(it.text().substringBefore(" ").toIntOrNull() ?: 0)) }.timeInMillis }
?: 0
})
return listOf(
SChapter.create().apply {
setUrlWithoutDomain(response.request().url().toString())
name = "Chapter"
date_upload = response.asJsoup().select("div.info > div.meta li:contains(days ago)").firstOrNull()
?.let { Calendar.getInstance().apply { add(Calendar.DAY_OF_YEAR, -(it.text().substringBefore(" ").toIntOrNull() ?: 0)) }.timeInMillis }
?: 0
}
)
}
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.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
class Explosm : HttpSource() {
@ -92,7 +92,7 @@ class Explosm : HttpSource() {
element.select("div#comic-author").text().let { cName ->
name = cName
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)
}
override fun chapterListSelector() = """div.chapters option[value~=\d*]"""
override fun chapterListSelector() =
"""div.chapters option[value~=\d*]"""
override fun chapterListParse(response: Response): List<SChapter> {
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.SManga
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.Callback
import okhttp3.Headers
@ -29,6 +26,9 @@ import org.json.JSONObject
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
import java.util.HashMap
import java.util.concurrent.TimeUnit
open class Guya : ConfigurableSource, HttpSource() {
@ -40,10 +40,13 @@ open class Guya : ConfigurableSource, HttpSource() {
private val scanlatorCacheUrl = "$baseUrl/api/get_all_groups"
override fun headersBuilder() = Headers.Builder().apply {
add("User-Agent", "(Android ${Build.VERSION.RELEASE}; " +
"${Build.MANUFACTURER} ${Build.MODEL}) " +
"Tachiyomi/${BuildConfig.VERSION_NAME} " +
Build.ID)
add(
"User-Agent",
"(Android ${Build.VERSION.RELEASE}; " +
"${Build.MANUFACTURER} ${Build.MODEL}) " +
"Tachiyomi/${BuildConfig.VERSION_NAME} " +
Build.ID
)
}
private val scanlators: ScanlatorStore = ScanlatorStore()
@ -131,9 +134,12 @@ open class Guya : ConfigurableSource, HttpSource() {
metadata.put("chapter", chapterNum)
metadata.put("scanlator", scanlators.getKeyFromValue(chapter.scanlator.toString()))
metadata.put("slug", json.getString("slug"))
metadata.put("folder", json.getJSONObject("chapters")
.getJSONObject(chapterNum)
.getString("folder"))
metadata.put(
"folder",
json.getJSONObject("chapters")
.getJSONObject(chapterNum)
.getString("folder")
)
return parsePageFromJson(pages, metadata)
}
@ -320,10 +326,16 @@ open class Guya : ConfigurableSource, HttpSource() {
val pageArray = ArrayList<Page>()
for (i in 0 until pages.length()) {
val page = Page(i + 1, "", pageBuilder(metadata.getString("slug"),
metadata.getString("folder"),
pages[i].toString(),
metadata.getString("scanlator")))
val page = Page(
i + 1,
"",
pageBuilder(
metadata.getString("slug"),
metadata.getString("folder"),
pages[i].toString(),
metadata.getString("scanlator")
)
)
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.io.IOException
import okhttp3.CookieJar
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.io.IOException
@Nsfw
class HBrowse : ParsedHttpSource() {
@ -185,7 +185,7 @@ class HBrowse : ParsedHttpSource() {
override fun getFilterList(): FilterList {
return FilterList(
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.lang.UnsupportedOperationException
import java.util.Calendar
import java.util.regex.Pattern
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
@ -22,6 +19,9 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.lang.UnsupportedOperationException
import java.util.Calendar
import java.util.regex.Pattern
@Nsfw
class Hentai2Read : ParsedHttpSource() {
@ -182,7 +182,7 @@ class Hentai2Read : ParsedHttpSource() {
chapter.date_upload = element.select("div > small").text()?.let {
val matcher = chapterDatePattern.matcher(it)
if (matcher.find()) {
parseChapterDate(matcher.group(1))
parseChapterDate(matcher.group(1)!!)
} else {
0L
}
@ -216,7 +216,7 @@ class Hentai2Read : ParsedHttpSource() {
val m = pagesUrlPattern.matcher(response.body()!!.string())
var i = 0
while (m.find()) {
m.group(1).split(",").forEach {
m.group(1)?.split(",")?.forEach {
pages.add(Page(i++, "", imageBaseUrl + it.trim('"').replace("""\/""", "/")))
}
}
@ -245,27 +245,27 @@ class Hentai2Read : ParsedHttpSource() {
}
override fun getFilterList() = FilterList(
SortOrder(getSortOrder()),
MangaNameSelect(),
Filter.Separator(),
ArtistName(),
ArtistNameSelect(),
Filter.Separator(),
CharacterName(),
CharacterNameSelect(),
Filter.Separator(),
ReleaseYear(),
ReleaseYearSelect(),
Filter.Separator(),
Status(),
Filter.Separator(),
TagSearchMode(),
Filter.Separator(),
TagList("Categories", getCategoryList()),
Filter.Separator(),
TagList("Tags", getTagList()),
Filter.Separator(),
TagList("Doujins", getDoujinList())
SortOrder(getSortOrder()),
MangaNameSelect(),
Filter.Separator(),
ArtistName(),
ArtistNameSelect(),
Filter.Separator(),
CharacterName(),
CharacterNameSelect(),
Filter.Separator(),
ReleaseYear(),
ReleaseYearSelect(),
Filter.Separator(),
Status(),
Filter.Separator(),
TagSearchMode(),
Filter.Separator(),
TagList("Categories", getCategoryList()),
Filter.Separator(),
TagList("Tags", getTagList()),
Filter.Separator(),
TagList("Doujins", getDoujinList())
)
private fun getSortOrder() = arrayOf(

View File

@ -109,13 +109,15 @@ class HentaiFox : ParsedHttpSource() {
// Chapters
override fun chapterListParse(response: Response): List<SChapter> {
return listOf(SChapter.create().apply {
name = "Chapter"
// page path with a marker at the end
url = "${response.request().url().toString().replace("/gallery/", "/g/")}#"
// number of pages
url += response.asJsoup().select("[id=load_pages]").attr("value")
})
return listOf(
SChapter.create().apply {
name = "Chapter"
// page path with a marker at the end
url = "${response.request().url().toString().replace("/gallery/", "/g/")}#"
// number of pages
url += response.asJsoup().select("[id=load_pages]").attr("value")
}
)
}
override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
@ -146,59 +148,62 @@ class HentaiFox : ParsedHttpSource() {
)
// Top 50 tags
private class GenreFilter : UriPartFilter("Category", arrayOf(
Pair("<select>", "---"),
Pair("Big breasts", "big-breasts"),
Pair("Sole female", "sole-female"),
Pair("Sole male", "sole-male"),
Pair("Anal", "anal"),
Pair("Nakadashi", "nakadashi"),
Pair("Group", "group"),
Pair("Stockings", "stockings"),
Pair("Blowjob", "blowjob"),
Pair("Schoolgirl uniform", "schoolgirl-uniform"),
Pair("Rape", "rape"),
Pair("Lolicon", "lolicon"),
Pair("Glasses", "glasses"),
Pair("Defloration", "defloration"),
Pair("Ahegao", "ahegao"),
Pair("Incest", "incest"),
Pair("Shotacon", "shotacon"),
Pair("X-ray", "x-ray"),
Pair("Bondage", "bondage"),
Pair("Full color", "full-color"),
Pair("Double penetration", "double-penetration"),
Pair("Femdom", "femdom"),
Pair("Milf", "milf"),
Pair("Yaoi", "yaoi"),
Pair("Multi-work series", "multi-work-series"),
Pair("Schoolgirl", "schoolgirl"),
Pair("Mind break", "mind-break"),
Pair("Paizuri", "paizuri"),
Pair("Mosaic censorship", "mosaic-censorship"),
Pair("Impregnation", "impregnation"),
Pair("Males only", "males-only"),
Pair("Sex toys", "sex-toys"),
Pair("Sister", "sister"),
Pair("Dark skin", "dark-skin"),
Pair("Ffm threesome", "ffm-threesome"),
Pair("Hairy", "hairy"),
Pair("Cheating", "cheating"),
Pair("Sweating", "sweating"),
Pair("Yuri", "yuri"),
Pair("Netorare", "netorare"),
Pair("Full censorship", "full-censorship"),
Pair("Schoolboy uniform", "schoolboy-uniform"),
Pair("Dilf", "dilf"),
Pair("Big penis", "big-penis"),
Pair("Futanari", "futanari"),
Pair("Swimsuit", "swimsuit"),
Pair("Collar", "collar"),
Pair("Uncensored", "uncensored"),
Pair("Big ass", "big-ass"),
Pair("Story arc", "story-arc"),
Pair("Teacher", "teacher")
))
private class GenreFilter : UriPartFilter(
"Category",
arrayOf(
Pair("<select>", "---"),
Pair("Big breasts", "big-breasts"),
Pair("Sole female", "sole-female"),
Pair("Sole male", "sole-male"),
Pair("Anal", "anal"),
Pair("Nakadashi", "nakadashi"),
Pair("Group", "group"),
Pair("Stockings", "stockings"),
Pair("Blowjob", "blowjob"),
Pair("Schoolgirl uniform", "schoolgirl-uniform"),
Pair("Rape", "rape"),
Pair("Lolicon", "lolicon"),
Pair("Glasses", "glasses"),
Pair("Defloration", "defloration"),
Pair("Ahegao", "ahegao"),
Pair("Incest", "incest"),
Pair("Shotacon", "shotacon"),
Pair("X-ray", "x-ray"),
Pair("Bondage", "bondage"),
Pair("Full color", "full-color"),
Pair("Double penetration", "double-penetration"),
Pair("Femdom", "femdom"),
Pair("Milf", "milf"),
Pair("Yaoi", "yaoi"),
Pair("Multi-work series", "multi-work-series"),
Pair("Schoolgirl", "schoolgirl"),
Pair("Mind break", "mind-break"),
Pair("Paizuri", "paizuri"),
Pair("Mosaic censorship", "mosaic-censorship"),
Pair("Impregnation", "impregnation"),
Pair("Males only", "males-only"),
Pair("Sex toys", "sex-toys"),
Pair("Sister", "sister"),
Pair("Dark skin", "dark-skin"),
Pair("Ffm threesome", "ffm-threesome"),
Pair("Hairy", "hairy"),
Pair("Cheating", "cheating"),
Pair("Sweating", "sweating"),
Pair("Yuri", "yuri"),
Pair("Netorare", "netorare"),
Pair("Full censorship", "full-censorship"),
Pair("Schoolboy uniform", "schoolboy-uniform"),
Pair("Dilf", "dilf"),
Pair("Big penis", "big-penis"),
Pair("Futanari", "futanari"),
Pair("Swimsuit", "swimsuit"),
Pair("Collar", "collar"),
Pair("Uncensored", "uncensored"),
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>>) :
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.net.URLEncoder
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.net.URLEncoder
@Nsfw
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.online.ParsedHttpSource
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.OkHttpClient
import okhttp3.Request
@ -22,6 +18,10 @@ import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import java.util.concurrent.TimeUnit
class Hiveworks : ParsedHttpSource() {
@ -290,84 +290,104 @@ class Hiveworks : ParsedHttpSource() {
fun addToUri(uri: Uri.Builder)
}
private class UpdateDay : UriSelectFilter("Update Day", "update-day", arrayOf(
Pair("all", "All"),
Pair("monday", "Monday"),
Pair("tuesday", "Tuesday"),
Pair("wednesday", "Wednesday"),
Pair("thursday", "Thursday"),
Pair("friday", "Friday"),
Pair("saturday", "Saturday"),
Pair("sunday", "Sunday")
))
private class UpdateDay : UriSelectFilter(
"Update Day",
"update-day",
arrayOf(
Pair("all", "All"),
Pair("monday", "Monday"),
Pair("tuesday", "Tuesday"),
Pair("wednesday", "Wednesday"),
Pair("thursday", "Thursday"),
Pair("friday", "Friday"),
Pair("saturday", "Saturday"),
Pair("sunday", "Sunday")
)
)
private class RatingFilter : UriSelectFilter("Rating", "age", arrayOf(
Pair("all", "All"),
Pair("everyone", "Everyone"),
Pair("teen", "Teen"),
Pair("young-adult", "Young Adult"),
Pair("mature", "Mature")
))
private class RatingFilter : UriSelectFilter(
"Rating",
"age",
arrayOf(
Pair("all", "All"),
Pair("everyone", "Everyone"),
Pair("teen", "Teen"),
Pair("young-adult", "Young Adult"),
Pair("mature", "Mature")
)
)
private class GenreFilter : UriSelectFilter("Genre", "genre", arrayOf(
Pair("all", "All"),
Pair("action/adventure", "Action/Adventure"),
Pair("animated", "Animated"),
Pair("autobio", "Autobio"),
Pair("comedy", "Comedy"),
Pair("drama", "Drama"),
Pair("dystopian", "Dystopian"),
Pair("fairytale", "Fairytale"),
Pair("fantasy", "Fantasy"),
Pair("finished", "Finished"),
Pair("historical-fiction", "Historical Fiction"),
Pair("horror", "Horror"),
Pair("lgbt", "LGBT"),
Pair("mystery", "Mystery"),
Pair("romance", "Romance"),
Pair("sci-fi", "Science Fiction"),
Pair("slice-of-life", "Slice of Life"),
Pair("steampunk", "Steampunk"),
Pair("superhero", "Superhero"),
Pair("urban-fantasy", "Urban Fantasy")
))
private class GenreFilter : UriSelectFilter(
"Genre",
"genre",
arrayOf(
Pair("all", "All"),
Pair("action/adventure", "Action/Adventure"),
Pair("animated", "Animated"),
Pair("autobio", "Autobio"),
Pair("comedy", "Comedy"),
Pair("drama", "Drama"),
Pair("dystopian", "Dystopian"),
Pair("fairytale", "Fairytale"),
Pair("fantasy", "Fantasy"),
Pair("finished", "Finished"),
Pair("historical-fiction", "Historical Fiction"),
Pair("horror", "Horror"),
Pair("lgbt", "LGBT"),
Pair("mystery", "Mystery"),
Pair("romance", "Romance"),
Pair("sci-fi", "Science Fiction"),
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(
Pair("all", "All"),
Pair("a", "A"),
Pair("b", "B"),
Pair("c", "C"),
Pair("d", "D"),
Pair("e", "E"),
Pair("f", "F"),
Pair("g", "G"),
Pair("h", "H"),
Pair("i", "I"),
Pair("j", "J"),
Pair("k", "K"),
Pair("l", "L"),
Pair("m", "M"),
Pair("n", "N"),
Pair("o", "O"),
Pair("p", "P"),
Pair("q", "Q"),
Pair("r", "R"),
Pair("s", "S"),
Pair("t", "T"),
Pair("u", "U"),
Pair("v", "V"),
Pair("w", "W"),
Pair("x", "X"),
Pair("y", "Y"),
Pair("z", "Z"),
Pair("numbers-symbols", "Numbers / Symbols")
))
private class TitleFilter : UriSelectFilter(
"Title",
"alpha",
arrayOf(
Pair("all", "All"),
Pair("a", "A"),
Pair("b", "B"),
Pair("c", "C"),
Pair("d", "D"),
Pair("e", "E"),
Pair("f", "F"),
Pair("g", "G"),
Pair("h", "H"),
Pair("i", "I"),
Pair("j", "J"),
Pair("k", "K"),
Pair("l", "L"),
Pair("m", "M"),
Pair("n", "N"),
Pair("o", "O"),
Pair("p", "P"),
Pair("q", "Q"),
Pair("r", "R"),
Pair("s", "S"),
Pair("t", "T"),
Pair("u", "U"),
Pair("v", "V"),
Pair("w", "W"),
Pair("x", "X"),
Pair("y", "Y"),
Pair("z", "Z"),
Pair("numbers-symbols", "Numbers / Symbols")
)
)
private class SortFilter : UriSelectFilter("Sort By", "sortby", arrayOf(
Pair("none", "None"),
Pair("a-z", "A-Z"),
Pair("z-a", "Z-A")
))
private class SortFilter : UriSelectFilter(
"Sort By",
"sortby",
arrayOf(
Pair("none", "None"),
Pair("a-z", "A-Z"),
Pair("z-a", "Z-A")
)
)
// 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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
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.SManga
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.HttpUrl
import okhttp3.OkHttpClient
@ -30,6 +24,12 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
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() {
override val name = "Madokami"
@ -145,7 +145,7 @@ class Madokami : ConfigurableSource, ParsedHttpSource() {
}
chapter.date_upload = newDate.time.time
} else {
chapter.date_upload = dateFormat.parse(date).time
chapter.date_upload = dateFormat.parse(date)?.time ?: 0L
}
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class mangacruzers : ParsedHttpSource() {
@ -70,16 +70,16 @@ class mangacruzers : ParsedHttpSource() {
override fun latestUpdatesFromElement(element: Element) = mangaFromElement(element)
override fun searchMangaFromElement(element: Element) = mangaFromElement(element)
private fun mangaFromElement(element: Element): SManga {
val manga = SManga.create()
manga.url = element.select("a").attr("abs:href")
manga.title = element.select("td").first().text().trim()
private fun mangaFromElement(element: Element): SManga {
val manga = SManga.create()
manga.url = element.select("a").attr("abs:href")
manga.title = element.select("td").first().text().trim()
return manga
}
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 {

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.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.text.SimpleDateFormat
import java.util.Locale
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 searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val uri = Uri.parse("$baseUrl/index/keywordsearch/index").buildUpon()
.appendQueryParameter("query", query)
.appendQueryParameter("query", query)
return GET(uri.toString(), headers)
}
@ -122,7 +122,7 @@ class Mangadog : HttpSource() {
}
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 {

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.SManga
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.HttpUrl
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangaeden : ParsedHttpSource() {
@ -52,15 +52,18 @@ class Mangaeden : ParsedHttpSource() {
val url = HttpUrl.parse("$baseUrl/en/en-directory/")?.newBuilder()!!.addQueryParameter("title", query)
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is StatusList -> filter.state
is StatusList ->
filter.state
.filter { it.state }
.map { it.id.toString() }
.forEach { url.addQueryParameter("status", it) }
is Types -> filter.state
is Types ->
filter.state
.filter { it.state }
.map { it.id.toString() }
.forEach { url.addQueryParameter("type", it) }
is GenreList -> filter.state
is GenreList ->
filter.state
.filter { !it.isIgnored() }
.forEach { genre -> url.addQueryParameter(if (genre.isIncluded()) "categoriesInc" else "categoriesExcl", genre.id) }
is TextField -> url.addQueryParameter(filter.key, filter.state)
@ -129,11 +132,12 @@ class Mangaeden : ParsedHttpSource() {
set(Calendar.MILLISECOND, 0)
}.timeInMillis
}
else -> try {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date).time
} catch (e: ParseException) {
0L
}
else ->
try {
SimpleDateFormat("MMM d, yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) {
0L
}
}
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 Genre(name: String, val id: String) : Filter.TriState(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"),
Selection(1, false))
private class OrderBy : Filter.Sort(
"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 Types(types: List<NamedId>) : Filter.Group<NamedId>("Tipo", types)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList(
TextField("Author", "author"),
TextField("Artist", "artist"),
OrderBy(),
Types(types()),
StatusList(statuses()),
GenreList(genres())
TextField("Author", "author"),
TextField("Artist", "artist"),
OrderBy(),
Types(types()),
StatusList(statuses()),
GenreList(genres())
)
private fun types() = listOf(
NamedId("Japanese Manga", 0),
NamedId("Korean Manhwa", 1),
NamedId("Chinese Manhua", 2),
NamedId("Comic", 3),
NamedId("Doujinshi", 4)
NamedId("Japanese Manga", 0),
NamedId("Korean Manhwa", 1),
NamedId("Chinese Manhua", 2),
NamedId("Comic", 3),
NamedId("Doujinshi", 4)
)
private fun statuses() = listOf(
NamedId("Ongoing", 1),
NamedId("Completed", 2),
NamedId("Suspended", 0)
NamedId("Ongoing", 1),
NamedId("Completed", 2),
NamedId("Suspended", 0)
)
private fun genres() = listOf(
Genre("Action", "4e70e91bc092255ef70016f8"),
Genre("Adult", "4e70e92fc092255ef7001b94"),
Genre("Adventure", "4e70e918c092255ef700168e"),
Genre("Comedy", "4e70e918c092255ef7001675"),
Genre("Doujinshi", "4e70e928c092255ef7001a0a"),
Genre("Drama", "4e70e918c092255ef7001693"),
Genre("Ecchi", "4e70e91ec092255ef700175e"),
Genre("Fantasy", "4e70e918c092255ef7001676"),
Genre("Gender Bender", "4e70e921c092255ef700184b"),
Genre("Harem", "4e70e91fc092255ef7001783"),
Genre("Historical", "4e70e91ac092255ef70016d8"),
Genre("Horror", "4e70e919c092255ef70016a8"),
Genre("Josei", "4e70e920c092255ef70017de"),
Genre("Martial Arts", "4e70e923c092255ef70018d0"),
Genre("Mature", "4e70e91bc092255ef7001705"),
Genre("Mecha", "4e70e922c092255ef7001877"),
Genre("Mystery", "4e70e918c092255ef7001681"),
Genre("One Shot", "4e70e91dc092255ef7001747"),
Genre("Psychological", "4e70e919c092255ef70016a9"),
Genre("Romance", "4e70e918c092255ef7001677"),
Genre("School Life", "4e70e918c092255ef7001688"),
Genre("Sci-fi", "4e70e91bc092255ef7001706"),
Genre("Seinen", "4e70e918c092255ef700168b"),
Genre("Shoujo", "4e70e918c092255ef7001667"),
Genre("Shounen", "4e70e918c092255ef700166f"),
Genre("Slice of Life", "4e70e918c092255ef700167e"),
Genre("Smut", "4e70e922c092255ef700185a"),
Genre("Sports", "4e70e91dc092255ef700172e"),
Genre("Supernatural", "4e70e918c092255ef700166a"),
Genre("Tragedy", "4e70e918c092255ef7001672"),
Genre("Webtoons", "4e70ea70c092255ef7006d9c"),
Genre("Yaoi", "4e70e91ac092255ef70016e5"),
Genre("Yuri", "4e70e92ac092255ef7001a57")
Genre("Action", "4e70e91bc092255ef70016f8"),
Genre("Adult", "4e70e92fc092255ef7001b94"),
Genre("Adventure", "4e70e918c092255ef700168e"),
Genre("Comedy", "4e70e918c092255ef7001675"),
Genre("Doujinshi", "4e70e928c092255ef7001a0a"),
Genre("Drama", "4e70e918c092255ef7001693"),
Genre("Ecchi", "4e70e91ec092255ef700175e"),
Genre("Fantasy", "4e70e918c092255ef7001676"),
Genre("Gender Bender", "4e70e921c092255ef700184b"),
Genre("Harem", "4e70e91fc092255ef7001783"),
Genre("Historical", "4e70e91ac092255ef70016d8"),
Genre("Horror", "4e70e919c092255ef70016a8"),
Genre("Josei", "4e70e920c092255ef70017de"),
Genre("Martial Arts", "4e70e923c092255ef70018d0"),
Genre("Mature", "4e70e91bc092255ef7001705"),
Genre("Mecha", "4e70e922c092255ef7001877"),
Genre("Mystery", "4e70e918c092255ef7001681"),
Genre("One Shot", "4e70e91dc092255ef7001747"),
Genre("Psychological", "4e70e919c092255ef70016a9"),
Genre("Romance", "4e70e918c092255ef7001677"),
Genre("School Life", "4e70e918c092255ef7001688"),
Genre("Sci-fi", "4e70e91bc092255ef7001706"),
Genre("Seinen", "4e70e918c092255ef700168b"),
Genre("Shoujo", "4e70e918c092255ef7001667"),
Genre("Shounen", "4e70e918c092255ef700166f"),
Genre("Slice of Life", "4e70e918c092255ef700167e"),
Genre("Smut", "4e70e922c092255ef700185a"),
Genre("Sports", "4e70e91dc092255ef700172e"),
Genre("Supernatural", "4e70e918c092255ef700166a"),
Genre("Tragedy", "4e70e918c092255ef7001672"),
Genre("Webtoons", "4e70ea70c092255ef7006d9c"),
Genre("Yaoi", "4e70e91ac092255ef70016e5"),
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaFast : ParsedHttpSource() {
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.SManga
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.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class Mangafreak : ParsedHttpSource() {
override val name: String = "Mangafreak"
@ -76,14 +76,16 @@ class Mangafreak : ParsedHttpSource() {
uri.appendPath("Genre")
when (filter) {
is GenreList -> {
uri.appendPath(filter.state.joinToString("") {
when (it.state) {
Filter.TriState.STATE_IGNORE -> "0"
Filter.TriState.STATE_INCLUDE -> "1"
Filter.TriState.STATE_EXCLUDE -> "2"
else -> "0"
uri.appendPath(
filter.state.joinToString("") {
when (it.state) {
Filter.TriState.STATE_IGNORE -> "0"
Filter.TriState.STATE_INCLUDE -> "1"
Filter.TriState.STATE_EXCLUDE -> "2"
else -> "0"
}
}
})
)
}
}
uri.appendEncodedPath("Status/0/Type/0")
@ -120,7 +122,7 @@ class Mangafreak : ParsedHttpSource() {
date_upload = parseDate(element.select(" td:eq(1)").text())
}
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> {
return super.chapterListParse(response).reversed()
@ -144,7 +146,8 @@ class Mangafreak : ParsedHttpSource() {
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList(
GenreList(getGenreList()))
GenreList(getGenreList())
)
private fun getGenreList() = listOf(
Genre("Act"),
Genre("Adult"),
@ -185,5 +188,5 @@ class Mangafreak : ParsedHttpSource() {
Genre("Vampire"),
Genre("Yaoi"),
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class Mangahasu : ParsedHttpSource() {
@ -195,18 +195,24 @@ class Mangahasu : ParsedHttpSource() {
fun toUriPart() = vals[state].second
}
private class TypeFilter : UriPartFilter("Type", arrayOf(
Pair("Any", ""),
Pair("Manga", "10"),
Pair("Manhwa", "12"),
Pair("Manhua", "19")
))
private class TypeFilter : UriPartFilter(
"Type",
arrayOf(
Pair("Any", ""),
Pair("Manga", "10"),
Pair("Manhwa", "12"),
Pair("Manhua", "19")
)
)
private class StatusFilter : UriPartFilter("Status", arrayOf(
Pair("Any", ""),
Pair("Completed", "1"),
Pair("Ongoing", "2")
))
private class StatusFilter : UriPartFilter(
"Status",
arrayOf(
Pair("Any", ""),
Pair("Completed", "1"),
Pair("Ongoing", "2")
)
)
private class Genre(name: String, val id: String) : Filter.TriState(name)
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.online.ParsedHttpSource
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.CookieJar
import okhttp3.HttpUrl
@ -20,6 +16,10 @@ import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangahere : ParsedHttpSource() {
@ -34,19 +34,24 @@ class Mangahere : ParsedHttpSource() {
override val supportsLatest = true
override val client: OkHttpClient = super.client.newBuilder()
.cookieJar(object : CookieJar {
.cookieJar(
object : CookieJar {
override fun saveFromResponse(url: HttpUrl, cookies: MutableList<Cookie>) {}
override fun loadForRequest(url: HttpUrl): MutableList<Cookie> {
return ArrayList<Cookie>().apply {
add(Cookie.Builder()
add(
Cookie.Builder()
.domain("www.mangahere.cc")
.path("/")
.name("isAdult")
.value("1")
.build()) }
.build()
)
}
}
})
.build()
}
)
.build()
override fun popularMangaSelector() = ".manga-list-1-list li"
@ -67,7 +72,7 @@ class Mangahere : ParsedHttpSource() {
manga.title = titleElement.attr("title")
manga.setUrlWithoutDomain(titleElement.attr("href"))
manga.thumbnail_url = element.select("img.manga-list-1-cover")
?.first()?.attr("src")
?.first()?.attr("src")
return manga
}
@ -140,7 +145,7 @@ class Mangahere : ParsedHttpSource() {
manga.genre = document.select(".detail-info-right-tag-list > a")?.joinToString { it.text() }
manga.description = document.select(".fullcontent")?.first()?.text()
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 ->
when {
@ -186,7 +191,7 @@ class Mangahere : ParsedHttpSource() {
}.timeInMillis
} else {
try {
SimpleDateFormat("MMM dd,yyyy", Locale.ENGLISH).parse(date).time
SimpleDateFormat("MMM dd,yyyy", Locale.ENGLISH).parse(date)?.time ?: 0L
} catch (e: ParseException) {
0L
}
@ -232,8 +237,9 @@ class Mangahere : ParsedHttpSource() {
val chapterIdStartLoc = html.indexOf("chapterid")
val chapterId = html.substring(
chapterIdStartLoc + 11,
html.indexOf(";", chapterIdStartLoc)).trim()
chapterIdStartLoc + 11,
html.indexOf(";", chapterIdStartLoc)
).trim()
val chapterPagesElement = document.select(".pager-list-left > span").first()
val pagesLinksElements = chapterPagesElement.select("a")
@ -250,15 +256,15 @@ class Mangahere : ParsedHttpSource() {
for (tr in 1..3) {
val request = Request.Builder()
.url(pageLink)
.addHeader("Referer", link)
.addHeader("Accept", "*/*")
.addHeader("Accept-Language", "en-US,en;q=0.9")
.addHeader("Connection", "keep-alive")
.addHeader("Host", "www.mangahere.cc")
.addHeader("User-Agent", System.getProperty("http.agent") ?: "")
.addHeader("X-Requested-With", "XMLHttpRequest")
.build()
.url(pageLink)
.addHeader("Referer", link)
.addHeader("Accept", "*/*")
.addHeader("Accept-Language", "en-US,en;q=0.9")
.addHeader("Connection", "keep-alive")
.addHeader("Host", "www.mangahere.cc")
.addHeader("User-Agent", System.getProperty("http.agent") ?: "")
.addHeader("X-Requested-With", "XMLHttpRequest")
.build()
val response = client.newCall(request).execute()
responseText = response.body()!!.string()
@ -298,7 +304,9 @@ class Mangahere : ParsedHttpSource() {
val secretKeyEndLoc = secretKeyDeobfuscatedScript.indexOf(";")
val secretKeyResultScript = secretKeyDeobfuscatedScript.substring(
secretKeyStartLoc, secretKeyEndLoc)
secretKeyStartLoc,
secretKeyEndLoc
)
return duktape.evaluate(secretKeyResultScript).toString()
}
@ -312,56 +320,56 @@ class Mangahere : ParsedHttpSource() {
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList(
TypeList(types.keys.toList().sorted().toTypedArray()),
CompletionList(completions),
GenreList(genres())
TypeList(types.keys.toList().sorted().toTypedArray()),
CompletionList(completions),
GenreList(genres())
)
private val types = hashMapOf(
"Japanese Manga" to 1,
"Korean Manhwa" to 2,
"Other Manga" to 4,
"Any" to 0
"Japanese Manga" to 1,
"Korean Manhwa" to 2,
"Other Manga" to 4,
"Any" to 0
)
private val completions = arrayOf("Either", "No", "Yes")
private fun genres() = arrayListOf(
Genre("Action", 1),
Genre("Adventure", 2),
Genre("Comedy", 3),
Genre("Fantasy", 4),
Genre("Historical", 5),
Genre("Horror", 6),
Genre("Martial Arts", 7),
Genre("Mystery", 8),
Genre("Romance", 9),
Genre("Shounen Ai", 10),
Genre("Supernatural", 11),
Genre("Drama", 12),
Genre("Shounen", 13),
Genre("School Life", 14),
Genre("Shoujo", 15),
Genre("Gender Bender", 16),
Genre("Josei", 17),
Genre("Psychological", 18),
Genre("Seinen", 19),
Genre("Slice of Life", 20),
Genre("Sci-fi", 21),
Genre("Ecchi", 22),
Genre("Harem", 23),
Genre("Shoujo Ai", 24),
Genre("Yuri", 25),
Genre("Mature", 26),
Genre("Tragedy", 27),
Genre("Yaoi", 28),
Genre("Doujinshi", 29),
Genre("Sports", 30),
Genre("Adult", 31),
Genre("One Shot", 32),
Genre("Smut", 33),
Genre("Mecha", 34),
Genre("Shotacon", 35),
Genre("Lolicon", 36)
Genre("Action", 1),
Genre("Adventure", 2),
Genre("Comedy", 3),
Genre("Fantasy", 4),
Genre("Historical", 5),
Genre("Horror", 6),
Genre("Martial Arts", 7),
Genre("Mystery", 8),
Genre("Romance", 9),
Genre("Shounen Ai", 10),
Genre("Supernatural", 11),
Genre("Drama", 12),
Genre("Shounen", 13),
Genre("School Life", 14),
Genre("Shoujo", 15),
Genre("Gender Bender", 16),
Genre("Josei", 17),
Genre("Psychological", 18),
Genre("Seinen", 19),
Genre("Slice of Life", 20),
Genre("Sci-fi", 21),
Genre("Ecchi", 22),
Genre("Harem", 23),
Genre("Shoujo Ai", 24),
Genre("Yuri", 25),
Genre("Mature", 26),
Genre("Tragedy", 27),
Genre("Yaoi", 28),
Genre("Doujinshi", 29),
Genre("Sports", 30),
Genre("Adult", 31),
Genre("One Shot", 32),
Genre("Smut", 33),
Genre("Mecha", 34),
Genre("Shotacon", 35),
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.SManga
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.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.jsoup.nodes.Document
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() {
@ -55,7 +55,7 @@ class Mangahub : ParsedHttpSource() {
manga.title = titleElement.text()
manga.setUrlWithoutDomain(URL(titleElement.attr("href")).path)
manga.thumbnail_url = element.select("img.manga-thumb.list-item-thumb")
?.first()?.attr("src")
?.first()?.attr("src")
return manga
}
@ -78,7 +78,7 @@ class Mangahub : ParsedHttpSource() {
manga.genre = document.select("._3Czbn a")?.joinToString { it.text() }
manga.description = document.select("div#noanim-content-tab-pane-99 p.ZyMp7")?.first()?.text()
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 ->
when {
@ -133,7 +133,7 @@ class Mangahub : ParsedHttpSource() {
// parses: "12-20-2019" and defaults everything that wasn't taken into account to 0
else -> {
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*/ }
}
}
@ -208,16 +208,16 @@ class Mangahub : ParsedHttpSource() {
private class GenreList(genres: Array<Genre>) : Filter.Select<Genre>("Genres", genres, 0)
override fun getFilterList() = FilterList(
OrderBy(orderBy),
GenreList(genres)
OrderBy(orderBy),
GenreList(genres)
)
private val orderBy = arrayOf(
Order("Popular", "POPULAR"),
Order("Updates", "LATEST"),
Order("A-Z", "ALPHABET"),
Order("New", "NEW"),
Order("Completed", "COMPLETED")
Order("Popular", "POPULAR"),
Order("Updates", "LATEST"),
Order("A-Z", "ALPHABET"),
Order("New", "NEW"),
Order("Completed", "COMPLETED")
)
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class MangaJar : ParsedHttpSource() {
@ -43,8 +43,10 @@ class MangaJar : ParsedHttpSource() {
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.select("a").attr("href"))
title = element.select("img").attr("title")
thumbnail_url = element.select("img").let { if (it.hasAttr("data-src"))
it.attr("data-src") else it.attr("src") }
thumbnail_url = element.select("img").let {
if (it.hasAttr("data-src"))
it.attr("data-src") else it.attr("src")
}
}
override fun latestUpdatesFromElement(element: Element): SManga = popularMangaFromElement(element)
@ -63,16 +65,18 @@ class MangaJar : ParsedHttpSource() {
url.addQueryParameter("q", query)
url.addQueryParameter("page", page.toString())
(filters.forEach { filter ->
when (filter) {
is OrderBy -> {
url.addQueryParameter("sortBy", filter.toUriPart())
}
is SortBy -> {
url.addQueryParameter("sortAscending", filter.toUriPart())
(
filters.forEach { filter ->
when (filter) {
is OrderBy -> {
url.addQueryParameter("sortBy", filter.toUriPart())
}
is SortBy -> {
url.addQueryParameter("sortAscending", filter.toUriPart())
}
}
}
})
)
return GET(url.toString(), headers)
}
@ -117,7 +121,7 @@ class MangaJar : ParsedHttpSource() {
return if ("ago" in string) {
parseRelativeDate(string) ?: 0
} 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 getFilterList() = FilterList(
OrderBy(),
SortBy(),
GenreList()
OrderBy(),
SortBy(),
GenreList()
)
private class SortBy : UriPartFilter("Sort By", arrayOf(
private class SortBy : UriPartFilter(
"Sort By",
arrayOf(
Pair("Descending", "0"),
Pair("Ascending", "1")
))
)
)
private class OrderBy : UriPartFilter("Order By", arrayOf(
private class OrderBy : UriPartFilter(
"Order By",
arrayOf(
Pair("Popularity", "popular"),
Pair("Year", "year"),
Pair("Alphabet", "name"),
Pair("Date added", "published_at"),
Pair("Date updated", "last_chapter_at")
))
)
)
private class GenreList : Filter.Select<String>("Select Genre",
private class GenreList : Filter.Select<String>(
"Select Genre",
arrayOf(
"",
"Fantasy",
@ -220,7 +231,7 @@ class MangaJar : ParsedHttpSource() {
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>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.ResponseBody
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class MangaKatana : ParsedHttpSource() {
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.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
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
@ -89,11 +89,13 @@ class MangaLife : HttpSource() {
val endRange = ((page * 24) - 1).let { if (it <= directory.lastIndex) it else directory.lastIndex }
for (i in (((page - 1) * 24)..endRange)) {
mangas.add(SManga.create().apply {
title = directory[i]["s"].string
url = "/manga/${directory[i]["i"].string}"
thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg"
})
mangas.add(
SManga.create().apply {
title = directory[i]["s"].string
url = "/manga/${directory[i]["i"].string}"
thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg"
}
)
}
return MangasPage(mangas, endRange < directory.lastIndex)
}
@ -281,54 +283,54 @@ class MangaLife : HttpSource() {
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genres", genres)
override fun getFilterList() = FilterList(
YearField(),
AuthorField(),
SelectField("Scan Status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")),
SelectField("Publish Status", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")),
SelectField("Type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")),
SelectField("Translation", arrayOf("Any", "Official Only")),
Sort(),
GenreList(getGenreList())
YearField(),
AuthorField(),
SelectField("Scan Status", arrayOf("Any", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing")),
SelectField("Publish Status", arrayOf("Any", "Cancelled", "Complete", "Discontinued", "Hiatus", "Incomplete", "Ongoing", "Unfinished")),
SelectField("Type", arrayOf("Any", "Doujinshi", "Manga", "Manhua", "Manhwa", "OEL", "One-shot")),
SelectField("Translation", arrayOf("Any", "Official Only")),
Sort(),
GenreList(getGenreList())
)
// [...document.querySelectorAll("label.triStateCheckBox input")].map(el => `Filter("${el.getAttribute('name')}", "${el.nextSibling.textContent.trim()}")`).join(',\n')
// https://manga4life.com/advanced-search/
private fun getGenreList() = listOf(
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
Genre("Comedy"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender Bender"),
Genre("Harem"),
Genre("Hentai"),
Genre("Historical"),
Genre("Horror"),
Genre("Josei"),
Genre("Lolicon"),
Genre("Martial Arts"),
Genre("Mature"),
Genre("Mecha"),
Genre("Mystery"),
Genre("Psychological"),
Genre("Romance"),
Genre("School Life"),
Genre("Sci-fi"),
Genre("Seinen"),
Genre("Shotacon"),
Genre("Shoujo"),
Genre("Shoujo Ai"),
Genre("Shounen"),
Genre("Shounen Ai"),
Genre("Slice of Life"),
Genre("Smut"),
Genre("Sports"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Yaoi"),
Genre("Yuri")
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
Genre("Comedy"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender Bender"),
Genre("Harem"),
Genre("Hentai"),
Genre("Historical"),
Genre("Horror"),
Genre("Josei"),
Genre("Lolicon"),
Genre("Martial Arts"),
Genre("Mature"),
Genre("Mecha"),
Genre("Mystery"),
Genre("Psychological"),
Genre("Romance"),
Genre("School Life"),
Genre("Sci-fi"),
Genre("Seinen"),
Genre("Shotacon"),
Genre("Shoujo"),
Genre("Shoujo Ai"),
Genre("Shounen"),
Genre("Shounen Ai"),
Genre("Slice of Life"),
Genre("Smut"),
Genre("Sports"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Yaoi"),
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class MangaLinkz : ParsedHttpSource() {
@ -126,11 +126,12 @@ class MangaLinkz : ParsedHttpSource() {
}
}
}
else -> try {
SimpleDateFormat("MMM d, yyyy", Locale.US).parse(this).time
} catch (_: Exception) {
0L
}
else ->
try {
SimpleDateFormat("MMM d, yyyy", Locale.US).parse(this)?.time ?: 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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.util.Calendar
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.util.Calendar
// 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.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.TimeZone
import kotlin.collections.ArrayList
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
fun JsonObject.getNullable(key: String): JsonElement? {
val value: JsonElement = this.get(key) ?: return null
@ -72,11 +72,13 @@ class MangaMutiny : HttpSource() {
for (singleChapterJsonElement in jsonChapters) {
val singleChapterJsonObject = singleChapterJsonElement.asJsonObject
chapterList.add(SChapter.create().apply {
name = chapterTitleBuilder(singleChapterJsonObject)
url = singleChapterJsonObject.get("slug").asString
date_upload = parseDate(singleChapterJsonObject.get("releasedAt").asString)
})
chapterList.add(
SChapter.create().apply {
name = chapterTitleBuilder(singleChapterJsonObject)
url = singleChapterJsonObject.get("slug").asString
date_upload = parseDate(singleChapterJsonObject.get("releasedAt").asString)
}
)
}
}
@ -211,11 +213,13 @@ class MangaMutiny : HttpSource() {
for (singleItem in itemsArray) {
val mangaObject = singleItem.asJsonObject
mangasPage.add(SManga.create().apply {
this.title = mangaObject.get("title").asString
this.thumbnail_url = mangaObject.getNullable("thumbnail")?.asString
this.url = mangaObject.get("slug").asString
})
mangasPage.add(
SManga.create().apply {
this.title = mangaObject.get("title").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(
Pair("", "All"),
Pair("completed", "Completed"),
Pair("ongoing", "Ongoing")
))
private class StatusFilter : UriSelectFilter(
"Status",
"status",
arrayOf(
Pair("", "All"),
Pair("completed", "Completed"),
Pair("ongoing", "Ongoing")
)
)
private class CategoryFilter : UriSelectFilter("Category", "tags", arrayOf(
Pair("", "All"),
Pair("josei", "Josei"),
Pair("seinen", "Seinen"),
Pair("shoujo", "Shoujo"),
Pair("shounen", "Shounen")
)) {
private class CategoryFilter : UriSelectFilter(
"Category",
"tags",
arrayOf(
Pair("", "All"),
Pair("josei", "Josei"),
Pair("seinen", "Seinen"),
Pair("shoujo", "Shoujo"),
Pair("shounen", "Shounen")
)
) {
override fun potentiallyAddToUriParameterMap(parameterMap: MutableMap<String, String>) =
appendValueToKeyInUriParameterMap(parameterMap, uriParam, vals[state].first)
}
@ -333,92 +345,104 @@ class MangaMutiny : HttpSource() {
}
}
// Actual genere filter list
private class GenresFilter : GenreFilterList("Genres", listOf(
GenreFilter("action", "action"),
GenreFilter("adult", "adult"),
GenreFilter("adventure", "adventure"),
GenreFilter("aliens", "aliens"),
GenreFilter("animals", "animals"),
GenreFilter("comedy", "comedy"),
GenreFilter("cooking", "cooking"),
GenreFilter("crossdressing", "crossdressing"),
GenreFilter("delinquents", "delinquents"),
GenreFilter("demons", "demons"),
GenreFilter("drama", "drama"),
GenreFilter("ecchi", "ecchi"),
GenreFilter("fantasy", "fantasy"),
GenreFilter("gender_bender", "gender bender"),
GenreFilter("genderswap", "genderswap"),
GenreFilter("ghosts", "ghosts"),
GenreFilter("gore", "gore"),
GenreFilter("gyaru", "gyaru"),
GenreFilter("harem", "harem"),
GenreFilter("historical", "historical"),
GenreFilter("horror", "horror"),
GenreFilter("incest", "incest"),
GenreFilter("isekai", "isekai"),
GenreFilter("loli", "loli"),
GenreFilter("magic", "magic"),
GenreFilter("magical_girls", "magical girls"),
GenreFilter("mangamutiny", "mangamutiny"),
GenreFilter("martial_arts", "martial arts"),
GenreFilter("mature", "mature"),
GenreFilter("mecha", "mecha"),
GenreFilter("medical", "medical"),
GenreFilter("military", "military"),
GenreFilter("monster_girls", "monster girls"),
GenreFilter("monsters", "monsters"),
GenreFilter("mystery", "mystery"),
GenreFilter("ninja", "ninja"),
GenreFilter("office_workers", "office workers"),
GenreFilter("philosophical", "philosophical"),
GenreFilter("psychological", "psychological"),
GenreFilter("reincarnation", "reincarnation"),
GenreFilter("reverse_harem", "reverse harem"),
GenreFilter("romance", "romance"),
GenreFilter("school_life", "school life"),
GenreFilter("sci_fi", "sci fi"),
GenreFilter("sci-fi", "sci-fi"),
GenreFilter("sexual_violence", "sexual violence"),
GenreFilter("shota", "shota"),
GenreFilter("shoujo_ai", "shoujo ai"),
GenreFilter("shounen_ai", "shounen ai"),
GenreFilter("slice_of_life", "slice of life"),
GenreFilter("smut", "smut"),
GenreFilter("sports", "sports"),
GenreFilter("superhero", "superhero"),
GenreFilter("supernatural", "supernatural"),
GenreFilter("survival", "survival"),
GenreFilter("time_travel", "time travel"),
GenreFilter("tragedy", "tragedy"),
GenreFilter("video_games", "video games"),
GenreFilter("virtual_reality", "virtual reality"),
GenreFilter("webtoons", "webtoons"),
GenreFilter("wuxia", "wuxia"),
GenreFilter("zombies", "zombies")
))
private class GenresFilter : GenreFilterList(
"Genres",
listOf(
GenreFilter("action", "action"),
GenreFilter("adult", "adult"),
GenreFilter("adventure", "adventure"),
GenreFilter("aliens", "aliens"),
GenreFilter("animals", "animals"),
GenreFilter("comedy", "comedy"),
GenreFilter("cooking", "cooking"),
GenreFilter("crossdressing", "crossdressing"),
GenreFilter("delinquents", "delinquents"),
GenreFilter("demons", "demons"),
GenreFilter("drama", "drama"),
GenreFilter("ecchi", "ecchi"),
GenreFilter("fantasy", "fantasy"),
GenreFilter("gender_bender", "gender bender"),
GenreFilter("genderswap", "genderswap"),
GenreFilter("ghosts", "ghosts"),
GenreFilter("gore", "gore"),
GenreFilter("gyaru", "gyaru"),
GenreFilter("harem", "harem"),
GenreFilter("historical", "historical"),
GenreFilter("horror", "horror"),
GenreFilter("incest", "incest"),
GenreFilter("isekai", "isekai"),
GenreFilter("loli", "loli"),
GenreFilter("magic", "magic"),
GenreFilter("magical_girls", "magical girls"),
GenreFilter("mangamutiny", "mangamutiny"),
GenreFilter("martial_arts", "martial arts"),
GenreFilter("mature", "mature"),
GenreFilter("mecha", "mecha"),
GenreFilter("medical", "medical"),
GenreFilter("military", "military"),
GenreFilter("monster_girls", "monster girls"),
GenreFilter("monsters", "monsters"),
GenreFilter("mystery", "mystery"),
GenreFilter("ninja", "ninja"),
GenreFilter("office_workers", "office workers"),
GenreFilter("philosophical", "philosophical"),
GenreFilter("psychological", "psychological"),
GenreFilter("reincarnation", "reincarnation"),
GenreFilter("reverse_harem", "reverse harem"),
GenreFilter("romance", "romance"),
GenreFilter("school_life", "school life"),
GenreFilter("sci_fi", "sci fi"),
GenreFilter("sci-fi", "sci-fi"),
GenreFilter("sexual_violence", "sexual violence"),
GenreFilter("shota", "shota"),
GenreFilter("shoujo_ai", "shoujo ai"),
GenreFilter("shounen_ai", "shounen ai"),
GenreFilter("slice_of_life", "slice of life"),
GenreFilter("smut", "smut"),
GenreFilter("sports", "sports"),
GenreFilter("superhero", "superhero"),
GenreFilter("supernatural", "supernatural"),
GenreFilter("survival", "survival"),
GenreFilter("time_travel", "time travel"),
GenreFilter("tragedy", "tragedy"),
GenreFilter("video_games", "video games"),
GenreFilter("virtual_reality", "virtual reality"),
GenreFilter("webtoons", "webtoons"),
GenreFilter("wuxia", "wuxia"),
GenreFilter("zombies", "zombies")
)
)
// Actual format filter List
private class FormatsFilter : GenreFilterList("Formats", listOf(
GenreFilter("4-koma", "4-koma"),
GenreFilter("adaptation", "adaptation"),
GenreFilter("anthology", "anthology"),
GenreFilter("award_winning", "award winning"),
GenreFilter("doujinshi", "doujinshi"),
GenreFilter("fan_colored", "fan colored"),
GenreFilter("full_color", "full color"),
GenreFilter("long_strip", "long strip"),
GenreFilter("official_colored", "official colored"),
GenreFilter("oneshot", "oneshot"),
GenreFilter("web_comic", "web comic")
))
private class FormatsFilter : GenreFilterList(
"Formats",
listOf(
GenreFilter("4-koma", "4-koma"),
GenreFilter("adaptation", "adaptation"),
GenreFilter("anthology", "anthology"),
GenreFilter("award_winning", "award winning"),
GenreFilter("doujinshi", "doujinshi"),
GenreFilter("fan_colored", "fan colored"),
GenreFilter("full_color", "full color"),
GenreFilter("long_strip", "long strip"),
GenreFilter("official_colored", "official colored"),
GenreFilter("oneshot", "oneshot"),
GenreFilter("web_comic", "web comic")
)
)
private class SortFilter : UriSelectFilter("Sort", "sort", arrayOf(
Pair("-rating -ratingCount", "Popular"),
Pair("-lastReleasedAt", "Last update"),
Pair("-createdAt", "Newest"),
Pair("title", "Name")
), firstIsUnspecified = false, defaultValue = 0)
private class SortFilter : UriSelectFilter(
"Sort",
"sort",
arrayOf(
Pair("-rating -ratingCount", "Popular"),
Pair("-lastReleasedAt", "Last update"),
Pair("-createdAt", "Newest"),
Pair("title", "Name")
),
firstIsUnspecified = false,
defaultValue = 0
)
private class AuthorFilter : Filter.Text("Manga Author & Artist"), UriFilter {
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.
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.**/
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.**/
/*
private class ScanlatorFilter : Filter.Text("Scanlator Name"), UriFilter {
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.SManga
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.Request
import org.jsoup.nodes.Document
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() {

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

View File

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

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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.Jsoup.parse
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Locale
class Mangasail : ParsedHttpSource() {
@ -155,7 +155,7 @@ class Mangasail : ParsedHttpSource() {
}
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> {

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.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
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
@ -92,11 +92,13 @@ class Mangasee : HttpSource() {
val endRange = ((page * 24) - 1).let { if (it <= directory.lastIndex) it else directory.lastIndex }
for (i in (((page - 1) * 24)..endRange)) {
mangas.add(SManga.create().apply {
title = directory[i]["s"].string
url = "/manga/${directory[i]["i"].string}"
thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg"
})
mangas.add(
SManga.create().apply {
title = directory[i]["s"].string
url = "/manga/${directory[i]["i"].string}"
thumbnail_url = "https://cover.mangabeast01.com/cover/${directory[i]["i"].string}.jpg"
}
)
}
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.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class Mangatown : ParsedHttpSource() {
@ -110,7 +110,7 @@ class Mangatown : ParsedHttpSource() {
date.contains("Yesterday") -> Calendar.getInstance().apply { add(Calendar.DAY_OF_MONTH, -1) }.timeInMillis
else -> {
try {
SimpleDateFormat("MMM dd,yyyy", Locale.US).parse(date).time
SimpleDateFormat("MMM dd,yyyy", Locale.US).parse(date)?.time ?: 0L
} catch (e: Exception) {
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.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import java.text.SimpleDateFormat
import java.util.Locale
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import java.text.SimpleDateFormat
import java.util.Locale
class ManhwaTime : ParsedHttpSource() {

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