Init2
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 9.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
BIN
multisrc/overrides/fmreader/default/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 5.8 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 14 KiB |
BIN
multisrc/overrides/fmreader/epikmanga/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
56
multisrc/overrides/fmreader/epikmanga/src/EpikManga.kt
Normal file
@@ -0,0 +1,56 @@
|
||||
package eu.kanade.tachiyomi.extension.tr.epikmanga
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import rx.Observable
|
||||
|
||||
class EpikManga : FMReader("Epik Manga", "https://www.epikmanga.com", "tr") {
|
||||
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/seri-listesi?sorting=views&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 val headerSelector = "h4 a"
|
||||
|
||||
// search wasn't working on source's website
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return client.newCall(searchMangaRequest(page, query, filters))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
searchMangaParse(response, query)
|
||||
}
|
||||
}
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = GET("$baseUrl/seri-listesi?type=text", headers)
|
||||
private fun searchMangaParse(response: Response, query: String): MangasPage {
|
||||
val mangas = response.asJsoup().select("div.char.col-lg-4 a").toList()
|
||||
.filter { it.text().contains(query, ignoreCase = true) }
|
||||
.map {
|
||||
SManga.create().apply {
|
||||
setUrlWithoutDomain(it.attr("href"))
|
||||
title = it.text()
|
||||
}
|
||||
}
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val infoElement = document.select("div.col-md-9 div.row").first()!!
|
||||
|
||||
return SManga.create().apply {
|
||||
status = parseStatus(infoElement.select("h4:contains(Durum:)").firstOrNull()?.ownText())
|
||||
author = infoElement.select("h4:contains(Yazar:)").firstOrNull()?.ownText()
|
||||
artist = infoElement.select("h4:contains(Çizer:)").firstOrNull()?.ownText()
|
||||
genre = infoElement.select("h4:contains(Türler:) a").joinToString { it.text() }
|
||||
thumbnail_url = infoElement.select("img.thumbnail").imgAttr()
|
||||
description = document.select("div.col-md-12 p").text()
|
||||
}
|
||||
}
|
||||
override fun chapterListSelector() = "table.table tbody tr"
|
||||
override fun getFilterList(): FilterList = FilterList()
|
||||
}
|
||||
|
After Width: | Height: | Size: 5.2 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 21 KiB |
BIN
multisrc/overrides/fmreader/kisslove/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 111 KiB |
80
multisrc/overrides/fmreader/kisslove/src/KissLove.kt
Normal file
@@ -0,0 +1,80 @@
|
||||
package eu.kanade.tachiyomi.extension.ja.kisslove
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.Calendar
|
||||
|
||||
class KissLove : FMReader("KissLove", "https://klz9.com", "ja") {
|
||||
override fun latestUpdatesRequest(page: Int) =
|
||||
GET("$baseUrl/manga-list.html?page=$page&sort=last_update")
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
val mangaId = MID_URL_REGEX.find(manga.url)
|
||||
?.groupValues?.get(1)
|
||||
?: throw Exception("Could not find manga id")
|
||||
|
||||
val xhrUrl = "$baseUrl/app/manga/controllers/cont.listChapter.php".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("slug", mangaId)
|
||||
.build()
|
||||
|
||||
return GET(xhrUrl, headers)
|
||||
}
|
||||
|
||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
||||
return SChapter.create().apply {
|
||||
element.select(chapterUrlSelector).first()!!.let {
|
||||
setUrlWithoutDomain("$baseUrl/${it.attr("href")}")
|
||||
name = it.attr("title")
|
||||
}
|
||||
|
||||
date_upload = element.select(chapterTimeSelector)
|
||||
.let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChapterDate(date: String): Long {
|
||||
val value = date.split(' ')[dateValueIndex].toInt()
|
||||
val chapterDate = Calendar.getInstance().apply {
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
when (date.split(' ')[dateWordIndex]) {
|
||||
"mins", "minutes" -> chapterDate.add(Calendar.MINUTE, value * -1)
|
||||
"hours" -> chapterDate.add(Calendar.HOUR_OF_DAY, value * -1)
|
||||
"days" -> chapterDate.add(Calendar.DATE, value * -1)
|
||||
"weeks" -> chapterDate.add(Calendar.DATE, value * 7 * -1)
|
||||
"months" -> chapterDate.add(Calendar.MONTH, value * -1)
|
||||
"years" -> chapterDate.add(Calendar.YEAR, value * -1)
|
||||
else -> return 0
|
||||
}
|
||||
|
||||
return chapterDate.timeInMillis
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
val request = super.pageListRequest(chapter)
|
||||
val response = client.newCall(request).execute()
|
||||
val document = response.asJsoup()
|
||||
|
||||
val chapterId = document.selectFirst("#chapter")
|
||||
?.`val`()
|
||||
?: throw Exception("Could not find chapter id")
|
||||
|
||||
val xhrUrl = "$baseUrl/app/manga/controllers/cont.listImg.php".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("cid", chapterId)
|
||||
.build()
|
||||
|
||||
return GET(xhrUrl, headers)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MID_URL_REGEX = "-([^.]+).html".toRegex()
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
BIN
multisrc/overrides/fmreader/manga1000/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
40
multisrc/overrides/fmreader/manga1000/src/Manga1000.kt
Normal file
@@ -0,0 +1,40 @@
|
||||
package eu.kanade.tachiyomi.extension.ja.manga1000
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.Calendar
|
||||
|
||||
class Manga1000 : FMReader("Manga1000", "https://manga1000.top", "ja") {
|
||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
||||
return SChapter.create().apply {
|
||||
element.let {
|
||||
setUrlWithoutDomain(it.attr("abs:href"))
|
||||
name = it.attr("title")
|
||||
}
|
||||
|
||||
date_upload = element.select(chapterTimeSelector)
|
||||
.let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChapterDate(date: String): Long {
|
||||
val value = date.split(' ')[dateValueIndex].toInt()
|
||||
val chapterDate = Calendar.getInstance().apply {
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
when (date.split(' ')[dateWordIndex]) {
|
||||
"mins", "minutes" -> chapterDate.add(Calendar.MINUTE, value * -1)
|
||||
"hours" -> chapterDate.add(Calendar.HOUR_OF_DAY, value * -1)
|
||||
"days" -> chapterDate.add(Calendar.DATE, value * -1)
|
||||
"weeks" -> chapterDate.add(Calendar.DATE, value * 7 * -1)
|
||||
"months" -> chapterDate.add(Calendar.MONTH, value * -1)
|
||||
"years" -> chapterDate.add(Calendar.YEAR, value * -1)
|
||||
else -> return 0
|
||||
}
|
||||
|
||||
return chapterDate.timeInMillis
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 22 KiB |
BIN
multisrc/overrides/fmreader/mangatr/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 180 KiB |
101
multisrc/overrides/fmreader/mangatr/src/MangaTR.kt
Normal file
@@ -0,0 +1,101 @@
|
||||
package eu.kanade.tachiyomi.extension.tr.mangatr
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
|
||||
class MangaTR : FMReader("Manga-TR", "https://manga-tr.com", "tr") {
|
||||
override fun headersBuilder() = Headers.Builder().apply {
|
||||
add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
|
||||
}
|
||||
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>()
|
||||
|
||||
response.asJsoup().select("div.row a[data-toggle]")
|
||||
.filterNot { it.siblingElements().text().contains("Novel") }
|
||||
.map { mangas.add(searchMangaFromElement(it)) }
|
||||
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
manga.setUrlWithoutDomain(element.attr("abs:href"))
|
||||
manga.title = element.text()
|
||||
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val manga = SManga.create()
|
||||
val infoElement: Element = document.select("div#tab1").first()!!
|
||||
|
||||
manga.author = infoElement.select("table + table tr + tr td a").first()?.text()
|
||||
manga.artist = infoElement.select("table + table tr + tr td + td a").first()?.text()
|
||||
manga.genre = infoElement.select("div#tab1 table + table tr + tr td + td + td").text()
|
||||
manga.description = infoElement.select("div.well").text().trim()
|
||||
manga.thumbnail_url = document.select("img.thumbnail").attr("abs:src")
|
||||
manga.status = document.select("table.table:nth-child(2) > tbody:nth-child(1) > tr:nth-child(2) td").let {
|
||||
val translationStatus = it[it.size - 2].text()
|
||||
parseStatus(translationStatus)
|
||||
}
|
||||
return manga
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "tr.table-bordered"
|
||||
override val chapterUrlSelector = "td[align=left] > a"
|
||||
override val chapterTimeSelector = "td[align=right]"
|
||||
private val chapterListHeaders = headers.newBuilder().add("X-Requested-With", "XMLHttpRequest").build()
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
val requestUrl = "$baseUrl/cek/fetch_pages_manga.php?manga_cek=${manga.url.substringAfter("manga-").substringBefore(".")}"
|
||||
return client.newCall(GET(requestUrl, chapterListHeaders))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
chapterListParse(response, requestUrl)
|
||||
}
|
||||
}
|
||||
|
||||
private fun chapterListParse(response: Response, requestUrl: String): List<SChapter> {
|
||||
val chapters = mutableListOf<SChapter>()
|
||||
var document = response.asJsoup()
|
||||
var moreChapters = true
|
||||
var nextPage = 2
|
||||
|
||||
// chapters are paginated
|
||||
while (moreChapters) {
|
||||
document.select(chapterListSelector()).map { chapters.add(chapterFromElement(it)) }
|
||||
if (document.select("a[data-page=$nextPage]").isNotEmpty()) {
|
||||
val body = FormBody.Builder()
|
||||
.add("page", nextPage.toString())
|
||||
.build()
|
||||
document = client.newCall(POST(requestUrl, chapterListHeaders, body)).execute().asJsoup()
|
||||
nextPage++
|
||||
} else {
|
||||
moreChapters = false
|
||||
}
|
||||
}
|
||||
return chapters
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request = GET("$baseUrl/${chapter.url.substringAfter("cek/")}", headers)
|
||||
}
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 31 KiB |
BIN
multisrc/overrides/fmreader/manhwa18/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
90
multisrc/overrides/fmreader/manhwa18/src/Manhwa18.kt
Normal file
@@ -0,0 +1,90 @@
|
||||
package eu.kanade.tachiyomi.extension.en.manhwa18
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Manhwa18 : FMReader("Manhwa18", "https://manhwa18.com", "en") {
|
||||
override val requestPath = "tim-kiem"
|
||||
|
||||
override val popularSort = "sort=top"
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val document = response.asJsoup()
|
||||
|
||||
val mangas = document.select(popularMangaSelector()).map { popularMangaFromElement(it) }
|
||||
|
||||
return MangasPage(mangas, document.select(".pagination_wrap .disabled").text() != "Bottom")
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/$requestPath?".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("q", query)
|
||||
.addQueryParameter("page", page.toString())
|
||||
return GET(url.toString(), headers)
|
||||
}
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
GET("$baseUrl/$requestPath?listType=pagination&page=$page&sort=update&sort_type=DESC", headers)
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
return SManga.create().apply {
|
||||
title = document.select(".series-name").text()
|
||||
thumbnail_url = document.select("meta[property='og:image']").attr("abs:content")
|
||||
|
||||
document.select(".series-information")?.let { info ->
|
||||
author = info.select(".info-name:contains(Author:) + .info-value").text()
|
||||
genre = info.select(".info-name:contains(Genre:) + .info-value > a")
|
||||
.joinToString { it.text().trim() }
|
||||
|
||||
description = document.select(".summary-content").text().trim()
|
||||
info.select(".info-name:contains(Other name:) + .info-value")
|
||||
.firstOrNull()?.text()?.let {
|
||||
val altName = removeGenericWords(it)
|
||||
description = when (title.lowercase(Locale.US)) {
|
||||
altName.lowercase(Locale.US) -> description
|
||||
else -> description + "\n\n$altName"
|
||||
}
|
||||
}
|
||||
status =
|
||||
parseStatus(info.select(".info-name:contains(Status:) + .info-value").text())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeGenericWords(name: String): String {
|
||||
val excludeList = listOf("manhwa", "engsub")
|
||||
return name.split(' ').filterNot { word ->
|
||||
word.lowercase(Locale.US) in excludeList
|
||||
}.joinToString(" ")
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val document = response.asJsoup()
|
||||
|
||||
return document.select(".list-chapters > a").map { element ->
|
||||
SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.attr("abs:href"))
|
||||
name = element.attr("title")
|
||||
date_upload =
|
||||
SimpleDateFormat("dd/MM/yyyy", Locale.US).parse(
|
||||
element.select(".chapter-time").text().substringAfter(" - "),
|
||||
)?.time ?: 0L
|
||||
chapter_number = element.attr("time").substringAfterLast(' ').toFloatOrNull() ?: -1f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val pageListImageSelector = "#chapter-content > img"
|
||||
|
||||
override fun getFilterList() = FilterList()
|
||||
}
|
||||
|
After Width: | Height: | Size: 6.5 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 31 KiB |
BIN
multisrc/overrides/fmreader/manhwa18net/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 212 KiB |
@@ -0,0 +1,77 @@
|
||||
package eu.kanade.tachiyomi.extension.all.manhwa18net
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.Source
|
||||
import eu.kanade.tachiyomi.source.SourceFactory
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class Manhwa18NetFactory : SourceFactory {
|
||||
override fun createSources(): List<Source> = listOf(
|
||||
Manhwa18Net(),
|
||||
Manhwa18NetRaw(),
|
||||
)
|
||||
}
|
||||
|
||||
class Manhwa18Net : FMReader("Manhwa18.net", "https://manhwa18.net", "en") {
|
||||
override val requestPath = "genre/manhwa"
|
||||
override val popularSort = "sort=top"
|
||||
override val pageListImageSelector = "div#chapter-content > img"
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
GET(
|
||||
"$baseUrl/$requestPath?listType=pagination&page=$page&sort=update&sort_type=DESC",
|
||||
headers,
|
||||
)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val noRawsUrl = super.searchMangaRequest(page, query, filters).url.newBuilder().toString()
|
||||
return GET(noRawsUrl, headers)
|
||||
}
|
||||
|
||||
override fun getGenreList() = getAdultGenreList()
|
||||
|
||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
||||
return SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.attr("abs:href"))
|
||||
name = element.attr("title")
|
||||
date_upload = parseAbsoluteDate(
|
||||
element.select(chapterTimeSelector).text().substringAfter(" - "),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Manhwa18NetRaw : FMReader("Manhwa18.net", "https://manhwa18.net", "ko") {
|
||||
override val requestPath = "genre/raw"
|
||||
override val popularSort = "sort=top"
|
||||
override val pageListImageSelector = "div#chapter-content > img"
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
GET(
|
||||
"$baseUrl/$requestPath?listType=pagination&page=$page&sort=update&sort_type=DESC",
|
||||
headers,
|
||||
)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val onlyRawsUrl = super.searchMangaRequest(page, query, filters).url.newBuilder().toString()
|
||||
return GET(onlyRawsUrl, headers)
|
||||
}
|
||||
|
||||
override fun getFilterList() = FilterList(
|
||||
super.getFilterList().filterNot { it == GenreList(getGenreList()) },
|
||||
)
|
||||
|
||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
||||
return SChapter.create().apply {
|
||||
setUrlWithoutDomain(element.attr("abs:href"))
|
||||
name = element.attr("title")
|
||||
date_upload = parseAbsoluteDate(
|
||||
element.select(chapterTimeSelector).text().substringAfter(" - "),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 6.1 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 8.3 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 22 KiB |
BIN
multisrc/overrides/fmreader/rawlh/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
44
multisrc/overrides/fmreader/rawlh/src/WeLoveManga.kt
Normal file
@@ -0,0 +1,44 @@
|
||||
package eu.kanade.tachiyomi.extension.ja.rawlh
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class WeLoveManga : FMReader("WeLoveManga", "https://weloma.art", "ja") {
|
||||
// Formerly "RawLH"
|
||||
override val id = 7595224096258102519
|
||||
|
||||
override val chapterUrlSelector = ""
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
fun Element.decoded(): String {
|
||||
return this.attr("data-src").trimEnd()
|
||||
}
|
||||
|
||||
return document.select(pageListImageSelector).mapIndexed { i, img ->
|
||||
Page(i, document.location(), img.decoded())
|
||||
}
|
||||
}
|
||||
|
||||
// Referer needs to be chapter URL
|
||||
override fun imageRequest(page: Page): Request = GET(page.imageUrl!!, headersBuilder().set("Referer", page.url).build())
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
element.select(headerSelector).let {
|
||||
setUrlWithoutDomain(it.attr("abs:href"))
|
||||
title = it.text()
|
||||
}
|
||||
thumbnail_url = element
|
||||
.select("div.content.img-in-ratio")
|
||||
.first()!!
|
||||
.attr("style")
|
||||
.let { BACKGROUND_IMAGE_REGEX.find(it)?.groups?.get(1)?.value }
|
||||
}
|
||||
|
||||
companion object {
|
||||
val BACKGROUND_IMAGE_REGEX = Regex("""url\(['"]?(.*?)['"]?\)""")
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 3.1 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 6.9 KiB |
|
After Width: | Height: | Size: 9.4 KiB |
BIN
multisrc/overrides/fmreader/saytruyen/res/web_hi_res_512.png
Normal file
|
After Width: | Height: | Size: 59 KiB |
32
multisrc/overrides/fmreader/saytruyen/src/SayTruyen.kt
Normal file
@@ -0,0 +1,32 @@
|
||||
package eu.kanade.tachiyomi.extension.vi.saytruyen
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
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.Response
|
||||
import org.jsoup.nodes.Document
|
||||
|
||||
class SayTruyen : FMReader("Say Truyen", "https://saytruyenvip.com", "vi") {
|
||||
override fun mangaDetailsParse(document: Document): SManga {
|
||||
val info = document.select("div.row").first()!!
|
||||
return SManga.create().apply {
|
||||
author = info.select("div.row li:has(b:contains(Tác giả)) small").text()
|
||||
genre = info.select("div.row li:has(b:contains(Thể loại)) small a").joinToString { it.text() }
|
||||
status = parseStatus(info.select("div.row li:has(b:contains(Tình trạng)) a").text())
|
||||
description = document.select("div.description").text()
|
||||
thumbnail_url = info.select("img.thumbnail").attr("abs:src")
|
||||
}
|
||||
}
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
return response.asJsoup().let { document ->
|
||||
document.select(chapterListSelector()).map {
|
||||
chapterFromElement(it).apply {
|
||||
scanlator = document.select("div.row li:has(b:contains(Nhóm dịch)) small").text()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun pageListParse(document: Document): List<Page> = super.pageListParse(document).onEach { it.imageUrl!!.trim() }
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
package eu.kanade.tachiyomi.extension.ja.welovemangaone
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.fmreader.FMReader
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.Calendar
|
||||
|
||||
class WeLoveMangaOne : FMReader("WeLoveMangaOne", "https://welovemanga.one", "ja") {
|
||||
override fun latestUpdatesRequest(page: Int) =
|
||||
GET("$baseUrl/manga-list.html?page=$page&sort=last_update")
|
||||
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
val mangaId = MID_URL_REGEX.find(manga.url)
|
||||
?.groupValues?.get(1)
|
||||
?: throw Exception("Could not find manga id")
|
||||
|
||||
val xhrUrl = "$baseUrl/app/manga/controllers/cont.Listchapter.php".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("mid", mangaId)
|
||||
.build()
|
||||
|
||||
return GET(xhrUrl, headers)
|
||||
}
|
||||
|
||||
override fun chapterFromElement(element: Element, mangaTitle: String): SChapter {
|
||||
return SChapter.create().apply {
|
||||
element.let {
|
||||
setUrlWithoutDomain(it.attr("abs:href"))
|
||||
name = it.attr("title")
|
||||
}
|
||||
|
||||
date_upload = element.select(chapterTimeSelector)
|
||||
.let { if (it.hasText()) parseChapterDate(it.text()) else 0 }
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseChapterDate(date: String): Long {
|
||||
val value = date.split(' ')[dateValueIndex].toInt()
|
||||
val chapterDate = Calendar.getInstance().apply {
|
||||
set(Calendar.SECOND, 0)
|
||||
set(Calendar.MILLISECOND, 0)
|
||||
}
|
||||
|
||||
when (date.split(' ')[dateWordIndex]) {
|
||||
"mins", "minutes" -> chapterDate.add(Calendar.MINUTE, value * -1)
|
||||
"hours" -> chapterDate.add(Calendar.HOUR_OF_DAY, value * -1)
|
||||
"days" -> chapterDate.add(Calendar.DATE, value * -1)
|
||||
"weeks" -> chapterDate.add(Calendar.DATE, value * 7 * -1)
|
||||
"months" -> chapterDate.add(Calendar.MONTH, value * -1)
|
||||
"years" -> chapterDate.add(Calendar.YEAR, value * -1)
|
||||
else -> return 0
|
||||
}
|
||||
|
||||
return chapterDate.timeInMillis
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
val request = super.pageListRequest(chapter)
|
||||
val response = client.newCall(request).execute()
|
||||
val document = response.asJsoup()
|
||||
|
||||
val chapterId = document.selectFirst("#chapter")
|
||||
?.`val`()
|
||||
?: throw Exception("Could not find chapter id")
|
||||
|
||||
val xhrUrl = "$baseUrl/app/manga/controllers/cont.listImg.php".toHttpUrl().newBuilder()
|
||||
.addQueryParameter("cid", chapterId)
|
||||
.build()
|
||||
|
||||
return GET(xhrUrl, headers)
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MID_URL_REGEX = "(\\d+)/".toRegex()
|
||||
}
|
||||
}
|
||||