diff --git a/common.gradle b/common.gradle
index dbad91708..d68422b3d 100644
--- a/common.gradle
+++ b/common.gradle
@@ -76,4 +76,4 @@ dependencies {
}
preBuild.dependsOn(lintKotlin)
-lintKotlin.dependsOn(formatKotlin)
+lintKotlin.dependsOn(formatKotlin)
\ No newline at end of file
diff --git a/src/all/madara/build.gradle b/src/all/madara/build.gradle
index 8ec00a105..e3cf463b8 100644
--- a/src/all/madara/build.gradle
+++ b/src/all/madara/build.gradle
@@ -5,7 +5,7 @@ ext {
extName = 'Madara (multiple sources)'
pkgNameSuffix = "all.madara"
extClass = '.MadaraFactory'
- extVersionCode = 159
+ extVersionCode = 160
libVersion = '1.2'
containsNsfw = true
}
diff --git a/src/all/madara/src/eu/kanade/tachiyomi/extension/all/madara/MadaraFactory.kt b/src/all/madara/src/eu/kanade/tachiyomi/extension/all/madara/MadaraFactory.kt
index e3d3e50ed..41983f782 100644
--- a/src/all/madara/src/eu/kanade/tachiyomi/extension/all/madara/MadaraFactory.kt
+++ b/src/all/madara/src/eu/kanade/tachiyomi/extension/all/madara/MadaraFactory.kt
@@ -116,6 +116,7 @@ class MadaraFactory : SourceFactory {
MangaScantrad(),
MangaSco(),
MangaSpark(),
+ Mangastein()
MangaStarz(),
MangaSY(),
MangaTX(),
@@ -174,6 +175,7 @@ class MadaraFactory : SourceFactory {
RenaScans(),
RuyaManga(),
S2Manga(),
+ Skymanga(),
SpookyScanlations(),
StageComics(),
TheTopComic(),
@@ -987,6 +989,8 @@ class MangaWT : Madara("MangaWT", "https://mangawt.com", "tr")
class DecadenceScans : Madara("Decadence Scans", "https://reader.decadencescans.com", "en")
+class MangaStein : Madara("MangaStein", "https://mangastein.com", "tr")
+
class MangaRockTeam : Madara("Manga Rock Team", "https://mangarockteam.com", "en")
class MixedManga : Madara("Mixed Manga", "https://mixedmanga.com", "en", SimpleDateFormat("d MMM yyyy", Locale.US)) {
@@ -1298,6 +1302,8 @@ class AkuManga : Madara("AkuManga", "https://akumanga.com", "ar")
class AsgardTeam : Madara("Asgard Team", "https://www.asgard1team.com", "ar")
+class Skymanga : Madara("Skymanga", "https://skymanga.co", "en")
+
@Nsfw
class ToonilyNet : Madara("Toonily.net", "https://toonily.net", "en")
diff --git a/src/en/hentainexus/AndroidManifest.xml b/src/en/hentainexus/AndroidManifest.xml
new file mode 100644
index 000000000..8a9a4a062
--- /dev/null
+++ b/src/en/hentainexus/AndroidManifest.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/en/hentainexus/build.gradle b/src/en/hentainexus/build.gradle
new file mode 100644
index 000000000..45f5534df
--- /dev/null
+++ b/src/en/hentainexus/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ appName = 'Tachiyomi: HentaiNexus'
+ pkgNameSuffix = 'en.hentainexus'
+ extClass = '.HentaiNexus'
+ extVersionCode = 4
+ libVersion = '1.2'
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/en/hentainexus/res/mipmap-hdpi/ic_launcher.png b/src/en/hentainexus/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..ce0177c2d
Binary files /dev/null and b/src/en/hentainexus/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/en/hentainexus/res/mipmap-mdpi/ic_launcher.png b/src/en/hentainexus/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..972f68631
Binary files /dev/null and b/src/en/hentainexus/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/en/hentainexus/res/mipmap-xhdpi/ic_launcher.png b/src/en/hentainexus/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..d7d062dd7
Binary files /dev/null and b/src/en/hentainexus/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/en/hentainexus/res/mipmap-xxhdpi/ic_launcher.png b/src/en/hentainexus/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..b6a2745b0
Binary files /dev/null and b/src/en/hentainexus/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/en/hentainexus/res/mipmap-xxxhdpi/ic_launcher.png b/src/en/hentainexus/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..3d95cadfa
Binary files /dev/null and b/src/en/hentainexus/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/en/hentainexus/res/web_hi_res_512.png b/src/en/hentainexus/res/web_hi_res_512.png
new file mode 100644
index 000000000..e623a3c7c
Binary files /dev/null and b/src/en/hentainexus/res/web_hi_res_512.png differ
diff --git a/src/en/hentainexus/src/eu/kanade/tachiyomi/extension/en/hentainexus/HentaiNexus.kt b/src/en/hentainexus/src/eu/kanade/tachiyomi/extension/en/hentainexus/HentaiNexus.kt
new file mode 100644
index 000000000..607b5f016
--- /dev/null
+++ b/src/en/hentainexus/src/eu/kanade/tachiyomi/extension/en/hentainexus/HentaiNexus.kt
@@ -0,0 +1,252 @@
+package eu.kanade.tachiyomi.extension.en.hentainexus
+
+import eu.kanade.tachiyomi.annotations.Nsfw
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.network.asObservableSuccess
+import eu.kanade.tachiyomi.source.model.Filter
+import eu.kanade.tachiyomi.source.model.FilterList
+import eu.kanade.tachiyomi.source.model.MangasPage
+import eu.kanade.tachiyomi.source.model.Page
+import eu.kanade.tachiyomi.source.model.SChapter
+import eu.kanade.tachiyomi.source.model.SManga
+import eu.kanade.tachiyomi.source.online.ParsedHttpSource
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import org.jsoup.nodes.Document
+import org.jsoup.nodes.Element
+import rx.Observable
+import java.net.URLEncoder
+import android.util.Base64
+import kotlin.experimental.xor
+import com.google.gson.Gson
+import com.google.gson.JsonElement
+import com.google.gson.JsonObject
+import com.google.gson.JsonParser
+
+@Nsfw
+class HentaiNexus : ParsedHttpSource() {
+
+ override val name = "HentaiNexus"
+
+ override val baseUrl = "https://hentainexus.com"
+
+ override val lang = "en"
+
+ override val supportsLatest = true
+
+ override val client: OkHttpClient = network.cloudflareClient
+
+ override fun latestUpdatesSelector() = "div.container div.column"
+
+ override fun latestUpdatesRequest(page: Int) = pagedRequest("$baseUrl/", page)
+
+ override fun latestUpdatesFromElement(element: Element): SManga {
+ val manga = SManga.create()
+ val item = element.select("div.column a")
+
+ manga.url = item.attr("href")
+ manga.title = item.text()
+ manga.thumbnail_url = element.select("figure.image > img").attr("src")
+
+ return manga
+ }
+
+ override fun latestUpdatesNextPageSelector() = "nav.pagination > a.pagination-next"
+
+ override fun popularMangaRequest(page: Int): Request = latestUpdatesRequest(page)
+
+ override fun popularMangaFromElement(element: Element) = latestUpdatesFromElement(element)
+
+ override fun popularMangaSelector() = latestUpdatesSelector()
+
+ override fun popularMangaNextPageSelector() = latestUpdatesNextPageSelector()
+
+ override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+ var url: String? = null
+ var queryString: String? = null
+ fun requireNoUrl() = require(url == null && queryString == null) {
+ "You cannot combine filters or use text search with filters!"
+ }
+
+ filters.findInstance()?.let { f ->
+ if (f.state.isNotBlank()) {
+ requireNoUrl()
+ url = "/"
+ queryString = "q=artist:%22${URLEncoder.encode(f.state, "UTF-8")}%22"
+ }
+ }
+
+ filters.findInstance()?.let { f ->
+ if (f.state.isNotBlank()) {
+ requireNoUrl()
+ url = "/"
+ queryString = "q=tag:%22${URLEncoder.encode(f.state, "UTF-8")}%22"
+ }
+ }
+
+ if (query.isNotBlank()) {
+ requireNoUrl()
+ url = "/"
+ queryString = "q=" + URLEncoder.encode(query, "UTF-8")
+ }
+
+ return url?.let {
+ pagedRequest("$baseUrl$url", page, queryString)
+ } ?: latestUpdatesRequest(page)
+ }
+
+ private fun pagedRequest(url: String, page: Int, queryString: String? = null): Request {
+ // The site redirects page 1 -> url-without-page so we do this redirect early for optimization
+ val builtUrl = if (page == 1) url else "${url}page/$page"
+ return GET(if (queryString != null) "$builtUrl?$queryString" else builtUrl)
+ }
+
+ override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable {
+ return if (query.startsWith(PREFIX_ID_SEARCH)) {
+ val id = query.removePrefix(PREFIX_ID_SEARCH)
+ client.newCall(GET("$baseUrl/view/$id", headers)).asObservableSuccess()
+ .map { MangasPage(listOf(mangaDetailsParse(it).apply { url = "/view/$id" }), false) }
+ } else {
+ super.fetchSearchManga(page, query, filters)
+ }
+ }
+
+ override fun searchMangaSelector() = latestUpdatesSelector()
+
+ override fun searchMangaFromElement(element: Element) = latestUpdatesFromElement(element)
+
+ override fun searchMangaNextPageSelector() = latestUpdatesNextPageSelector()
+
+ override fun mangaDetailsRequest(manga: SManga): Request {
+ if (manga.url.startsWith("http")) {
+ return GET(manga.url, headers)
+ }
+ return super.mangaDetailsRequest(manga)
+ }
+
+ override fun mangaDetailsParse(document: Document): SManga {
+ val infoElement = document.select("div.column")
+ val manga = SManga.create()
+ val genres = mutableListOf()
+
+ document.select("td.viewcolumn:containsOwn(Tags) + td a").forEach { element ->
+ val genre = element.text()
+ genres.add(genre)
+ }
+
+ manga.title = infoElement.select("h1").text()
+ manga.author = infoElement.select("td.viewcolumn:containsOwn(Artist) + td").text()
+ manga.artist = infoElement.select("td.viewcolumn:containsOwn(Artist) + td").text()
+ manga.status = SManga.COMPLETED
+ manga.genre = genres.joinToString(", ")
+ manga.description = getDesc(document)
+ manga.thumbnail_url = document.select("figure.image > img").attr("src")
+
+ return manga
+ }
+
+ private fun getDesc(document: Document): String {
+ val infoElement = document.select("div.column")
+ val stringBuilder = StringBuilder()
+ val description = infoElement.select("td.viewcolumn:containsOwn(Description) + td").text()
+ val magazine = infoElement.select("td.viewcolumn:containsOwn(Magazine) + td").text()
+ val parodies = infoElement.select("td.viewcolumn:containsOwn(Parody) + td").text()
+ val publisher = infoElement.select("td.viewcolumn:containsOwn(Publisher) + td").text()
+ val pagess = infoElement.select("td.viewcolumn:containsOwn(Pages) + td").text()
+
+ stringBuilder.append(description)
+ stringBuilder.append("\n\n")
+
+ stringBuilder.append("Magazine: ")
+ stringBuilder.append(magazine)
+ stringBuilder.append("\n\n")
+
+ stringBuilder.append("Parodies: ")
+ stringBuilder.append(parodies)
+ stringBuilder.append("\n\n")
+
+ stringBuilder.append("Publisher: ")
+ stringBuilder.append(publisher)
+ stringBuilder.append("\n\n")
+
+ stringBuilder.append("Pages: ")
+ stringBuilder.append(pagess)
+
+ return stringBuilder.toString()
+ }
+
+ override fun chapterListRequest(manga: SManga): Request {
+ if (manga.url.startsWith("http")) {
+ return GET(manga.url, headers)
+ }
+ return super.chapterListRequest(manga)
+ }
+
+ override fun chapterListSelector() = "div.container nav.depict-button-set"
+
+ override fun chapterFromElement(element: Element): SChapter {
+ return SChapter.create().apply {
+ url = element.select("div.level-item a").attr("href")
+ name = "Read Online: Chapter 0"
+ }
+ }
+
+ override fun pageListRequest(chapter: SChapter): Request {
+ if (chapter.url.startsWith("http")) {
+ return GET(chapter.url, headers)
+ }
+ return super.pageListRequest(chapter)
+ }
+
+ override fun pageListParse(document: Document): List {
+ return document.select("script:containsData(initreader)").first().data()
+ .substringAfter("initReader(\"")
+ .substringBefore("\", 1")
+ .let(::decodePages)
+ .mapIndexed { i, image -> Page(i, "", image) }
+ }
+
+ private fun decodePages(code: String): List {
+ val hidden: ByteArray = Base64.decode(code, Base64.DEFAULT)
+ var key: ByteArray = hidden.sliceArray(0..63)
+ var body: ByteArray = hidden.sliceArray(64..hidden.size-1)
+
+ val buf = StringBuilder()
+
+ for (begin in 0 until body.size step 64) {
+ var chunk: ByteArray = body.sliceArray(begin..begin+63)
+ for (x in 0 until 64) {
+ buf.append((chunk[x] xor key[x]).toChar())
+ }
+ key = chunk
+ }
+
+ val json = JsonParser().parse(buf.toString()).asJsonObject
+
+ val base = json.get("b").asString
+ val folder = json.get("r").asString
+ val id = json.get("i").asString
+ return json.get("f").asJsonArray.map { it ->
+ val page = it.asJsonObject
+ "${base}${folder}${page.get("h").asString}/${id}/${page.get("p").asString}"
+ }
+ }
+
+ override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
+
+ override fun getFilterList() = FilterList(
+ Filter.Header("Only one filter may be used at a time."),
+ Filter.Separator(),
+ ArtistFilter(),
+ TagFilter()
+ )
+
+ class ArtistFilter : Filter.Text("Search by Artist (must be exact match)")
+ class TagFilter : Filter.Text("Search by Tag (must be exact match)")
+
+ companion object {
+ const val PREFIX_ID_SEARCH = "id:"
+ }
+}
+
+private inline fun Iterable<*>.findInstance() = find { it is T } as? T
diff --git a/src/en/hentainexus/src/eu/kanade/tachiyomi/extension/en/hentainexus/HentaiNexusActivity.kt b/src/en/hentainexus/src/eu/kanade/tachiyomi/extension/en/hentainexus/HentaiNexusActivity.kt
new file mode 100644
index 000000000..5ef34cb8b
--- /dev/null
+++ b/src/en/hentainexus/src/eu/kanade/tachiyomi/extension/en/hentainexus/HentaiNexusActivity.kt
@@ -0,0 +1,38 @@
+package eu.kanade.tachiyomi.extension.en.hentainexus
+
+import android.app.Activity
+import android.content.ActivityNotFoundException
+import android.content.Intent
+import android.os.Bundle
+import android.util.Log
+import kotlin.system.exitProcess
+
+/**
+ * Springboard that accepts https://hentainexus.com/view/xxxx intents
+ * and redirects them to the main Tachiyomi process.
+ */
+class HentaiNexusActivity : Activity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val pathSegments = intent?.data?.pathSegments
+ if (pathSegments != null && pathSegments.size > 1) {
+ val id = pathSegments[1]
+ val mainIntent = Intent().apply {
+ action = "eu.kanade.tachiyomi.SEARCH"
+ putExtra("query", "${HentaiNexus.PREFIX_ID_SEARCH}$id")
+ putExtra("filter", packageName)
+ }
+
+ try {
+ startActivity(mainIntent)
+ } catch (e: ActivityNotFoundException) {
+ Log.e("HentaiNexusActivity", e.toString())
+ }
+ } else {
+ Log.e("HentaiNexusActivity", "Could not parse URI from intent $intent")
+ }
+
+ finish()
+ exitProcess(0)
+ }
+}
diff --git a/src/it/mangaworld/build.gradle b/src/it/mangaworld/build.gradle
new file mode 100644
index 000000000..95df3a271
--- /dev/null
+++ b/src/it/mangaworld/build.gradle
@@ -0,0 +1,12 @@
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+
+ext {
+ appName = 'Tachiyomi: Mangaworld'
+ pkgNameSuffix = 'it.mangaworld'
+ extClass = '.Mangaworld'
+ extVersionCode = 2
+ libVersion = '1.2'
+}
+
+apply from: "$rootDir/common.gradle"
diff --git a/src/it/mangaworld/res/mipmap-hdpi/ic_launcher.png b/src/it/mangaworld/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 000000000..a0e240ca8
Binary files /dev/null and b/src/it/mangaworld/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/src/it/mangaworld/res/mipmap-mdpi/ic_launcher.png b/src/it/mangaworld/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 000000000..2ebaa6e34
Binary files /dev/null and b/src/it/mangaworld/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/src/it/mangaworld/res/mipmap-xhdpi/ic_launcher.png b/src/it/mangaworld/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 000000000..2de3bdd62
Binary files /dev/null and b/src/it/mangaworld/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/src/it/mangaworld/res/mipmap-xxhdpi/ic_launcher.png b/src/it/mangaworld/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 000000000..30b969103
Binary files /dev/null and b/src/it/mangaworld/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/src/it/mangaworld/res/mipmap-xxxhdpi/ic_launcher.png b/src/it/mangaworld/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 000000000..a537d262b
Binary files /dev/null and b/src/it/mangaworld/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/src/it/mangaworld/res/web_hi_res_512.png b/src/it/mangaworld/res/web_hi_res_512.png
new file mode 100644
index 000000000..837e92699
Binary files /dev/null and b/src/it/mangaworld/res/web_hi_res_512.png differ
diff --git a/src/it/mangaworld/src/eu/kanade/tachiyomi/extension/it/mangaworld/Mangaworld.kt b/src/it/mangaworld/src/eu/kanade/tachiyomi/extension/it/mangaworld/Mangaworld.kt
new file mode 100644
index 000000000..f25c59dea
--- /dev/null
+++ b/src/it/mangaworld/src/eu/kanade/tachiyomi/extension/it/mangaworld/Mangaworld.kt
@@ -0,0 +1,293 @@
+package eu.kanade.tachiyomi.extension.it.mangaworld
+
+import eu.kanade.tachiyomi.network.GET
+import eu.kanade.tachiyomi.source.online.ParsedHttpSource
+import okhttp3.*
+import org.jsoup.nodes.Document
+import org.jsoup.nodes.Element
+import java.text.SimpleDateFormat
+import java.util.*
+import eu.kanade.tachiyomi.source.model.*
+import java.text.ParseException
+
+class Mangaworld: ParsedHttpSource() {
+
+ override val name = "Mangaworld"
+ override val baseUrl = "https://mangaworld.tv"
+ override val lang = "it"
+ override val supportsLatest = true
+ override val client: OkHttpClient = network.cloudflareClient
+
+ override fun popularMangaRequest(page: Int): Request {
+ return GET("$baseUrl/page/$page?s&post_type=wp-manga&m_orderby=views", headers)
+ }
+ override fun latestUpdatesRequest(page: Int): Request {
+ return GET("$baseUrl/page/$page?s&post_type=wp-manga&m_orderby=latest", headers)
+ }
+ // LIST SELECTOR
+ override fun popularMangaSelector() = "div.c-tabs-item__content"
+ override fun latestUpdatesSelector() = popularMangaSelector()
+ override fun searchMangaSelector() = popularMangaSelector()
+
+ // ELEMENT
+ override fun popularMangaFromElement(element: Element): SManga = searchMangaFromElement(element)
+ override fun latestUpdatesFromElement(element: Element): SManga = searchMangaFromElement(element)
+
+ // NEXT SELECTOR
+ override fun popularMangaNextPageSelector() = "div.nav-previous.float-left > a"
+ override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
+ override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
+
+ override fun searchMangaFromElement(element: Element):SManga {
+ val manga = SManga.create()
+ manga.thumbnail_url = element.select("div.tab-thumb > a > img").attr("src")
+ element.select("div.tab-thumb > a").first().let {
+ manga.setUrlWithoutDomain(it.attr("href"))
+ manga.title = it.attr("title")
+ }
+ return manga
+ }
+
+ override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+ val url = HttpUrl.parse("$baseUrl/page/$page")!!.newBuilder()
+ url.addQueryParameter("post_type","wp-manga")
+ val pattern = "\\s+".toRegex()
+ val q = query.replace(pattern, "+")
+ if(query.length > 0){
+ url.addQueryParameter("s", q)
+ }else{
+ url.addQueryParameter("s", "")
+ }
+
+ var orderBy = ""
+
+ (if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
+ when (filter) {
+// is Status -> url.addQueryParameter("manga_status", arrayOf("", "completed", "ongoing")[filter.state])
+ is GenreList -> {
+ val genreInclude = mutableListOf()
+ filter.state.forEach {
+ if (it.state == 1) {
+ genreInclude.add(it.id)
+ }
+ }
+ if(genreInclude.isNotEmpty()){
+ genreInclude.forEach{ genre ->
+ url.addQueryParameter("genre[]", genre)
+ }
+ }
+ }
+ is StatusList ->{
+ val statuses = mutableListOf()
+ filter.state.forEach {
+ if (it.state == 1) {
+ statuses.add(it.id)
+ }
+ }
+ if(statuses.isNotEmpty()){
+ statuses.forEach{ status ->
+ url.addQueryParameter("status[]", status)
+ }
+ }
+ }
+
+ is SortBy -> {
+ orderBy = filter.toUriPart();
+ url.addQueryParameter("m_orderby",orderBy)
+ }
+ is TextField -> url.addQueryParameter(filter.key, filter.state)
+ }
+ }
+
+ return GET(url.toString(), headers)
+ }
+
+
+
+ // max 200 results
+
+ override fun mangaDetailsParse(document: Document): SManga {
+ val infoElement = document.select("div.site-content").first()
+
+ val manga = SManga.create()
+ manga.author = infoElement.select("div.author-content")?.text()
+ manga.artist = infoElement.select("div.artist-content")?.text()
+
+ val genres = mutableListOf()
+ infoElement.select("div.genres-content a").forEach { element ->
+ val genre = element.text()
+ genres.add(genre)
+ }
+ manga.genre =genres.joinToString(", ")
+ manga.status = parseStatus(infoElement.select("div.post-status > div:nth-child(2) div").text())
+
+ manga.description = document.select("div.summary__content > p")?.text()
+ manga.thumbnail_url = document.select("div.summary_image > a > img").attr("src")
+
+ return manga
+ }
+
+ private fun parseStatus(element: String): Int = when {
+
+ element.toLowerCase().contains("ongoing") -> SManga.ONGOING
+ element.toLowerCase().contains("completed") -> SManga.COMPLETED
+ else -> SManga.UNKNOWN
+ }
+
+ override fun chapterListSelector() = "li.wp-manga-chapter"
+
+ override fun chapterFromElement(element: Element): SChapter {
+ val urlElement = element.select("a").first()
+ val chapter = SChapter.create()
+ chapter.setUrlWithoutDomain(getUrl(urlElement))
+ chapter.name = urlElement.text()
+ chapter.date_upload = element.select("span.chapter-release-date i").last()?.text()?.let {
+ try {
+ SimpleDateFormat("dd MMMM yyyy", Locale.ITALY).parse(it).time
+ } catch (e: ParseException) {
+ SimpleDateFormat("H", Locale.ITALY).parse(it).time
+ }
+
+ } ?: 0
+ return chapter
+ }
+
+ private fun getUrl(urlElement: Element): String {
+ var url = urlElement.attr("href")
+ return when {
+ url.endsWith("?style=list") -> url
+ else -> "$url?style=list"
+ }
+ }
+
+ override fun prepareNewChapter(chapter: SChapter, manga: SManga) {
+ val basic = Regex("""Capitolo\s([0-9]+)""")
+ when {
+ basic.containsMatchIn(chapter.name) -> {
+ basic.find(chapter.name)?.let {
+ chapter.chapter_number = it.groups[1]?.value!!.toFloat()
+ }
+ }
+ }
+ }
+
+ override fun pageListParse(document: Document): List {
+ val pages = mutableListOf()
+ var i = 0
+ document.select("div.reading-content * img").forEach { element ->
+ val url = element.attr("src")
+ i++
+ if(url.length != 0){
+ pages.add(Page(i, "", url))
+ }
+ }
+ return pages
+ }
+
+ override fun imageUrlParse(document: Document) = ""
+
+ override fun imageRequest(page: Page): Request {
+ val imgHeader = Headers.Builder().apply {
+ add("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.1.1; en-gb; Build/KLP) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30")
+ add("Referer", baseUrl)
+ }.build()
+ return GET(page.imageUrl!!, imgHeader)
+ }
+ // private class Status : Filter.TriState("Completed")
+ private class TextField(name: String, val key: String) : Filter.Text(name)
+ private class SortBy : UriPartFilter("Ordina per", arrayOf(
+ Pair("Rilevanza", ""),
+ Pair("Ultime Aggiunte", "latest"),
+ Pair("A-Z", "alphabet"),
+ Pair("Voto", "rating"),
+ Pair("Tendenza", "trending"),
+ Pair("PiĆ¹ Visualizzati", "views"),
+ Pair("Nuove Aggiunte", "new-manga")
+ ))
+ private class Genre(name: String, val id: String = name) : Filter.TriState(name)
+ private class GenreList(genres: List) : Filter.Group("Generi", genres)
+ private class Status(name: String, val id: String = name) : Filter.TriState(name)
+ private class StatusList(statuses: List) : Filter.Group("Stato", statuses)
+
+ override fun getFilterList() = FilterList(
+// TextField("Judul", "title"),
+ TextField("Autore", "author"),
+ TextField("Anno di rilascio", "release"),
+ SortBy(),
+ StatusList(getStatusList()),
+ GenreList(getGenreList())
+ )
+ private fun getStatusList() = listOf(
+ Status("Completato","end"),
+ Status("In Corso","on-going"),
+ Status("Droppato","canceled"),
+ Status("In Pausa","on-hold")
+ )
+ private fun getGenreList() = listOf(
+ Genre("Adulti","adult"),
+ Genre("Anime","anime"),
+ Genre("Arti Marziali","martial-arts"),
+ Genre("Avventura","adventure"),
+ Genre("Azione","action"),
+ Genre("Cartoon","cartoon"),
+ Genre("Comic","comic"),
+ Genre("Commedia","comedy"),
+ Genre("Cucina","cooking"),
+ Genre("Demoni","demoni"),
+ Genre("Detective","detective"),
+ Genre("Doujinshi","doujinshi"),
+ Genre("Drama","drama-"),
+ Genre("Drammatico","drama"),
+ Genre("Ecchi","ecchi"),
+ Genre("Fantasy","fantasy"),
+ Genre("Game","game"),
+ Genre("Gender Bender","gender-bender"),
+ Genre("Harem","harem"),
+ Genre("Hentai","hentai"),
+ Genre("Horror","horror"),
+ Genre("Josei","josei"),
+ Genre("Live action","live-action"),
+ Genre("Magia","magia"),
+ Genre("Manga","manga"),
+ Genre("Manhua","manhua"),
+ Genre("Manhwa","manhwa"),
+ Genre("Mature","mature"),
+ Genre("Mecha","mecha"),
+ Genre("Militari","militari"),
+ Genre("Mistero","mystery"),
+ Genre("Musica","musica"),
+ Genre("One shot","one-shot"),
+ Genre("Parodia","parodia"),
+ Genre("Psicologico","psychological"),
+ Genre("Romantico","romance"),
+ Genre("RPG","rpg"),
+ Genre("Sci-fi","sci-fi"),
+ Genre("Scolastico","school-life"),
+ Genre("Seinen","seinen"),
+ Genre("Shoujo","shoujo"),
+ Genre("Shoujo Ai","shoujo-ai"),
+ Genre("Shounen","shounen"),
+ Genre("Shounen Ai","shounen-ai"),
+ Genre("Slice of Life","slice-of-life"),
+ Genre("Smut","smut"),
+ Genre("Soft Yaoi","soft-yaoi"),
+ Genre("Soft Yuri","soft-yuri"),
+ Genre("Soprannaturale","supernatural"),
+ Genre("Spazio","spazio"),
+ Genre("Sport","sports"),
+ Genre("Storico","historical"),
+ Genre("Super Poteri","superpower"),
+ Genre("Thriller","thriller"),
+ Genre("Tragico","tragedy"),
+ Genre("Vampiri","vampiri"),
+ Genre("Webtoon","webtoon"),
+ Genre("Yaoi","yaoi"),
+ Genre("Yuri","yuri")
+ )
+ private open class UriPartFilter(displayName: String, val vals: Array>) :
+ Filter.Select(displayName, vals.map { it.first }.toTypedArray()) {
+ fun toUriPart() = vals[state].second
+ }
+
+
+}