[Source is Down] Remove JMana & Esomanga (#1540)
* JMana Source is Down * Esomamga Source is Down
|
@ -1,7 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'JMana'
|
|
||||||
extClass = '.JMana'
|
|
||||||
extVersionCode = 15
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 24 KiB |
|
@ -1,238 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.ko.jmana
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import android.widget.Toast
|
|
||||||
import eu.kanade.tachiyomi.AppInfo
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
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 eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import okhttp3.Request
|
|
||||||
import okhttp3.Response
|
|
||||||
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.Locale
|
|
||||||
|
|
||||||
/**
|
|
||||||
* JMana Source
|
|
||||||
**/
|
|
||||||
class JMana : ConfigurableSource, ParsedHttpSource() {
|
|
||||||
override val name = "JMana"
|
|
||||||
override val baseUrl: String by lazy { getPrefBaseUrl()!!.removeSuffix("/") }
|
|
||||||
override val lang: String = "ko"
|
|
||||||
override val supportsLatest = true
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
|
||||||
.add("Referer", baseUrl)
|
|
||||||
|
|
||||||
private fun String.cleanedUrl() = this.replace(" ", "%20").replace(Regex("/[0-9]+(?!.*?/)"), "")
|
|
||||||
|
|
||||||
// Latest page has chapter number appended to the title
|
|
||||||
private fun String.cleanedTitle() = this.removeSuffix("([0-9]+-)?[0-9]+화".toRegex().find(this)?.value ?: "").trim()
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.content > div.search-result-wrap > div.img-lst-wrap > ul > li"
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
|
||||||
return SManga.create().apply {
|
|
||||||
element.select("div.txt-wrap > a.tit").let {
|
|
||||||
setUrlWithoutDomain("/" + it.attr("href").cleanedUrl())
|
|
||||||
title = it.text()
|
|
||||||
}
|
|
||||||
thumbnail_url = element.select("a.img-wrap > img").attr("abs:src")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
// Do not add page parameter if page is 1 to prevent tracking.
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/comic_list?page=${page - 1}", headers)
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val mangas = document.select(popularMangaSelector()).map { element ->
|
|
||||||
popularMangaFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasNextPage = document.select("div.lst-btm-wrap > div.cnt-wrap > ul.pager-wrap > li.next > a").attr("href") != "#"
|
|
||||||
|
|
||||||
return MangasPage(mangas, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
|
||||||
override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
|
|
||||||
override fun searchMangaNextPageSelector() = throw UnsupportedOperationException()
|
|
||||||
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/comic_list?page=${page - 1}&keyword=$query", headers)
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val descriptionElement = document.select("div.content > div.books-list-detail > div.books-db-detail")
|
|
||||||
|
|
||||||
val manga = SManga.create()
|
|
||||||
descriptionElement.select("div.books-d-wrap > dl")
|
|
||||||
.map { it.text() }
|
|
||||||
.forEach { text ->
|
|
||||||
when {
|
|
||||||
DETAIL_AUTHOR in text -> manga.author = text.substringAfter(DETAIL_AUTHOR).trim()
|
|
||||||
DETAIL_GENRE in text -> manga.genre = text.substringAfter(DETAIL_GENRE).trim()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
manga.title = descriptionElement.select("a.tit").text()
|
|
||||||
manga.thumbnail_url = descriptionElement.select("div.books-thumnail img").attr("abs:src")
|
|
||||||
return manga
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector() = "div.content > div.books-list-detail > div.lst-wrap > ul > li"
|
|
||||||
private val TAG = "JMana"
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter {
|
|
||||||
val top = element.select("div.top-layout-m > div.inner > a.tit")
|
|
||||||
val bottom = element.select("div.btm-layout-m > div.inner > p.date")
|
|
||||||
val rawName = top.text()
|
|
||||||
|
|
||||||
return SChapter.create().apply {
|
|
||||||
setUrlWithoutDomain(top.attr("abs:href"))
|
|
||||||
chapter_number = parseChapterNumber(rawName)
|
|
||||||
name = rawName.trim()
|
|
||||||
date_upload = parseChapterDate(bottom.text())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterNumber(name: String): Float {
|
|
||||||
try {
|
|
||||||
if (name.contains("[단편]")) return 1f
|
|
||||||
// `특별` means `Special`, so It can be buggy. so pad `편`(Chapter) to prevent false return
|
|
||||||
if (name.contains("번외") || name.contains("특별편")) return -2f
|
|
||||||
val regex = Regex("([0-9]+)(?:[-.]([0-9]+))?(?:화)")
|
|
||||||
val (ch_primal, ch_second) = regex.find(name)!!.destructured
|
|
||||||
return (ch_primal + if (ch_second.isBlank()) "" else ".$ch_second").toFloatOrNull() ?: -1f
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
return -1f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long {
|
|
||||||
return try {
|
|
||||||
SimpleDateFormat("yy-MM-dd", Locale.getDefault()).parse(date)?.time ?: 0
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> {
|
|
||||||
// <img class="comicdetail" style="width:auto;min-width:auto;margin:auto;display:block"
|
|
||||||
// data-src="https://img6.xyz.futbol/comics/jdrive01/202005/하야테처럼/하야테처럼! 1화/2d206674-93f5-4991-9420-6d63e2a00010.jpg">
|
|
||||||
val pages = document.select("div.pdf-wrap img.comicdetail")
|
|
||||||
.groupBy { img ->
|
|
||||||
val imageUrl = getImageUrl(img)
|
|
||||||
extractChapterName(imageUrl)
|
|
||||||
}
|
|
||||||
.maxByOrNull { it.value.size }
|
|
||||||
?.value
|
|
||||||
?.mapIndexed { i, img ->
|
|
||||||
Page(
|
|
||||||
i,
|
|
||||||
"",
|
|
||||||
getImageUrl(img),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return pages ?: emptyList()
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extracts the chapter name from the image url, e.g.
|
|
||||||
* https://img6.xyz.futbol/comics/jdrive01/202005/하야테처럼/하야테처럼! 1화/2d206674-93f5-4991-9420-6d63e2a00010.jpg
|
|
||||||
* -> '하야테처럼! 1화'
|
|
||||||
*/
|
|
||||||
private fun extractChapterName(imageUrl: String) =
|
|
||||||
imageUrl.split('/').dropLast(1).lastOrNull()
|
|
||||||
|
|
||||||
private fun getImageUrl(img: Element) =
|
|
||||||
if (img.hasAttr("data-src")) img.attr("abs:data-src") else img.attr("abs:src")
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/comic_recent?page=$page", headers)
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
val mangas = document.select(latestUpdatesSelector()).map { element ->
|
|
||||||
latestUpdatesFromElement(element)
|
|
||||||
}
|
|
||||||
|
|
||||||
val hasNextPage = document.select("div.lst-btm-wrap > div.cnt-wrap > ul.pager-wrap > li.next > a").attr("href") != "#"
|
|
||||||
|
|
||||||
return MangasPage(mangas, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = "div.content > div.board03 > div.img-lst-wrap > ul > li"
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga {
|
|
||||||
return SManga.create().apply {
|
|
||||||
element.select("div.list-con > div.books-db").let {
|
|
||||||
setUrlWithoutDomain(it.select("a.btn").attr("href").cleanedUrl())
|
|
||||||
title = it.select("a.tit").text().cleanedTitle()
|
|
||||||
}
|
|
||||||
thumbnail_url = element.select("a.img-wrap > img").attr("abs:src")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
// We are able to get the image URL directly from the page list
|
|
||||||
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val DETAIL_GENRE = "장르 : "
|
|
||||||
const val DETAIL_AUTHOR = "작가 : "
|
|
||||||
const val DETAIL_DESCRIPTION = "설명 : "
|
|
||||||
const val DEFAULT_BASEURL = "https://jmana1.net"
|
|
||||||
private const val BASE_URL_PREF_TITLE = "Override BaseUrl"
|
|
||||||
private val BASE_URL_PREF = "overrideBaseUrl_v${AppInfo.getVersionName()}"
|
|
||||||
private const val BASE_URL_PREF_SUMMARY = "For temporary uses. Update extension will erase this setting."
|
|
||||||
private const val RESTART_TACHIYOMI = "Restart Tachiyomi to apply new setting."
|
|
||||||
}
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
|
||||||
val baseUrlPref = androidx.preference.EditTextPreference(screen.context).apply {
|
|
||||||
key = BASE_URL_PREF_TITLE
|
|
||||||
title = BASE_URL_PREF_TITLE
|
|
||||||
summary = BASE_URL_PREF_SUMMARY
|
|
||||||
this.setDefaultValue(DEFAULT_BASEURL)
|
|
||||||
dialogTitle = BASE_URL_PREF_TITLE
|
|
||||||
dialogMessage = "Default: $DEFAULT_BASEURL"
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
try {
|
|
||||||
val res = preferences.edit().putString(BASE_URL_PREF, newValue as String).commit()
|
|
||||||
Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
|
|
||||||
res
|
|
||||||
} catch (e: Exception) {
|
|
||||||
e.printStackTrace()
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
screen.addPreference(baseUrlPref)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPrefBaseUrl() = preferences.getString(BASE_URL_PREF, DEFAULT_BASEURL)
|
|
||||||
}
|
|
|
@ -1,9 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'Esomanga'
|
|
||||||
extClass = '.Esomanga'
|
|
||||||
themePkg = 'madara'
|
|
||||||
baseUrl = 'https://esomanga.com'
|
|
||||||
overrideVersionCode = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Before Width: | Height: | Size: 5.9 KiB |
Before Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 26 KiB |
|
@ -1,5 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.tr.esomanga
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
|
||||||
|
|
||||||
class Esomanga : Madara("Esomanga", "https://esomanga.com", "tr")
|
|