update FMReader for new theme (#5353)
* update FMReader for new theme * fix kissLove * clean thing after update factory * revert parseChapterDate to private * almost forgot this for substring chapter name
This commit is contained in:
parent
314cb965e3
commit
02259c06bd
|
@ -5,7 +5,7 @@ ext {
|
||||||
extName = 'FMReader (multiple aggregators)'
|
extName = 'FMReader (multiple aggregators)'
|
||||||
pkgNameSuffix = 'all.fmreader'
|
pkgNameSuffix = 'all.fmreader'
|
||||||
extClass = '.FMReaderFactory'
|
extClass = '.FMReaderFactory'
|
||||||
extVersionCode = 24
|
extVersionCode = 25
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ abstract class FMReader(
|
||||||
element == null -> null
|
element == null -> null
|
||||||
element.hasAttr("data-original") -> element.attr("abs:data-original")
|
element.hasAttr("data-original") -> element.attr("abs:data-original")
|
||||||
element.hasAttr("data-src") -> element.attr("abs:data-src")
|
element.hasAttr("data-src") -> element.attr("abs:data-src")
|
||||||
|
element.hasAttr("data-bg") -> element.attr("abs:data-bg")
|
||||||
else -> element.attr("abs:src")
|
else -> element.attr("abs:src")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -121,21 +122,21 @@ abstract class FMReader(
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
override fun searchMangaParse(response: Response) = popularMangaParse(response)
|
||||||
|
|
||||||
override fun popularMangaSelector() = "div.media"
|
override fun popularMangaSelector() = "div.media, .thumb-item-flow"
|
||||||
|
|
||||||
override fun latestUpdatesSelector() = popularMangaSelector()
|
override fun latestUpdatesSelector() = popularMangaSelector()
|
||||||
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
override fun searchMangaSelector() = popularMangaSelector()
|
||||||
|
|
||||||
open val headerSelector = "h3"
|
open val headerSelector = "h3 a, .series-title a"
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun popularMangaFromElement(element: Element): SManga {
|
||||||
return SManga.create().apply {
|
return SManga.create().apply {
|
||||||
element.select("$headerSelector a").let {
|
element.select("$headerSelector").let {
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
title = it.text()
|
title = it.text()
|
||||||
}
|
}
|
||||||
thumbnail_url = element.select("img").imgAttr()
|
thumbnail_url = element.select("img, .thumb-wrapper .img-in-ratio").imgAttr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +149,7 @@ abstract class FMReader(
|
||||||
* one is an element with text "page x of y", must be the first element if it's part of a collection
|
* one is an element with text "page x of y", must be the first element if it's part of a collection
|
||||||
* the other choice is the standard "next page" element (but most FMReader sources don't have this one)
|
* the other choice is the standard "next page" element (but most FMReader sources don't have this one)
|
||||||
*/
|
*/
|
||||||
override fun popularMangaNextPageSelector() = "div.col-lg-9 button.btn-info"
|
override fun popularMangaNextPageSelector() = "div.col-lg-9 button.btn-info, .pagination a:contains(»):not(.disabled)"
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
|
@ -161,7 +162,7 @@ abstract class FMReader(
|
||||||
author = infoElement.select("li a.btn-info").text()
|
author = infoElement.select("li a.btn-info").text()
|
||||||
genre = infoElement.select("li a.btn-danger").joinToString { it.text() }
|
genre = infoElement.select("li a.btn-danger").joinToString { it.text() }
|
||||||
status = parseStatus(infoElement.select("li a.btn-success").first()?.text())
|
status = parseStatus(infoElement.select("li a.btn-success").first()?.text())
|
||||||
description = document.select("div.detail .content, div.row ~ div.row:has(h3:first-child) p").text().trim()
|
description = document.select("div.detail .content, div.row ~ div.row:has(h3:first-child) p, .summary-content p").text().trim()
|
||||||
thumbnail_url = infoElement.select("img.thumbnail").imgAttr()
|
thumbnail_url = infoElement.select("img.thumbnail").imgAttr()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -180,7 +181,7 @@ abstract class FMReader(
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
val mangaTitle = document.select(".manga-info h1").text()
|
val mangaTitle = document.select(".manga-info h1, .manga-info h3").text()
|
||||||
return document.select(chapterListSelector()).map { chapterFromElement(it, mangaTitle) }.distinctBy { it.url }
|
return document.select(chapterListSelector()).map { chapterFromElement(it, mangaTitle) }.distinctBy { it.url }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,17 +189,26 @@ abstract class FMReader(
|
||||||
return chapterFromElement(element, "")
|
return chapterFromElement(element, "")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListSelector() = "div#list-chapters p, table.table tr"
|
override fun chapterListSelector() = "div#list-chapters p, table.table tr, .list-chapters a"
|
||||||
|
|
||||||
open val chapterUrlSelector = "a"
|
open val chapterUrlSelector = "a"
|
||||||
|
|
||||||
open val chapterTimeSelector = "time"
|
open val chapterTimeSelector = "time, .chapter-time"
|
||||||
|
|
||||||
|
open val chapterNameAttrSelector = "title"
|
||||||
|
|
||||||
open fun chapterFromElement(element: Element, mangaTitle: String = ""): SChapter {
|
open fun chapterFromElement(element: Element, mangaTitle: String = ""): SChapter {
|
||||||
return SChapter.create().apply {
|
return SChapter.create().apply {
|
||||||
element.select(chapterUrlSelector).first().let {
|
if (chapterUrlSelector != "") {
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
element.select(chapterUrlSelector).first().let {
|
||||||
name = it.text().substringAfter("$mangaTitle ")
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
|
name = it.text().substringAfter("$mangaTitle ")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
element.let {
|
||||||
|
setUrlWithoutDomain(it.attr("abs:href"))
|
||||||
|
name = element.attr(chapterNameAttrSelector).substringAfter("$mangaTitle ")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
date_upload = element.select(chapterTimeSelector).let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
date_upload = element.select(chapterTimeSelector).let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||||
}
|
}
|
||||||
|
@ -210,7 +220,7 @@ abstract class FMReader(
|
||||||
// gets the unit of time (day, week hour) from "1 day ago"
|
// gets the unit of time (day, week hour) from "1 day ago"
|
||||||
open val dateWordIndex = 1
|
open val dateWordIndex = 1
|
||||||
|
|
||||||
open fun parseChapterDate(date: String): Long {
|
private fun parseChapterDate(date: String): Long {
|
||||||
val value = date.split(' ')[dateValueIndex].toInt()
|
val value = date.split(' ')[dateValueIndex].toInt()
|
||||||
val dateWord = date.split(' ')[dateWordIndex].let {
|
val dateWord = date.split(' ')[dateWordIndex].let {
|
||||||
if (it.contains("(")) {
|
if (it.contains("(")) {
|
||||||
|
@ -268,7 +278,10 @@ abstract class FMReader(
|
||||||
|
|
||||||
protected fun base64PageListParse(document: Document): List<Page> {
|
protected fun base64PageListParse(document: Document): List<Page> {
|
||||||
fun Element.decoded(): String {
|
fun Element.decoded(): String {
|
||||||
val attr = if (this.hasAttr("data-original")) "data-original" else "data-src"
|
val attr =
|
||||||
|
if (this.hasAttr("data-original")) "data-original"
|
||||||
|
else if (this.hasAttr("data-src")) "data-src"
|
||||||
|
else "src"
|
||||||
return if (!this.attr(attr).contains(".")) {
|
return if (!this.attr(attr).contains(".")) {
|
||||||
Base64.decode(this.attr(attr), Base64.DEFAULT).toString(Charset.defaultCharset())
|
Base64.decode(this.attr(attr), Base64.DEFAULT).toString(Charset.defaultCharset())
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.fmreader
|
package eu.kanade.tachiyomi.extension.all.fmreader
|
||||||
|
|
||||||
import android.util.Base64
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
@ -19,7 +18,6 @@ import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.nio.charset.Charset
|
|
||||||
|
|
||||||
class FMReaderFactory : SourceFactory {
|
class FMReaderFactory : SourceFactory {
|
||||||
override fun createSources(): List<Source> = listOf(
|
override fun createSources(): List<Source> = listOf(
|
||||||
|
@ -45,7 +43,7 @@ class FMReaderFactory : SourceFactory {
|
||||||
|
|
||||||
class LHTranslation : FMReader("LHTranslation", "https://lhtranslation.net", "en")
|
class LHTranslation : FMReader("LHTranslation", "https://lhtranslation.net", "en")
|
||||||
|
|
||||||
class KissLove : FMReader("KissLove", "https://kisslove.net", "ja") {
|
class KissLove : FMReader("KissLove", "https://kissaway.net", "ja") {
|
||||||
override fun pageListParse(document: Document): List<Page> = base64PageListParse(document)
|
override fun pageListParse(document: Document): List<Page> = base64PageListParse(document)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,53 +70,8 @@ class HeroScan : FMReader("HeroScan", "https://heroscan.com", "en") {
|
||||||
}
|
}
|
||||||
|
|
||||||
class RawLH : FMReader("RawLH", "https://lovehug.net", "ja") {
|
class RawLH : FMReader("RawLH", "https://lovehug.net", "ja") {
|
||||||
override fun popularMangaSelector() = "#history .thumb-item-flow"
|
override val chapterUrlSelector = ""
|
||||||
override fun popularMangaFromElement(element: Element): SManga {
|
override fun pageListParse(document: Document): List<Page> = base64PageListParse(document)
|
||||||
return SManga.create().apply {
|
|
||||||
element.select(".series-title a").let {
|
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
|
||||||
title = it.text()
|
|
||||||
}
|
|
||||||
thumbnail_url = element.select(".thumb-wrapper .img-in-ratio").imgAttr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun popularMangaNextPageSelector() = ".pagination a:contains(»):not(.disabled)"
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga {
|
|
||||||
val infoElement = document.select("div.row").first()
|
|
||||||
|
|
||||||
return SManga.create().apply {
|
|
||||||
author = infoElement.select("li a.btn-info").text()
|
|
||||||
genre = infoElement.select("li a.btn-danger").joinToString { it.text() }
|
|
||||||
status = parseStatus(infoElement.select("li a.btn-success").first()?.text())
|
|
||||||
description = document.select(".summary-content p").text().trim()
|
|
||||||
thumbnail_url = infoElement.select(".thumbnail").imgAttr()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun chapterListSelector() = ".list-chapters a"
|
|
||||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
|
||||||
return SChapter.create().apply {
|
|
||||||
element.let {
|
|
||||||
setUrlWithoutDomain(it.attr("abs:href"))
|
|
||||||
name = element.attr("title")
|
|
||||||
}
|
|
||||||
date_upload = element.select(".chapter-time").let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
override fun pageListParse(document: Document): List<Page> = base64PageListParse2(document)
|
|
||||||
protected fun base64PageListParse2(document: Document): List<Page> {
|
|
||||||
fun Element.decoded(): String {
|
|
||||||
val attr = "src"
|
|
||||||
return if (!this.attr(attr).contains(".")) {
|
|
||||||
Base64.decode(this.attr(attr), Base64.DEFAULT).toString(Charset.defaultCharset())
|
|
||||||
} else {
|
|
||||||
this.attr("abs:$attr")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return document.select("img.chapter-img").mapIndexed { i, img ->
|
|
||||||
Page(i, document.location(), img.decoded())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Referer needs to be chapter URL
|
// Referer needs to be chapter URL
|
||||||
override fun imageRequest(page: Page): Request = GET(page.imageUrl!!, headersBuilder().set("Referer", page.url).build())
|
override fun imageRequest(page: Page): Request = GET(page.imageUrl!!, headersBuilder().set("Referer", page.url).build())
|
||||||
}
|
}
|
||||||
|
@ -282,7 +235,7 @@ class EpikManga : FMReader("Epik Manga", "https://www.epikmanga.com", "tr") {
|
||||||
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/seri-listesi?sorting=lastUpdate&sorting-type=DESC&Sayfa=$page", headers)
|
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/seri-listesi?sorting=lastUpdate&sorting-type=DESC&Sayfa=$page", headers)
|
||||||
override fun popularMangaNextPageSelector() = "ul.pagination li.active + li:not(.disabled)"
|
override fun popularMangaNextPageSelector() = "ul.pagination li.active + li:not(.disabled)"
|
||||||
|
|
||||||
override val headerSelector = "h4"
|
override val headerSelector = "h4 a"
|
||||||
|
|
||||||
// search wasn't working on source's website
|
// search wasn't working on source's website
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||||
|
|
Loading…
Reference in New Issue