Fix: Academyvn (#109)

Add:
- Blogtruyen
- Truyentranhlh
- Iutruyentranh
This commit is contained in:
Nam Nguyễn 2017-10-23 00:18:43 +07:00 committed by inorichi
parent cd392cd52b
commit acacecf4bd
7 changed files with 651 additions and 1 deletions

View File

@ -14,7 +14,7 @@ class Academyvn : ParsedHttpSource() {
override val name = "Academy VN"
override val baseUrl = "http://truyen.academyvn.com"
override val baseUrl = "http://hocvientruyentranh.com"
override val lang = "vi"

View File

@ -0,0 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: BlogTruyen'
pkgNameSuffix = "vi.blogtruyen"
extClass = '.Blogtruyen'
extVersionCode = 1
extVersionSuffix = 1
libVersion = '1.0'
}
apply from: "$rootDir/common.gradle"

View File

@ -0,0 +1,214 @@
package eu.kanade.tachiyomi.source.online.vietnamese
import android.util.Log
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.text.SimpleDateFormat
class Blogtruyen : ParsedHttpSource() {
override val name = "BlogTruyen"
override val baseUrl = "http://blogtruyen.com"
override val lang = "vi"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun popularMangaSelector() = "div.list span.tiptip.fs-12.ellipsis"
override fun latestUpdatesSelector() = popularMangaSelector()
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/ajax/Search/AjaxLoadListManga?key=tatca&orderBy=3&p=$page", headers)
}
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/ajax/Search/AjaxLoadListManga?key=tatca&orderBy=5&p=$page", headers)
}
override 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
}
override fun latestUpdatesFromElement(element: Element): SManga {
return popularMangaFromElement(element)
}
override fun popularMangaNextPageSelector() = "div.paging:last-child:not(.current_page)"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
var temp = "$baseUrl/timkiem/nangcao/1/0"
val genres = mutableListOf<String>()
val genresEx = mutableListOf<String>()
var aut = ""
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is GenreList -> filter.state.forEach {
genre ->
when (genre.state) {
Filter.TriState.STATE_INCLUDE -> genres.add(genre.name.toLowerCase())
Filter.TriState.STATE_EXCLUDE -> genresEx.add(genre.name.toLowerCase())
}
}
is Author -> {
if (!filter.state.isEmpty()) {
aut = filter.state
}
}
}
}
if (genres.isNotEmpty()) temp = temp + "/" + genres.joinToString(",")
else temp = temp + "/-1"
if (genresEx.isNotEmpty()) temp = temp + "/" + genresEx.joinToString(",")
else temp = temp + "/-1"
val url = HttpUrl.parse(temp)!!.newBuilder()
url.addQueryParameter("txt", query)
if (!aut.isEmpty()) url.addQueryParameter("aut", aut)
url.addQueryParameter("p", page.toString())
Log.i("tachiyomi", url.toString())
return GET(url.toString().replace("m.", ""), headers)
}
override fun searchMangaSelector() = "div.list > p:gt(0) > span:eq(0)"
override fun searchMangaFromElement(element: Element): SManga {
return popularMangaFromElement(element)
}
override fun searchMangaNextPageSelector() = "ul.pagination i.glyphicon.glyphicon-step-forward.red"
override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("div.description").first()
val manga = SManga.create()
manga.author = infoElement.select("p:contains(Tác giả) > a").first()?.text()
manga.genre = infoElement.select("p:contains(Thể loại) > span.category > a").text()
manga.description = document.select("div.detail > div.content").text()
manga.status = infoElement.select("p:contains(Trạng thái) > span.color-red").first()?.text().orEmpty().let { parseStatus(it) }
manga.thumbnail_url = document.select("div.thumbnail > img").first()?.attr("src")
return manga
}
fun parseStatus(status: String) = when {
status.contains("Đang tiến hành") -> SManga.ONGOING
status.contains("Đã hoàn thành") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
override fun chapterListSelector() = "div.list-wrap > p"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("span > a").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain(urlElement.attr("href"))
chapter.name = urlElement.attr("title")
chapter.date_upload = element.select("span.publishedDate").first()?.text()?.let {
SimpleDateFormat("dd/MM/yyyy HH:mm").parse(it).time
} ?: 0
return chapter
}
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
var i = 0
document.select("article#content > img").forEach {
pages.add(Page(i++, "", it.attr("src")))
}
return pages
}
override fun imageUrlRequest(page: Page) = GET(page.url)
override fun imageUrlParse(document: Document) = ""
var status = arrayOf("Sao cũng được", "Đang tiến hành", "Đã hoàn thành", "Tạm ngưng")
private class Status : Filter.Select<String>("Status", arrayOf("Sao cũng được", "Đang tiến hành", "Đã hoàn thành", "Tạm ngưng"))
private class Author : Filter.Text("Tác giả")
private class Genre(name: String, val id: Int) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Thể loại", genres)
override fun getFilterList() = FilterList(
Status(),
GenreList(getGenreList()),
Author()
)
private fun getGenreList() = listOf(
Genre("16+", 54),
Genre("18+", 45),
Genre("Action", 1),
Genre("Adult", 2),
Genre("Adventure", 3),
Genre("Anime", 4),
Genre("Comedy", 5),
Genre("Comic", 6),
Genre("Doujinshi", 7),
Genre("Drama", 49),
Genre("Ecchi", 48),
Genre("Even BT", 60),
Genre("Fantasy", 50),
Genre("Game", 61),
Genre("Gender Bender", 51),
Genre("Harem", 12),
Genre("Historical", 13),
Genre("Horror", 14),
Genre("Josei", 15),
Genre("Live Action", 16),
Genre("Magic", 46),
Genre("Manga", 55),
Genre("Manhua", 17),
Genre("Manhwa", 18),
Genre("Martial Arts", 19),
Genre("Mature", 20),
Genre("Mecha", 21),
Genre("Mystery", 22),
Genre("Nấu ăn", 56),
Genre("NTR", 61),
Genre("One shot", 23),
Genre("Psychological", 24),
Genre("Romance", 25),
Genre("School Life", 26),
Genre("Sci-fi", 27),
Genre("Seinen", 28),
Genre("Shoujo", 29),
Genre("Shoujo Ai", 30),
Genre("Shounen", 31),
Genre("Shounen Ai", 32),
Genre("Slice of Life", 33),
Genre("Smut", 34),
Genre("Soft Yaoi", 35),
Genre("Soft Yuri", 36),
Genre("Sports", 37),
Genre("Supernatural", 38),
Genre("Tạp chí truyện tranh", 39),
Genre("Tragedy", 40),
Genre("Trap", 58),
Genre("Trinh thám", 57),
Genre("Truyện scan", 41),
Genre("Video clip", 53),
Genre("VnComic", 42),
Genre("Webtoon", 52),
Genre("Yuri", 59)
)
}

View File

@ -0,0 +1,13 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: IuTruyenTranh'
pkgNameSuffix = "vi.iutruyentranh"
extClass = '.Iutruyentranh'
extVersionCode = 1
extVersionSuffix = 1
libVersion = '1.0'
}
apply from: "$rootDir/common.gradle"

View File

@ -0,0 +1,201 @@
package eu.kanade.tachiyomi.source.online.vietnamese
import android.util.Log
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.text.SimpleDateFormat
/**
* Created by Nam Nguyen on 29/4/2017.
*/
class Iutruyentranh : ParsedHttpSource() {
override val name = "IuTruyenTranh"
override val baseUrl = "http://iutruyentranh.com"
override val lang = "vi"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun popularMangaSelector() = "div.bbottom h4.media-heading"
override fun latestUpdatesSelector() = "h4.media-heading"
override fun popularMangaRequest(page: Int): Request {
return GET("$baseUrl/genre/$page?popular", headers)
}
override fun latestUpdatesRequest(page: Int): Request {
return GET("$baseUrl/latest/$page", headers)
}
override 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
}
override fun latestUpdatesFromElement(element: Element): SManga {
return popularMangaFromElement(element)
}
override fun popularMangaNextPageSelector() = "ul.pagination > li:contains(...»)"
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = HttpUrl.parse("$baseUrl/search/$page?")!!.newBuilder().addQueryParameter("name", query)
val genres = mutableListOf<String>()
val genresEx = mutableListOf<String>()
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
when (filter) {
is Author -> url.addQueryParameter("autart", filter.state)
is GenreList -> filter.state.forEach { genre ->
when (genre.state) {
Filter.TriState.STATE_INCLUDE -> genres.add(genre.name.toLowerCase())
Filter.TriState.STATE_EXCLUDE -> genresEx.add(genre.name.toLowerCase())
}
}
}
}
if (genres.isNotEmpty()) url.addQueryParameter("genres", genres.joinToString(","))
if (genresEx.isNotEmpty()) url.addQueryParameter("genres-exclude", genresEx.joinToString(","))
Log.i("tachiyomi", url.toString())
return GET(url.toString(), headers)
}
override fun searchMangaSelector() = popularMangaSelector()
override fun searchMangaFromElement(element: Element): SManga {
return popularMangaFromElement(element)
}
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
override fun mangaDetailsParse(document: Document): SManga {
val infoElement = document.select("section.manga article").first()
val manga = SManga.create()
manga.author = infoElement.select("span[itemprop=author]").first()?.text()
manga.genre = infoElement.select("a[itemprop=genre]").text()
manga.description = infoElement.select("p.box.box-danger").text()
manga.status = infoElement.select("a[rel=nofollow]").last()?.text().orEmpty().let { parseStatus(it) }
manga.thumbnail_url = infoElement.select("img[class^=thumbnail]").first()?.attr("src")
return manga
}
fun parseStatus(status: String) = when {
status.contains("Đang tiến hành") -> SManga.ONGOING
status.contains("Đã hoàn thành") -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
override fun chapterListSelector() = "ul.list-unstyled > table > tbody > tr"
override fun chapterFromElement(element: Element): SChapter {
val urlElement = element.select("a").first()
val chapter = SChapter.create()
chapter.setUrlWithoutDomain(urlElement.attr("href") + "&load=all")
chapter.name = urlElement.select("b").text()
chapter.date_upload = element.select("td:eq(1)").first()?.text()?.let {
SimpleDateFormat("dd/MM/yyyy").parse(it).time
} ?: 0
return chapter
}
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url, headers)
override fun pageListParse(document: Document): List<Page> {
val pages = mutableListOf<Page>()
var i = 0
document.select("img.img").forEach {
pages.add(Page(i++, "", it.attr("src")))
}
return pages
}
override fun imageUrlRequest(page: Page) = GET(page.url)
override fun imageUrlParse(document: Document) = ""
private class Author : Filter.Text("Tác giả")
private class Genre(name: String) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Thể loại", genres)
override fun getFilterList() = FilterList(
Author(),
GenreList(getGenreList())
)
private fun getGenreList() = listOf(
Genre("Action"),
Genre("Adult"),
Genre("Adventure"),
Genre("Anime"),
Genre("Bishounen"),
Genre("Comedy"),
Genre("Cookin"),
Genre("Demons"),
Genre("Doujinshi"),
Genre("Drama"),
Genre("Ecchi"),
Genre("Fantasy"),
Genre("Gender Bender"),
Genre("Harem"),
Genre("Hentai"),
Genre("Historical"),
Genre("Horror"),
Genre("Josei"),
Genre("Live action"),
Genre("Magic"),
Genre("Manhua"),
Genre("Manhwa"),
Genre("Martial Arts"),
Genre("Mature"),
Genre("Mecha"),
Genre("Medical"),
Genre("Military"),
Genre("Mystery"),
Genre("One shot"),
Genre("Oneshot"),
Genre("Other"),
Genre("Psychological"),
Genre("Romance"),
Genre("School Life"),
Genre("Sci fi"),
Genre("Seinen"),
Genre("Shotacon"),
Genre("Shoujo"),
Genre("Shoujo Ai"),
Genre("Shoujoai"),
Genre("Shounen"),
Genre("Shounen Ai"),
Genre("Shounenai"),
Genre("Slice of Life"),
Genre("Smut"),
Genre("Sports"),
Genre("Super power"),
Genre("Superma"),
Genre("Supernatural"),
Genre("Tragedy"),
Genre("Vampire"),
Genre("Webtoon"),
Genre("Yaoi"),
Genre("Yuri")
)
}

View File

@ -0,0 +1,18 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: TruyenTranhLh'
pkgNameSuffix = "vi.truyentranhlh"
extClass = '.Truyentrnahlh'
extVersionCode = 1
extVersionSuffix = 1
libVersion = '1.0'
}
dependencies {
provided "com.google.code.gson:gson:2.8.0"
provided "com.github.salomonbrys.kotson:kotson:2.5.0"
}
apply from: "$rootDir/common.gradle"

View File

@ -0,0 +1,191 @@
package eu.kanade.tachiyomi.source.online.vietnamese
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.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element
import java.util.*
class Truyentranhlh : HttpSource() {
override val name = "TruyenTranhLH"
override val baseUrl = "http://truyentranhlh.com"
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").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) }
manga.thumbnail_url = document.select("img.thumbnail").first()?.attr("src")
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>()
var i = 0
document.select("div.chapter-content > img").forEach {
pages.add(Page(i++, "", it.attr("src")))
}
return pages
}
override fun imageUrlRequest(page: Page) = GET(page.url)
override fun imageUrlParse(response: Response): String {
return ""
}
}