diff --git a/src/vi/blogtruyen/AndroidManifest.xml b/src/vi/blogtruyen/AndroidManifest.xml
index fb26bfecb..f022fb209 100644
--- a/src/vi/blogtruyen/AndroidManifest.xml
+++ b/src/vi/blogtruyen/AndroidManifest.xml
@@ -13,8 +13,34 @@
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/vi/blogtruyen/build.gradle b/src/vi/blogtruyen/build.gradle
index 49590524b..019391573 100644
--- a/src/vi/blogtruyen/build.gradle
+++ b/src/vi/blogtruyen/build.gradle
@@ -5,7 +5,7 @@ ext {
extName = 'BlogTruyen'
pkgNameSuffix = 'vi.blogtruyen'
extClass = '.BlogTruyen'
- extVersionCode = 13
+ extVersionCode = 14
isNsfw = true
}
diff --git a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt b/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt
index 349236db0..b89e64681 100644
--- a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt
+++ b/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyen.kt
@@ -48,6 +48,8 @@ class BlogTruyen : ParsedHttpSource() {
companion object {
const val PREFIX_ID_SEARCH = "id:"
+ const val PREFIX_AUTHOR_SEARCH = "author:"
+ const val PREFIX_TEAM_SEARCH = "team:"
}
override fun headersBuilder(): Headers.Builder =
@@ -105,23 +107,53 @@ class BlogTruyen : ParsedHttpSource() {
): Observable {
return when {
query.startsWith(PREFIX_ID_SEARCH) -> {
- val id = query.removePrefix(PREFIX_ID_SEARCH).trim()
- if (!id.startsWith("/")) {
- throw Exception("ID tìm kiếm không hợp lệ")
+ var id = query.removePrefix(PREFIX_ID_SEARCH).trim()
+
+ // it's a chapter, resolve to manga ID
+ if (id.startsWith("c")) {
+ val document = client.newCall(GET("$baseUrl/$id", headers)).execute().asJsoup()
+ id = document.selectFirst(".breadcrumbs a:last-child").attr("href").removePrefix("/")
}
fetchMangaDetails(
SManga.create().apply {
- url = id
+ url = "/$id"
}
)
- .map { MangasPage(listOf(it.apply { url = id }), false) }
+ .map { MangasPage(listOf(it.apply { url = "/$id" }), false) }
}
else -> super.fetchSearchManga(page, query, filters)
}
}
+ private fun extractIdFromQuery(prefix: String, query: String): String {
+ val q = query.substringAfter(prefix).trim()
+ return if (q.contains("-")) {
+ q.substringAfterLast("-")
+ } else {
+ q
+ }
+ }
+
+ private val ajaxSearchUrls: Map = mapOf(
+ PREFIX_AUTHOR_SEARCH to "Author/AjaxLoadMangaByAuthor?orderBy=3",
+ PREFIX_TEAM_SEARCH to "TranslateTeam/AjaxLoadMangaByTranslateTeam",
+ )
+
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
+ ajaxSearchUrls.keys.forEach {
+ if (!query.startsWith(it)) {
+ return@forEach
+ }
+ val id = extractIdFromQuery(it, query)
+ val url = "$baseUrl/ajax/${ajaxSearchUrls[it]}".toHttpUrl().newBuilder()
+ .addQueryParameter("id", id)
+ .addQueryParameter("p", page.toString())
+ .build()
+ .toString()
+ return GET(url, headers)
+ }
+
val url = "$baseUrl/timkiem/nangcao/1".toHttpUrl().newBuilder().apply {
addQueryParameter("txt", query)
addQueryParameter("p", page.toString())
@@ -181,34 +213,75 @@ class BlogTruyen : ParsedHttpSource() {
override fun searchMangaNextPageSelector() = ".pagination .glyphicon-step-forward"
+ private fun getMangaTitle(document: Document) = document.selectFirst(".entry-title a")
+ .attr("title")
+ .replaceFirst("truyện tranh", "", false)
+ .trim()
+
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
val anchor = document.selectFirst(".entry-title a")
setUrlWithoutDomain(anchor.attr("href"))
- title = anchor.attr("title")
- .replace("truyện tranh ", "")
- .trim()
+ title = getMangaTitle(document)
thumbnail_url = document.select(".thumbnail img").attr("abs:src")
- author = document.select("a.color-green.label.label-info").joinToString { it.text() }
+ author = document.select("a[href*=tac-gia]").joinToString { it.text() }
genre = document.select("span.category a").joinToString { it.text() }
status = parseStatus(
document.select("span.color-red:not(.bold)").text()
)
- description = document.selectFirst(".manga-detail .detail .content").let {
- if (it.select("p").any()) {
- it.select("p").joinToString("\n", transform = ::brToNewline)
- } else {
- brToNewline(it)
+ description = StringBuilder().apply {
+ // the actual synopsis
+ val synopsisBlock = document.selectFirst(".manga-detail .detail .content")
+
+ // replace the facebook blockquote in synopsis with the link (if there is one)
+ val fbElement = synopsisBlock.selectFirst(".fb-page, .fb-group")
+ if (fbElement != null) {
+ val fbLink = fbElement.attr("data-href")
+
+ val node = document.createElement("p")
+ node.appendText(fbLink)
+
+ fbElement.replaceWith(node)
}
- }
+ appendLine(synopsisBlock.textWithNewlines().trim())
+ appendLine()
+
+ // other metadata
+ document.select(".description p").forEach {
+ val text = it.text()
+ if (text.contains("Thể loại") ||
+ text.contains("Tác giả") ||
+ text.isBlank()
+ ) {
+ return@forEach
+ }
+
+ if (text.contains("Trạng thái")) {
+ appendLine(text.substringBefore("Trạng thái").trim())
+ return@forEach
+ }
+
+ if (text.contains("Nguồn") ||
+ text.contains("Tham gia update") ||
+ text.contains("Nhóm dịch")
+ ) {
+ val key = text.substringBefore(":")
+ val value = it.select("a").joinToString { el -> el.text() }
+ appendLine("$key: $value")
+ return@forEach
+ }
+
+ it.select("a, span").append("\\n")
+ appendLine(it.text().replace("\\n", "\n").replace("\n ", "\n").trim())
+ }
+ }.toString().trim()
}
- private fun brToNewline(element: Element): String {
- return element.run {
- select("br").prepend("\\n")
- text().replace("\\n", "\n").replace("\n ", "\n")
- }
+ private fun Element.textWithNewlines() = run {
+ select("p").prepend("\\n")
+ select("br").prepend("\\n")
+ text().replace("\\n", "\n").replace("\n ", "\n")
}
private fun parseStatus(status: String) = when {
@@ -218,13 +291,21 @@ class BlogTruyen : ParsedHttpSource() {
else -> SManga.UNKNOWN
}
+ override fun chapterListParse(response: Response): List {
+ val document = response.asJsoup()
+ val title = getMangaTitle(document)
+ return document.select(chapterListSelector()).map { chapterFromElement(it, title) }
+ }
+
override fun chapterListSelector() = "div.list-wrap > p"
- override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
+ override fun chapterFromElement(element: Element): SChapter = throw UnsupportedOperationException("Not used")
+
+ private fun chapterFromElement(element: Element, title: String): SChapter = SChapter.create().apply {
val anchor = element.select("span > a").first()
setUrlWithoutDomain(anchor.attr("href"))
- name = anchor.attr("title").trim()
+ name = anchor.attr("title").replace(title, "", true).trim()
date_upload = kotlin.runCatching {
dateFormat.parse(
element.selectFirst("span.publishedDate").text()
diff --git a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt b/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt
index 4777ed87c..304accb7b 100644
--- a/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt
+++ b/src/vi/blogtruyen/src/eu/kanade/tachiyomi/extension/vi/blogtruyen/BlogTruyenUrlActivity.kt
@@ -12,12 +12,17 @@ class BlogTruyenUrlActivity : Activity() {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size > 1) {
- val id = "/${pathSegments[0]}/${pathSegments[1]}"
try {
startActivity(
Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
- putExtra("query", "${BlogTruyen.PREFIX_ID_SEARCH}$id")
+ with(pathSegments[0]) {
+ when {
+ equals("tac-gia") -> putExtra("query", "${BlogTruyen.PREFIX_AUTHOR_SEARCH}${pathSegments[1]}")
+ equals("nhom-dich") -> putExtra("query", "${BlogTruyen.PREFIX_TEAM_SEARCH}${pathSegments[1]}")
+ else -> putExtra("query", "${BlogTruyen.PREFIX_ID_SEARCH}${pathSegments[0]}/${pathSegments[1]}")
+ }
+ }
putExtra("filter", packageName)
}
)