FMReader cleanup (#1633)

This commit is contained in:
Mike 2019-10-15 18:15:20 -04:00 committed by arkon
parent 4b55071ea2
commit 6a928541c5
40 changed files with 0 additions and 1310 deletions

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: LHTranslation'
pkgNameSuffix = 'en.lhtranslation'
extClass = '.LHTranslation'
extVersionCode = 4
libVersion = '1.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,260 +0,0 @@
package eu.kanade.tachiyomi.extension.en.lhtranslation
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.*
class LHTranslation : ParsedHttpSource() {
// Ps. LHTranslation is really similar to rawLH
override val name = "LHTranslation"
override val baseUrl = "https://lhtranslation.net"
override val lang = "en"
override val supportsLatest = true
override fun popularMangaRequest(page: Int): Request =
GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&ungenre=&sort=views&sort_type=DESC", headers)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/manga-list.html?")!!.newBuilder()
.addQueryParameter("name", query)
.addQueryParameter("page", page.toString())
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is Status -> {
val status = arrayOf("", "1", "2")[filter.state]
url.addQueryParameter("m_status", status)
}
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}"
}
url.addQueryParameter("genre", genre)
url.addQueryParameter("ungenre", ungenre)
}
}
}
return GET(url.toString(), headers)
}
override fun latestUpdatesRequest(page: Int): Request =
GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&sort=last_update&sort_type=DESC")
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = mutableListOf<SManga>()
var hasNextPage = true
document.select(popularMangaSelector()).forEach{ mangas.add(popularMangaFromElement(it)) }
// check if there's a next page
document.select(popularMangaNextPageSelector()).first().text().let {
val currentPage = it.substringAfter("Page ").substringBefore(" ")
val lastPage = it.substringAfterLast(" ")
if (currentPage == lastPage) hasNextPage = false
}
return MangasPage(mangas, hasNextPage)
}
override fun latestUpdatesParse(response: Response) = popularMangaParse(response)
override fun searchMangaParse(response: Response) = popularMangaParse(response)
override fun popularMangaSelector() = "div.media"
override fun latestUpdatesSelector() = popularMangaSelector()
override fun searchMangaSelector() = popularMangaSelector()
override fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("h3 > a").first().let {
manga.setUrlWithoutDomain("/" + it.attr("href"))
manga.title = it.text()
}
return manga
}
override fun latestUpdatesFromElement(element: Element): SManga =
popularMangaFromElement(element)
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun popularMangaNextPageSelector() = "div.col-lg-9 button.btn-info"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
val manga = SManga.create()
val infoElement = document.select("div.row").first()
val genres = infoElement.select("ul.manga-info li:nth-child(5) small a")?.map {
it.text()
}
manga.author = infoElement.select("small a.btn.btn-xs.btn-info").first()?.text()
manga.genre = genres?.joinToString(", ")
manga.status = parseStatus(infoElement.select("a.btn.btn-xs.btn-success").first().text())
manga.description = document.select("div.row > p")?.text()?.trim()
val imgUrl = document.select("img.thumbnail").first()?.attr("src")
if (imgUrl!!.startsWith("app/")) {
manga.thumbnail_url = "$baseUrl/$imgUrl"
} else {
manga.thumbnail_url = imgUrl
}
return manga
}
private fun parseStatus(element: String): Int = when {
element.contains("Completed") -> SManga.COMPLETED
element.contains("Ongoing") -> SManga.ONGOING
else -> SManga.UNKNOWN
}
override fun chapterListSelector() = ".list-chapters .list-wrap p"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select(".titleLink a").first()
val timeElement = element.select(".pubDate time").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain("/" + urlElement.attr("href"))
chapter.name = urlElement.text()
chapter.date_upload = parseChapterDate(timeElement.text())
return chapter
}
private fun parseChapterDate(date: String): Long {
val value = date.split(' ')[0].toInt()
return when {
"min(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.MINUTE, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"hour(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"day(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"week(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"month(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"year(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
else -> {
return 0
}
}
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
document.select(".chapter-img").forEach {
val url = it.attr("src")
if (url != "") {
pages.add(Page(pages.size, "", url))
}
}
return pages
}
override fun imageUrlParse(document: Document) = ""
override fun imageRequest(page: Page): Request {
val imgHeader = Headers.Builder().apply {
add("Referer", baseUrl)
}.build()
return GET(page.imageUrl!!, imgHeader)
}
private class TextField(name: String, val key: String) : Filter.Text(name)
private class Status : Filter.Select<String>("Status", arrayOf("Any", "Completed", "Ongoing"))
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres)
private class Genre(name: String, val id: String = name.replace(' ', '+')) : Filter.TriState(name)
// TODO: Country
override fun getFilterList() = FilterList(
TextField("Author", "author"),
TextField("Group", "group"),
Status(),
GenreList(getGenreList())
)
// [...document.querySelectorAll("div.panel-body a")].map((el,i) => `Genre("${el.innerText.trim()}")`).join(',\n')
// on https://lhtranslation.net/search
private fun getGenreList() = listOf(
Genre("Action"),
Genre("18+"),
Genre("Adult"),
Genre("Anime"),
Genre("Comedy"),
Genre("Comic"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender Bender"),
Genre("Harem"),
Genre("Historical"),
Genre("Horror"),
Genre("Josei"),
Genre("Live action"),
Genre("Manhua"),
Genre("Manhwa"),
Genre("Martial Art"),
Genre("Mature"),
Genre("Mecha"),
Genre("Mystery"),
Genre("One shot"),
Genre("Psychological"),
Genre("Romance"),
Genre("School Life"),
Genre("Sci-fi"),
Genre("Seinen"),
Genre("Shoujo"),
Genre("Shojou Ai"),
Genre("Shounen"),
Genre("Shounen Ai"),
Genre("Slice of Life"),
Genre("Smut"),
Genre("Sports"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Adventure"),
Genre("Yaoi")
)
}

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: Manhwa18'
pkgNameSuffix = 'en.manhwa18'
extClass = '.Manhwa18'
extVersionCode = 1
libVersion = '1.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 KiB

View File

@ -1,300 +0,0 @@
package eu.kanade.tachiyomi.extension.en.manhwa18
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.*
class Manhwa18 : ParsedHttpSource() {
override val name = "Manhwa18"
override val baseUrl = "https://manhwa18.com"
override val lang = "en"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun latestUpdatesSelector() = "div.row.top div.media"
override fun latestUpdatesRequest(page: Int) =
GET("$baseUrl/manga-list.html?page=$page&ungenre=raw&sort=last_update&sort_type=DESC")
override fun latestUpdatesFromElement(element: Element): SManga {
val manga = SManga.create()
val item = element.select("h3 a")
manga.setUrlWithoutDomain("/" + item.attr("href"))
manga.title = item.text()
when {
element.select("img").attr("src").contains("file-thumb") ->
manga.thumbnail_url = "http:" + element.select("img").attr("src")
element.select("img").attr("src").contains("app/manga/uploads") ->
manga.thumbnail_url = baseUrl + element.select("img").attr("src")
else -> manga.thumbnail_url = element.select("img").attr("src")
}
return manga
}
override fun latestUpdatesNextPageSelector() = "a:not(.disabled):contains(»)"
override fun popularMangaRequest(page: Int) =
GET("$baseUrl/manga-list.html?page=$page&ungenre=raw&sort=views&sort_type=DESC")
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 {
val url = HttpUrl.parse("$baseUrl/manga-list.html")!!.newBuilder()
url.addQueryParameter("listType", "pagination")
url.addQueryParameter("page", page.toString())
url.addQueryParameter("name", query)
filters.forEach { filter ->
when (filter) {
is AuthorFilter -> {
url.addQueryParameter("author", filter.state)
}
is StatusFilter -> {
if(filter.state != 0) {
url.addQueryParameter("m_status", filter.toUriPart())
}
}
is SortBy -> {
url.addQueryParameter("sort", when {
filter.state?.index == 0 -> "name"
filter.state?.index == 1 -> "views"
else -> "last_update"
})
if (filter.state?.ascending == true)
url.addQueryParameter("sort_type", "ASC")
}
is GenreFilter -> {
val genreToExclude = mutableListOf<String>()
val genreToInclude = mutableListOf<String>()
filter.state.forEach { content ->
if (content.isExcluded())
genreToExclude.add(content.name)
else if (content.isIncluded())
genreToInclude.add(content.name)
}
if (genreToExclude.isNotEmpty()) {
genreToExclude.add("raw")
url.addQueryParameter("ungenre", genreToExclude
.joinToString(","))
} else url.addQueryParameter("ungenre", "raw")
if (genreToInclude.isNotEmpty()) {
url.addQueryParameter("genre", genreToInclude
.joinToString(","))
}
}
is TypeFilter -> {
if(filter.state != 0) {
url.addQueryParameter("genre", filter.toUriPart())
}
}
}
}
return GET(url.build().toString(), headers)
}
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("ul.manga-info")
val manga = SManga.create()
val status = infoElement.select("b:contains(status) + a").text()
val genres = mutableListOf<String>()
infoElement.select("b:contains(genre) + small a").forEach { element ->
val genre = element.text()
genres.add(genre)
}
val authors = mutableListOf<String>()
infoElement.select("b:contains(author) + small a").forEach { element ->
val author = element.text()
authors.add(author)
}
manga.title = infoElement.select("h1").text()
manga.author = authors.joinToString(", ")
manga.artist = authors.joinToString(", ")
manga.status = parseStatus(status)
manga.genre = genres.joinToString(", ")
manga.description = document.select("div.row:contains(description)").text()
.substringAfter("Description ")
when {
document.select("img.thumbnail").attr("src").contains("file-thumb") ->
manga.thumbnail_url = "http:" + document.select("img.thumbnail").attr("src")
document.select("img.thumbnail").attr("src").contains("app/manga/uploads") ->
manga.thumbnail_url = baseUrl + document.select("img.thumbnail").attr("src")
else -> manga.thumbnail_url = document.select("img.thumbnail").attr("src")
}
return manga
}
private fun parseStatus(status: String?) = when {
status == null -> SManga.UNKNOWN
status.contains("On going") -> SManga.ONGOING
status.contains("Completed") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
override fun chapterListRequest(manga: SManga): Request {
if (manga.url.startsWith("http")) {
return GET(manga.url, headers)
}
return super.chapterListRequest(manga)
}
override fun chapterListSelector() = "table tr"
override fun chapterFromElement(element: Element): SChapter {
val chapter = SChapter.create()
val timeElement = element.select("time").first()
chapter.setUrlWithoutDomain("/" + element.select("a.chapter").attr("href"))
chapter.name = element.select("a.chapter").text()
chapter.date_upload = parseChapterDate(timeElement.text())
return chapter
}
private fun parseChapterDate(date: String): Long {
val value = date.split(' ')[0].toInt()
return when {
"minutes" in date -> Calendar.getInstance().apply {
add(Calendar.MINUTE, value * -1)
}.timeInMillis
"hours" in date -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1)
}.timeInMillis
"days" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1)
}.timeInMillis
"weeks" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1)
}.timeInMillis
"months" in date -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1)
}.timeInMillis
"years" in date -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1)
}.timeInMillis
else -> {
return 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> {
val pages = mutableListOf<Page>()
document.select("img.chapter-img").forEach {
val img = if (!it.attr("src").contains("app/manga/uploads"))
it.attr("src")
else
"$baseUrl/" + it.attr("src")
pages.add(Page(pages.size, "", img))
}
return pages
}
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not used")
private class AuthorFilter : Filter.Text("Author(s)")
private class StatusFilter : UriPartFilter("Status", arrayOf(
Pair("Any", ""),
Pair("Completed", "1"),
Pair("On going", "2"),
Pair("Drop", "3")
))
private class SortBy : Filter.Sort("Sorted By", arrayOf("A-Z", "Most vỉews", "Last updated"),
Selection(1, false))
private class GenreFilter(genres: List<Tag>) : Filter.Group<Tag>("Genres", genres)
override fun getFilterList() = FilterList(
AuthorFilter(),
StatusFilter(),
TypeFilter(),
SortBy(),
GenreFilter(getGenreList())
)
private fun getGenreList() = listOf(
Tag("Action"),
Tag("Anime"),
Tag("Comedy"),
Tag("Comic"),
Tag("Doujinshi"),
Tag("Drama"),
Tag("Ecchi"),
Tag("Fantasy"),
Tag("Gender Bender"),
Tag("Harem"),
Tag("Historical"),
Tag("Horror"),
Tag("Josei"),
Tag("Manhua"),
Tag("Martial Art"),
Tag("Mature"),
Tag("Mecha"),
Tag("Mystery"),
Tag("One shot"),
Tag("Psychological"),
Tag("Romance"),
Tag("School Life"),
Tag("Sci-fi"),
Tag("Seinen"),
Tag("Shoujo"),
Tag("Shojou Ai"),
Tag("Shounen"),
Tag("Shounen Ai"),
Tag("Slice of Life"),
Tag("Smut"),
Tag("Sports"),
Tag("Supernatural"),
Tag("Tragedy"),
Tag("Adventure"),
Tag("Yaoi")
)
private class TypeFilter : UriPartFilter("Types", arrayOf(
Pair("<select>", ""),
Pair("Adult 18", "adult"),
Pair("Manhwa", "manhwa"),
Pair("Hentai", "hentai")
))
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
}
private class Tag(name: String) : Filter.TriState(name)
}

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: RawQQ'
pkgNameSuffix = 'ja.rawqq'
extClass = '.Rawqq'
extVersionCode = 4
libVersion = '1.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 KiB

View File

@ -1,242 +0,0 @@
package eu.kanade.tachiyomi.extension.ja.rawqq
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.*
class Rawqq : ParsedHttpSource() {
override val name = "RawQQ"
override val baseUrl = "http://rawqq.com"
override val lang = "ja"
override val supportsLatest = true
override fun popularMangaRequest(page: Int): Request =
GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&ungenre=&sort=views&sort_type=DESC", headers)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/manga-list.html?")!!.newBuilder().addQueryParameter("name", query)
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is Status -> {
val status = arrayOf("", "1", "2")[filter.state]
url.addQueryParameter("m_status", status)
}
is TextField -> url.addQueryParameter(filter.key, filter.state)
is GenreList -> {
var genre = mutableListOf<String>()
var ungenre = mutableListOf<String>()
filter.state.forEach {it ->
if (it.isIncluded()) genre.add(it.name)
if (it.isExcluded()) ungenre.add(it.name)
}
url.addQueryParameter("genre", genre.joinToString())
url.addQueryParameter("ungenre", ungenre.joinToString())
}
}
}
return GET(url.toString(), headers)
}
override fun latestUpdatesRequest(page: Int): Request =
GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&sort=last_update&sort_type=DESC")
override fun popularMangaSelector() = "div.media"
override fun latestUpdatesSelector() = popularMangaSelector()
override fun searchMangaSelector() = popularMangaSelector()
override fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("h3 > a").first().let {
manga.setUrlWithoutDomain("/" + it.attr("href"))
manga.title = it.text()
}
return manga
}
override fun latestUpdatesFromElement(element: Element): SManga =
popularMangaFromElement(element)
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun popularMangaNextPageSelector() = "a:contains(»)"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
val manga = SManga.create()
val infoElement = document.select("div.row").first()
manga.author = infoElement.select("small a.btn.btn-xs.btn-info").first()?.text()
manga.status = parseStatus(infoElement.select("a.btn.btn-xs.btn-success").first().text())
manga.description = document.select("div.content").first()?.text()
val imgUrl = document.select("img.thumbnail").first()?.attr("src")
if (imgUrl!!.startsWith("app/")) {
manga.thumbnail_url = "$baseUrl/$imgUrl"
} else {
manga.thumbnail_url = imgUrl
}
var genres = mutableListOf<String>()
infoElement.select("div.row small a.btn.btn-xs.btn-danger")?.forEach { it -> genres.add(it.text())}
manga.genre = genres.joinToString(", ")
return manga
}
private fun parseStatus(element: String): Int = when {
element.contains("Completed") -> SManga.COMPLETED
element.contains("Ongoing") -> SManga.ONGOING
else -> SManga.UNKNOWN
}
//override fun chapterListSelector() = " table.table.table-hover tbody tr"
override fun chapterListSelector() = " div#list-chapters.list-wrap p"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("span.title a").first()
val timeElement = element.select("span.publishedDate time").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain("/" + urlElement.attr("href"))
chapter.name = urlElement.text()
chapter.date_upload = parseChapterDate(timeElement.text())
return chapter
}
private fun parseChapterDate(date: String): Long {
val value = date.split(' ')[0].toInt()
return when {
"hour(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"day(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"week(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"month(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"year(s) ago" in date -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
else -> {
return 0
}
}
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
document.select("img.chapter-img").forEach {
val url = it.attr("src")
if (url != "") {
pages.add(Page(pages.size, "", url))
}
}
return pages
}
override fun imageUrlParse(document: Document) = ""
override fun imageRequest(page: Page): Request {
if (page.imageUrl!!.contains("lhscanlation.club")) {
val imgHeader = Headers.Builder().apply {
add("Referer", "https://lhscan.net")
}.build()
return GET(page.imageUrl!!, imgHeader)
}
return GET(page.imageUrl!!)
}
private class TextField(name: String, val key: String) : Filter.Text(name)
private class Status : Filter.Select<String>("Status", arrayOf("Any", "Completed", "Ongoing"))
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres)
private class Genre(name: String, val id: String = name.replace(' ', '+')) : Filter.TriState(name)
override fun getFilterList() = FilterList(
TextField("Author", "author"),
TextField("Group", "group"),
Status(),
GenreList(getGenreList())
)
private fun getGenreList() = listOf(
Genre("4-Koma"),
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
Genre("Isekai"),
Genre("Comedy"),
Genre("Comic"),
Genre("Cooking"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender Bender"),
Genre("Harem"),
Genre("Historical"),
Genre("Horror"),
Genre("Josei"),
Genre("Lolicon"),
Genre("Manga"),
Genre("Manhua"),
Genre("Manhwa"),
Genre("Martial Art"),
Genre("Mature"),
Genre("Mecha"),
Genre("Medical"),
Genre("Music"),
Genre("Mystery"),
Genre("One shot"),
Genre("Psychological"),
Genre("Romance"),
Genre("School Life"),
Genre("Sci-fi"),
Genre("Seinen"),
Genre("Shoujo"),
Genre("Shojou Ai"),
Genre("Shounen"),
Genre("Shounen Ai"),
Genre("Slice of Life"),
Genre("Smut"),
Genre("Sports"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Webtoon"),
Genre("Yaoi"),
Genre("Yuri")
)
}

View File

@ -1,12 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: RawLH'
pkgNameSuffix = 'ja.rawlh'
extClass = '.Rawlh'
extVersionCode = 11
libVersion = '1.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@ -1,242 +0,0 @@
package eu.kanade.tachiyomi.extension.ja.rawlh
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.Request
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import java.util.*
class Rawlh : ParsedHttpSource() {
override val name = "RawLH"
override val baseUrl = "http://lhscan.net"
override val lang = "ja"
override val supportsLatest = true
override fun popularMangaRequest(page: Int): Request =
GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&ungenre=&sort=views&sort_type=DESC", headers)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/manga-list.html?")!!.newBuilder().addQueryParameter("name", query)
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is Status -> {
val status = arrayOf("", "1", "2")[filter.state]
url.addQueryParameter("m_status", status)
}
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}"
}
url.addQueryParameter("genre", genre)
url.addQueryParameter("ungenre", ungenre)
}
}
}
return GET(url.toString(), headers)
}
override fun latestUpdatesRequest(page: Int): Request =
GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&m_status=&name=&genre=&sort=last_update&sort_type=DESC")
override fun popularMangaSelector() = "div.media"
override fun latestUpdatesSelector() = popularMangaSelector()
override fun searchMangaSelector() = popularMangaSelector()
override fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("h3 > a").first().let {
manga.setUrlWithoutDomain("/" + it.attr("href"))
manga.title = it.text()
}
return manga
}
override fun latestUpdatesFromElement(element: Element): SManga =
popularMangaFromElement(element)
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun popularMangaNextPageSelector() = "a:contains(»)"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
val manga = SManga.create()
val infoElement = document.select("div.row").first()
val genres = mutableListOf<String>()
infoElement.select("li:contains(genre) a").forEach { element ->
val genre = element.text()
genres.add(genre)
}
manga.author = infoElement.select("li:contains(author) a").text()
manga.genre = genres.joinToString(", ")
manga.status = parseStatus(infoElement.select("li:contains(status) a").first().text())
manga.description = document.select("div.row:contains(description) > p").text()
val imgUrl = document.select("img.thumbnail").first()?.attr("src")
if (imgUrl!!.startsWith("app/")) {
manga.thumbnail_url = "$baseUrl/$imgUrl"
} else {
manga.thumbnail_url = imgUrl
}
return manga
}
private fun parseStatus(element: String): Int = when {
element.contains("Completed") -> SManga.COMPLETED
element.contains("On Going") -> SManga.ONGOING
else -> SManga.UNKNOWN
}
override fun chapterListSelector() = " table.table.table-hover tbody tr"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("td a").first()
val timeElement = element.select("td time").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain("/" + urlElement.attr("href"))
chapter.name = urlElement.text()
chapter.date_upload = parseChapterDate(timeElement.text())
return chapter
}
private fun parseChapterDate(date: String): Long {
val value = date.split(' ')[0].toInt()
return when {
"hours ago" in date -> Calendar.getInstance().apply {
add(Calendar.HOUR_OF_DAY, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"days ago" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"weeks ago" in date -> Calendar.getInstance().apply {
add(Calendar.DATE, value * 7 * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"months ago" in date -> Calendar.getInstance().apply {
add(Calendar.MONTH, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
"years ago" in date -> Calendar.getInstance().apply {
add(Calendar.YEAR, value * -1)
set(Calendar.SECOND, 0)
set(Calendar.MILLISECOND, 0)
}.timeInMillis
else -> {
return 0
}
}
}
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
document.select("img.chapter-img").forEach {
val dataSrc = it.attr("data-src")
if (dataSrc != "") {
pages.add(Page(pages.size, "", dataSrc))
}else{
val src = it.attr("src")
pages.add(Page(pages.size, "", src))
}
}
return pages
}
override fun imageUrlParse(document: Document) = ""
override fun imageRequest(page: Page): Request {
val imgHeader = Headers.Builder().apply {
add("Referer", baseUrl)
}.build()
return GET(page.imageUrl!!, imgHeader)
}
private class TextField(name: String, val key: String) : Filter.Text(name)
private class Status : Filter.Select<String>("Status", arrayOf("Any", "Completed", "Ongoing"))
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Genre", genres)
private class Genre(name: String) : Filter.TriState(name)
// TODO: Country
override fun getFilterList() = FilterList(
TextField("Author", "author"),
TextField("Group", "group"),
Status(),
GenreList(getGenreList())
)
// [...document.querySelectorAll("div.panel-body a")].map((el,i) => `Genre("${el.innerText.trim()}")`).join(',\n')
// on https://lhscan.net/search
private fun getGenreList() = listOf(
Genre("4-Koma"),
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
Genre("Isekai"),
Genre("Comedy"),
Genre("Comic"),
Genre("Cooking"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender Bender"),
Genre("Harem"),
Genre("Historical"),
Genre("Horror"),
Genre("Josei"),
Genre("Lolicon"),
Genre("Manga"),
Genre("Manhua"),
Genre("Manhwa"),
Genre("Martial Art"),
Genre("Mature"),
Genre("Mecha"),
Genre("Medical"),
Genre("Music"),
Genre("Mystery"),
Genre("One shot"),
Genre("Psychological"),
Genre("Romance"),
Genre("School Life"),
Genre("Sci-fi"),
Genre("Seinen"),
Genre("Shoujo"),
Genre("Shojou Ai"),
Genre("Shounen"),
Genre("Shounen Ai"),
Genre("Slice of Life"),
Genre("Smut"),
Genre("Sports"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Webtoon"),
Genre("Yaoi"),
Genre("Yuri")
)
}

View File

@ -1,16 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: TruyenTranhLH'
pkgNameSuffix = 'vi.truyentranhlh'
extClass = '.TruyenTranhLH'
extVersionCode = 7
libVersion = '1.2'
}
dependencies {
compileOnly 'com.google.code.gson:gson:2.8.2'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@ -1,202 +0,0 @@
package eu.kanade.tachiyomi.extension.vi.truyentranhlh
import com.google.gson.JsonElement
import com.google.gson.JsonParser
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.HttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.helper.StringUtil
import org.jsoup.nodes.Element
import java.util.*
class TruyenTranhLH : HttpSource() {
override val name = "TruyenTranhLH"
override val baseUrl = "https://truyentranhlh.net"
override val lang = "vi"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
fun popularMangaSelector() = "div.media-body > h3"
fun latestUpdatesSelector() = popularMangaSelector()
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&name=&genre=&sort=views&sort_type=DESC", headers)
}
override fun popularMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(popularMangaSelector()).map { element ->
popularMangaFromElement(element)
}
val hasNextPage = popularMangaNextPageSelector().let { selector ->
document.select(selector).first()
} != null
return MangasPage(mangas, hasNextPage)
}
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/manga-list.html?listType=pagination&page=$page&artist=&author=&group=&name=&genre=&sort=last_update&sort_type=DESC", headers)
}
override fun latestUpdatesParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select(latestUpdatesSelector()).map { element ->
latestUpdatesFromElement(element)
}
val hasNextPage = latestUpdatesNextPageSelector().let { selector ->
document.select(selector).first()
} != null
return MangasPage(mangas, hasNextPage)
}
fun popularMangaFromElement(element: Element): SManga {
val manga = SManga.create()
element.select("a").first().let {
manga.setUrlWithoutDomain("/" + it.attr("href"))
manga.title = it.text()
}
return manga
}
fun latestUpdatesFromElement(element: Element): SManga {
return popularMangaFromElement(element)
}
fun popularMangaNextPageSelector() = "i.glyphicon.glyphicon-chevron-right"
fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
return GET("$baseUrl/app/manga/controllers/search.single.php?q=" + query, headers)
}
override fun searchMangaParse(response: Response): MangasPage {
var jsonData = response.asJsoup().text()
jsonData = jsonData.substring(1, jsonData.length - 1)
val elementArray = JsonParser().parse(jsonData)
.asJsonObject
.getAsJsonArray("data")
val mangas = elementArray.map { element ->
searchMangaFromElement(element)
}
return MangasPage(mangas, false)
}
fun searchMangaFromElement(element: JsonElement): SManga {
val result = element.asJsonObject
val manga = SManga.create()
manga.title = result.get("primary").toString().replace("\"", "")
manga.url = "/" + result.get("onclick").toString().replace("\"window.location='", "").replace("'\"", "")
return manga
}
override fun mangaDetailsParse(response: Response): SManga {
val document = response.asJsoup()
val infoElement = document.select("ul.manga-info").first()
val manga = SManga.create()
manga.author = infoElement.select("a.btn.btn-xs.btn-info").first()?.text()
manga.genre = infoElement.select("a.btn.btn-xs.btn-danger").joinToString { it.text() }
manga.description = document.select("h3:contains(Sơ lược) + p").text()
manga.status = infoElement.select("a.btn.btn-xs.btn-success").last()?.text().orEmpty().let { parseStatus(it) }
val imgUrl = document.select("img.thumbnail").first()?.attr("src")
if (imgUrl!!.startsWith("/app/")) {
manga.thumbnail_url = "$baseUrl/$imgUrl"
} else {
manga.thumbnail_url = imgUrl
}
return manga
}
fun parseStatus(status: String) = when {
status.contains("Chưa hoàn thành") -> SManga.ONGOING
status.contains("Đã hoàn thành") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup()
return document.select(chapterListSelector()).map { chapterFromElement(it) }
}
fun chapterListSelector() = "table.table.table-hover > tbody > tr"
fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("td > a").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain(cleanUrl(urlElement.attr("href")))
chapter.name = urlElement.select("b").text()
chapter.date_upload = element.select("td > i > time").first()?.text()?.let { parseChapterDate(it) } ?: 0
return chapter
}
fun cleanUrl(url: String): String {
val index = url.lastIndexOf(baseUrl)
if (index != -1) return url.substring(index)
return "/" + url
}
private fun parseChapterDate(date: String): Long {
val dateWords: List<String> = date.split(" ")
if (dateWords.size == 3) {
val timeAgo = Integer.parseInt(dateWords[0])
val dates: Calendar = Calendar.getInstance()
if (dateWords[1].contains("phút")) {
dates.add(Calendar.MINUTE, -timeAgo)
} else if (dateWords[1].contains("giờ")) {
dates.add(Calendar.HOUR_OF_DAY, -timeAgo)
} else if (dateWords[1].contains("ngày")) {
dates.add(Calendar.DAY_OF_YEAR, -timeAgo)
} else if (dateWords[1].contains("tuần")) {
dates.add(Calendar.WEEK_OF_YEAR, -timeAgo)
} else if (dateWords[1].contains("tháng")) {
dates.add(Calendar.MONTH, -timeAgo)
} else if (dateWords[1].contains("năm")) {
dates.add(Calendar.YEAR, -timeAgo)
}
return dates.timeInMillis
}
return 0L
}
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
override fun pageListParse(response: Response): List<Page> {
val document = response.asJsoup()
val pages = mutableListOf<Page>()
document.select("div.chapter-content > img").forEach {
pages.add(Page(pages.size, "", it.attr("src")))
}
return pages
}
override fun imageRequest(page: Page): Request {
val imgHeader = Headers.Builder().apply {
add("Referer", baseUrl)
}.build()
return GET(page.imageUrl!!, imgHeader)
}
override fun imageUrlParse(response: Response): String {
return ""
}
}