|
@ -76,4 +76,4 @@ dependencies {
|
|||
}
|
||||
|
||||
preBuild.dependsOn(lintKotlin)
|
||||
lintKotlin.dependsOn(formatKotlin)
|
||||
lintKotlin.dependsOn(formatKotlin)
|
|
@ -5,7 +5,7 @@ ext {
|
|||
extName = 'Madara (multiple sources)'
|
||||
pkgNameSuffix = "all.madara"
|
||||
extClass = '.MadaraFactory'
|
||||
extVersionCode = 159
|
||||
extVersionCode = 160
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
<activity
|
||||
android:name=".HentaiNexusActivity"
|
||||
android:theme="@android:style/Theme.NoDisplay"
|
||||
android:excludeFromRecents="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
<data android:scheme="https"
|
||||
android:host="hentainexus.com"
|
||||
android:pathPattern="/view/..*"/>
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -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"
|
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 1.8 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 5.5 KiB |
After Width: | Height: | Size: 8.8 KiB |
After Width: | Height: | Size: 30 KiB |
|
@ -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<ArtistFilter>()?.let { f ->
|
||||
if (f.state.isNotBlank()) {
|
||||
requireNoUrl()
|
||||
url = "/"
|
||||
queryString = "q=artist:%22${URLEncoder.encode(f.state, "UTF-8")}%22"
|
||||
}
|
||||
}
|
||||
|
||||
filters.findInstance<TagFilter>()?.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<MangasPage> {
|
||||
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<String>()
|
||||
|
||||
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<Page> {
|
||||
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<String> {
|
||||
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 <reified T> Iterable<*>.findInstance() = find { it is T } as? T
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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"
|
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.7 KiB |
After Width: | Height: | Size: 3.5 KiB |
After Width: | Height: | Size: 6.6 KiB |
After Width: | Height: | Size: 8.1 KiB |
After Width: | Height: | Size: 51 KiB |
|
@ -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<String>()
|
||||
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<String>()
|
||||
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<String>()
|
||||
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<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
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<Genre>) : Filter.Group<Genre>("Generi", genres)
|
||||
private class Status(name: String, val id: String = name) : Filter.TriState(name)
|
||||
private class StatusList(statuses: List<Status>) : Filter.Group<Status>("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<Pair<String, String>>) :
|
||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||
fun toUriPart() = vals[state].second
|
||||
}
|
||||
|
||||
|
||||
}
|