Misc code cleanup
This commit is contained in:
@ -5,7 +5,7 @@ ext {
|
||||
appName = 'Tachiyomi: FMReader (multiple aggregators)'
|
||||
pkgNameSuffix = 'all.fmreader'
|
||||
extClass = '.FMReaderFactory'
|
||||
extVersionCode = 2
|
||||
extVersionCode = 3
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,27 @@
|
||||
package eu.kanade.tachiyomi.extension.all.fmreader
|
||||
|
||||
// For sites based on the Flat-Manga CMS
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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 eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.*
|
||||
import java.util.*
|
||||
import java.util.Calendar
|
||||
|
||||
abstract class FMReader (
|
||||
/**
|
||||
* For sites based on the Flat-Manga CMS
|
||||
*/
|
||||
abstract class FMReader(
|
||||
override val name: String,
|
||||
override val baseUrl: String,
|
||||
override val lang: String
|
||||
@ -43,10 +53,8 @@ abstract class FMReader (
|
||||
}
|
||||
is TextField -> url.addQueryParameter(filter.key, filter.state)
|
||||
is GenreList -> {
|
||||
|
||||
var genre = String()
|
||||
var ungenre = String()
|
||||
|
||||
filter.state.forEach {
|
||||
if (it.isIncluded()) genre += ",${it.name}"
|
||||
if (it.isExcluded()) ungenre += ",${it.name}"
|
||||
@ -79,7 +87,7 @@ abstract class FMReader (
|
||||
val mangas = mutableListOf<SManga>()
|
||||
var hasNextPage = true
|
||||
|
||||
document.select(popularMangaSelector()).map{ mangas.add(popularMangaFromElement(it)) }
|
||||
document.select(popularMangaSelector()).map { mangas.add(popularMangaFromElement(it)) }
|
||||
|
||||
// check if there's a next page
|
||||
document.select(popularMangaNextPageSelector()).first().text().split(" ").let {
|
||||
@ -108,7 +116,7 @@ abstract class FMReader (
|
||||
manga.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
manga.title = it.text()
|
||||
}
|
||||
manga.thumbnail_url = element.select("img").let{
|
||||
manga.thumbnail_url = element.select("img").let {
|
||||
if (it.hasAttr("src")) {
|
||||
it.attr("abs:src")
|
||||
} else {
|
||||
@ -160,11 +168,11 @@ abstract class FMReader (
|
||||
override fun chapterFromElement(element: Element): SChapter {
|
||||
val chapter = SChapter.create()
|
||||
|
||||
element.select(chapterUrlSelector).first().let{
|
||||
element.select(chapterUrlSelector).first().let {
|
||||
chapter.setUrlWithoutDomain(it.attr("abs:href"))
|
||||
chapter.name = it.text()
|
||||
}
|
||||
chapter.date_upload = element.select(chapterTimeSelector).let{ if(it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
chapter.date_upload = element.select(chapterTimeSelector).let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
|
||||
return chapter
|
||||
}
|
||||
@ -177,7 +185,7 @@ abstract class FMReader (
|
||||
|
||||
private fun parseChapterDate(date: String): Long {
|
||||
val value = date.split(' ')[dateValueIndex].toInt()
|
||||
val dateWord = date.split(' ')[dateWordIndex].let{
|
||||
val dateWord = date.split(' ')[dateWordIndex].let {
|
||||
if (it.contains("(")) {
|
||||
it.substringBefore("(")
|
||||
} else {
|
||||
@ -227,7 +235,7 @@ abstract class FMReader (
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("img.chapter-img").forEachIndexed { i, img ->
|
||||
pages.add(Page(i, "", img.attr("abs:data-src").let{ if (it.isNotEmpty()) it else img.attr("abs:src") }))
|
||||
pages.add(Page(i, "", img.attr("abs:data-src").let { if (it.isNotEmpty()) it else img.attr("abs:src") }))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
@ -5,9 +5,17 @@ import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.model.*
|
||||
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.util.asJsoup
|
||||
import okhttp3.*
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
@ -40,6 +48,7 @@ class FMReaderFactory : SourceFactory {
|
||||
* most likely the fix is to override popularMangaNextPageSelector() */
|
||||
|
||||
class LHTranslation : FMReader("LHTranslation", "https://lhtranslation.net", "en")
|
||||
|
||||
class MangaHato : FMReader("MangaHato", "https://mangahato.com", "ja")
|
||||
class ManhwaScan : FMReader("ManhwaScan", "https://manhwascan.com", "en")
|
||||
class MangaTiki : FMReader("MangaTiki", "https://mangatiki.com", "ja")
|
||||
@ -47,16 +56,20 @@ class MangaBone : FMReader("MangaBone", "https://mangabone.com", "en")
|
||||
class YoloManga : FMReader("Yolo Manga", "https://yolomanga.ca", "es") {
|
||||
override fun chapterListSelector() = "div#tab-chapper ~ div#tab-chapper table tr"
|
||||
}
|
||||
|
||||
class MangaLeer : FMReader("MangaLeer", "https://mangaleer.com", "es") {
|
||||
override val dateValueIndex = 1
|
||||
override val dateWordIndex = 2
|
||||
}
|
||||
|
||||
class AiLoveManga : FMReader("AiLoveManga", "https://ailovemanga.com", "vi") {
|
||||
override val requestPath = "danh-sach-truyen.html"
|
||||
// TODO: could add a genre search (different URL paths for genres)
|
||||
override fun getFilterList() = FilterList()
|
||||
|
||||
// I don't know why, but I have to override searchMangaRequest to make it work for this source
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) = GET("$baseUrl/$requestPath?name=$query&page=$page")
|
||||
|
||||
override fun chapterListSelector() = "div#tab-chapper table tr"
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
@ -72,10 +85,12 @@ class AiLoveManga : FMReader("AiLoveManga", "https://ailovemanga.com", "vi") {
|
||||
return manga
|
||||
}
|
||||
}
|
||||
|
||||
class ReadComicOnlineOrg : FMReader("ReadComicOnline.org", "https://readcomiconline.org", "en") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor { requestIntercept(it) }
|
||||
.build()
|
||||
|
||||
private fun requestIntercept(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
val response = chain.proceed(request)
|
||||
@ -85,46 +100,55 @@ class ReadComicOnlineOrg : FMReader("ReadComicOnline.org", "https://readcomiconl
|
||||
.add("dqh_firewall", "%2F")
|
||||
.build()
|
||||
val cookie = mutableListOf<String>()
|
||||
response.headers("set-cookie").map{ cookie.add(it.substringBefore(" ")) }
|
||||
response.headers("set-cookie").map { cookie.add(it.substringBefore(" ")) }
|
||||
headers.newBuilder().add("Cookie", cookie.joinToString { " " }).build()
|
||||
client.newCall(POST(request.url().toString(), headers, body)).execute()
|
||||
} else {
|
||||
response
|
||||
}
|
||||
}
|
||||
|
||||
override val requestPath = "comic-list.html"
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("div#divImage > select:first-of-type option").forEachIndexed{ i, imgPage ->
|
||||
document.select("div#divImage > select:first-of-type option").forEachIndexed { i, imgPage ->
|
||||
pages.add(Page(i, imgPage.attr("value"), ""))
|
||||
}
|
||||
return pages.dropLast(1) // last page is a comments page
|
||||
}
|
||||
|
||||
override fun imageUrlRequest(page: Page): Request = GET(baseUrl + page.url, headers)
|
||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
||||
override fun getGenreList() = getComicsGenreList()
|
||||
}
|
||||
|
||||
class MangaWeek : FMReader("MangaWeek", "https://mangaweek.com", "en")
|
||||
class HanaScan : FMReader("HanaScan (RawQQ)", "http://rawqq.com", "ja") {
|
||||
override fun popularMangaNextPageSelector() = "div.col-md-8 button"
|
||||
}
|
||||
|
||||
class RawLH : FMReader("RawLH", "https://lhscan.net", "ja") {
|
||||
override fun popularMangaNextPageSelector() = "div.col-md-8 button"
|
||||
}
|
||||
|
||||
class Manhwa18 : FMReader("Manhwa18", "https://manhwa18.com", "en") {
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
}
|
||||
|
||||
class TruyenTranhLH : FMReader("TruyenTranhLH", "https://truyentranhlh.net", "vi") {
|
||||
override val requestPath = "danh-sach-truyen.html"
|
||||
}
|
||||
|
||||
class EighteenLHPlus : FMReader("18LHPlus", "https://18lhplus.com", "en") {
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
}
|
||||
|
||||
class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
override fun popularMangaNextPageSelector() = "div.btn-group:not(div.btn-block) button.btn-info"
|
||||
// TODO: genre search possible but a bit of a pain
|
||||
override fun getFilterList() = FilterList()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/arama.html?icerik=$query", headers)
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val mangas = mutableListOf<SManga>()
|
||||
@ -135,6 +159,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
@ -143,6 +168,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
val infoElement = document.select("div#tab1").first()
|
||||
@ -156,6 +182,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "tr.table-bordered"
|
||||
override val chapterUrlSelector = "td[align=left] > a"
|
||||
override val chapterTimeSelector = "td[align=right]"
|
||||
@ -172,6 +199,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
Observable.error(Exception("Licensed - No chapters to show"))
|
||||
}
|
||||
}
|
||||
|
||||
private fun chapterListParse(response: Response, requestUrl: String): List<SChapter> {
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
var document = response.asJsoup()
|
||||
@ -180,7 +208,7 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
|
||||
// chapters are paginated
|
||||
while (moreChapters) {
|
||||
document.select(chapterListSelector()).map{ chapters.add(chapterFromElement(it)) }
|
||||
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
|
||||
if (document.select("a[data-page=$nextPage]").isNotEmpty()) {
|
||||
val body = FormBody.Builder()
|
||||
.add("page", nextPage.toString())
|
||||
@ -193,21 +221,25 @@ class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
}
|
||||
return chapters
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request = GET("$baseUrl/${chapter.url.substringAfter("cek/")}", headers)
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("div.chapter-content select:first-of-type option").forEachIndexed{ i, imgPage ->
|
||||
document.select("div.chapter-content select:first-of-type option").forEachIndexed { i, imgPage ->
|
||||
pages.add(Page(i, "$baseUrl/${imgPage.attr("value")}", ""))
|
||||
}
|
||||
return pages.dropLast(1) // last page is a comments page
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
||||
}
|
||||
|
||||
class Comicastle : FMReader("Comicastle", "https://www.comicastle.org", "en") {
|
||||
override val requestPath = "comic-dir"
|
||||
// this source doesn't have the "page x of y" element
|
||||
override fun popularMangaNextPageSelector() = "li:contains(»)"
|
||||
|
||||
override fun popularMangaParse(response: Response) = defaultMangaParse(response)
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/comic-dir?q=$query", headers)
|
||||
override fun searchMangaParse(response: Response): MangasPage = defaultMangaParse(response)
|
||||
@ -224,39 +256,43 @@ class Comicastle : FMReader("Comicastle", "https://www.comicastle.org", "en") {
|
||||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "div.col-md-9 table:last-of-type tr"
|
||||
override fun chapterListParse(response: Response): List<SChapter> = super.chapterListParse(response).reversed()
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
val pages = mutableListOf<Page>()
|
||||
|
||||
document.select("div.text-center select option").forEachIndexed{ i, imgPage ->
|
||||
document.select("div.text-center select option").forEachIndexed { i, imgPage ->
|
||||
pages.add(Page(i, imgPage.attr("value"), ""))
|
||||
}
|
||||
return pages
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document): String = document.select("img.chapter-img").attr("abs:src").trim()
|
||||
override fun getGenreList() = getComicsGenreList()
|
||||
}
|
||||
|
||||
class Manhwa18Net : FMReader("Manhwa18.net", "https://manhwa18.net", "en") {
|
||||
override fun popularMangaRequest(page: Int): Request =
|
||||
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=views&sort_type=DESC&ungenre=raw", headers)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=last_update&sort_type=DESC&ungenre=raw", headers)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val noRawsUrl = super.searchMangaRequest(page, query, filters).url().newBuilder().addQueryParameter("ungenre", "raw").toString()
|
||||
return GET(noRawsUrl, headers)
|
||||
}
|
||||
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
}
|
||||
|
||||
class Manhwa18NetRaw : FMReader("Manhwa18.net Raw", "https://manhwa18.net", "ko") {
|
||||
override val requestPath = "manga-list-genre-raw.html"
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val onlyRawsUrl = super.searchMangaRequest(page, query, filters).url().newBuilder().addQueryParameter("genre", "raw").toString()
|
||||
return GET(onlyRawsUrl, headers)
|
||||
}
|
||||
|
||||
override fun getFilterList() = FilterList(super.getFilterList().filterNot { it == GenreList(getGenreList()) })
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user