Nekopost extension: Search fix (HTTP error 520) (#18931)
* format the code and change the throw exception * fix nekopost search * switch to HttpSource use request/parse instead of fetch * Remove commented code.
This commit is contained in:
parent
d044170507
commit
11a8fc6e5f
|
@ -6,7 +6,7 @@ ext {
|
|||
extName = 'Nekopost'
|
||||
pkgNameSuffix = 'th.nekopost'
|
||||
extClass = '.Nekopost'
|
||||
extVersionCode = 9
|
||||
extVersionCode = 10
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
|
|
|
@ -2,38 +2,35 @@ package eu.kanade.tachiyomi.extension.th.nekopost
|
|||
|
||||
import eu.kanade.tachiyomi.extension.th.nekopost.model.RawChapterInfo
|
||||
import eu.kanade.tachiyomi.extension.th.nekopost.model.RawProjectInfo
|
||||
import eu.kanade.tachiyomi.extension.th.nekopost.model.RawProjectNameListItem
|
||||
import eu.kanade.tachiyomi.extension.th.nekopost.model.RawProjectSearchSummary
|
||||
import eu.kanade.tachiyomi.extension.th.nekopost.model.RawProjectSummaryList
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
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.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Nekopost : ParsedHttpSource() {
|
||||
class Nekopost : HttpSource() {
|
||||
private val json: Json by injectLazy()
|
||||
override val baseUrl: String = "https://www.nekopost.net/manga/"
|
||||
|
||||
private val latestMangaEndpoint: String =
|
||||
"https://api.osemocphoto.com/frontAPI/getLatestChapter/m"
|
||||
private val projectDataEndpoint: String =
|
||||
"https://api.osemocphoto.com/frontAPI/getProjectInfo"
|
||||
private val latestMangaEndpoint: String = "https://api.osemocphoto.com/frontAPI/getLatestChapter/m"
|
||||
private val projectDataEndpoint: String = "https://api.osemocphoto.com/frontAPI/getProjectInfo"
|
||||
private val fileHost: String = "https://www.osemocphoto.com"
|
||||
private val nekopostUrl = "https://www.nekopost.net"
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient
|
||||
|
||||
|
@ -57,118 +54,96 @@ class Nekopost : ParsedHttpSource() {
|
|||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request = throw NotImplementedError("Unused")
|
||||
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used.")
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage =
|
||||
throw NotImplementedError("Unused")
|
||||
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used.")
|
||||
|
||||
override fun chapterListSelector(): String = throw NotImplementedError("Unused")
|
||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used.")
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter =
|
||||
throw NotImplementedError("Unused")
|
||||
override fun imageUrlRequest(page: Page): Request = throw UnsupportedOperationException("Not used.")
|
||||
|
||||
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl)
|
||||
|
||||
override fun imageUrlParse(document: Document): String = throw NotImplementedError("Unused")
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Unused")
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String = throw Exception("Unused")
|
||||
|
||||
override fun latestUpdatesSelector(): String = throw Exception("Unused")
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga = throw NotImplementedError("Unused")
|
||||
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return client.newCall(GET("$projectDataEndpoint/${manga.url}", headers))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val responseBody = response.body
|
||||
val projectInfo: RawProjectInfo = json.decodeFromString(responseBody.string())
|
||||
|
||||
manga.apply {
|
||||
projectInfo.projectInfo.let {
|
||||
url = it.projectId
|
||||
title = it.projectName
|
||||
artist = it.artistName
|
||||
author = it.authorName
|
||||
description = it.info
|
||||
status = getStatus(it.status)
|
||||
thumbnail_url =
|
||||
"$fileHost/collectManga/${it.projectId}/${it.projectId}_cover.jpg"
|
||||
initialized = true
|
||||
}
|
||||
|
||||
genre = if (projectInfo.projectCategoryUsed != null) {
|
||||
projectInfo.projectCategoryUsed.joinToString(", ") { it.categoryName }
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
}
|
||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||
return GET("$projectDataEndpoint/${manga.url}", headers)
|
||||
}
|
||||
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
return if (manga.status != SManga.LICENSED) {
|
||||
client.newCall(GET("$projectDataEndpoint/${manga.url}", headers))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val responseBody = response.body
|
||||
val projectInfo: RawProjectInfo = json.decodeFromString(responseBody.string())
|
||||
override fun mangaDetailsParse(response: Response): SManga {
|
||||
val responseBody = response.body
|
||||
val projectInfo: RawProjectInfo = json.decodeFromString(responseBody.string())
|
||||
val manga = SManga.create()
|
||||
manga.apply {
|
||||
projectInfo.projectInfo.let {
|
||||
url = it.projectId
|
||||
title = it.projectName
|
||||
artist = it.artistName
|
||||
author = it.authorName
|
||||
description = it.info
|
||||
status = getStatus(it.status)
|
||||
thumbnail_url = "$fileHost/collectManga/${it.projectId}/${it.projectId}_cover.jpg"
|
||||
initialized = true
|
||||
}
|
||||
|
||||
manga.status = getStatus(projectInfo.projectInfo.status)
|
||||
genre = if (projectInfo.projectCategoryUsed != null) {
|
||||
projectInfo.projectCategoryUsed.joinToString(", ") { it.categoryName }
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
return manga
|
||||
}
|
||||
|
||||
if (manga.status == SManga.LICENSED) {
|
||||
throw Exception("Licensed - No chapter to show")
|
||||
}
|
||||
override fun chapterListRequest(manga: SManga): Request {
|
||||
val headers = Headers.headersOf("accept", "*/*", "content-type", "text/plain;charset=UTF-8", "origin", nekopostUrl)
|
||||
return GET("$projectDataEndpoint/${manga.url}", headers)
|
||||
}
|
||||
|
||||
projectInfo.projectChapterList!!.map { chapter ->
|
||||
SChapter.create().apply {
|
||||
url =
|
||||
"${manga.url}/${chapter.chapterId}/${manga.url}_${chapter.chapterId}.json"
|
||||
name = chapter.chapterName
|
||||
date_upload = SimpleDateFormat(
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
Locale("th"),
|
||||
).parse(chapter.createDate)?.time
|
||||
?: 0L
|
||||
chapter_number = chapter.chapterNo.toFloat()
|
||||
scanlator = chapter.providerName
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Observable.error(Exception("Licensed - No chapter to show"))
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val responseBody = response.body.string()
|
||||
val projectInfo: RawProjectInfo = json.decodeFromString(responseBody)
|
||||
val manga = SManga.create()
|
||||
manga.status = getStatus(projectInfo.projectInfo.status)
|
||||
|
||||
if (manga.status == SManga.LICENSED) {
|
||||
throw Exception("Licensed - No chapter to show")
|
||||
}
|
||||
|
||||
return projectInfo.projectChapterList!!.map { chapter ->
|
||||
SChapter.create().apply {
|
||||
url = "${projectInfo.projectInfo.projectId.toInt()}/${chapter.chapterId}/${projectInfo.projectInfo.projectId.toInt()}_${chapter.chapterId}.json"
|
||||
name = chapter.chapterName
|
||||
date_upload = SimpleDateFormat(
|
||||
"yyyy-MM-dd HH:mm:ss",
|
||||
Locale("th"),
|
||||
).parse(chapter.createDate)?.time ?: 0L
|
||||
chapter_number = chapter.chapterNo.toFloat()
|
||||
scanlator = chapter.providerName
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||
return client.newCall(GET("$fileHost/collectManga/${chapter.url}", headers))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val responseBody = response.body
|
||||
val chapterInfo: RawChapterInfo = json.decodeFromString(responseBody.string())
|
||||
|
||||
chapterInfo.pageItem.map { page ->
|
||||
val imgUrl: String = if (page.pageName != null) {
|
||||
"$fileHost/collectManga/${chapterInfo.projectId}/${chapterInfo.chapterId}/${page.pageName}"
|
||||
} else {
|
||||
"$fileHost/collectManga/${chapterInfo.projectId}/${chapterInfo.chapterId}/${page.fileName}"
|
||||
}
|
||||
Page(
|
||||
index = page.pageNo,
|
||||
imageUrl = imgUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
return GET("$fileHost/collectManga/${chapter.url}", headers)
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> = throw NotImplementedError("Unused")
|
||||
override fun pageListParse(response: Response): List<Page> {
|
||||
val responseBody = response.body
|
||||
val chapterInfo: RawChapterInfo = json.decodeFromString(responseBody.string())
|
||||
|
||||
return chapterInfo.pageItem.map { page ->
|
||||
val imgUrl: String = if (page.pageName != null) {
|
||||
"$fileHost/collectManga/${chapterInfo.projectId}/${chapterInfo.chapterId}/${page.pageName}"
|
||||
} else {
|
||||
"$fileHost/collectManga/${chapterInfo.projectId}/${chapterInfo.chapterId}/${page.fileName}"
|
||||
}
|
||||
Page(
|
||||
index = page.pageNo,
|
||||
imageUrl = imgUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
if (page <= 1) existingProject.clear()
|
||||
// API has a bug that sometime it returns null on first page
|
||||
return GET("$latestMangaEndpoint/${if (firstPageNulled) page else page - 1 }", headers)
|
||||
return GET("$latestMangaEndpoint/${if (firstPageNulled) page else page - 1}", headers)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
|
@ -176,18 +151,15 @@ class Nekopost : ParsedHttpSource() {
|
|||
val projectList: RawProjectSummaryList = json.decodeFromString(responseBody.string())
|
||||
|
||||
val mangaList: List<SManga> = if (projectList.listChapter != null) {
|
||||
projectList.listChapter
|
||||
.filter { !existingProject.contains(it.projectId) }
|
||||
.map {
|
||||
SManga.create().apply {
|
||||
url = it.projectId
|
||||
title = it.projectName
|
||||
thumbnail_url =
|
||||
"$fileHost/collectManga/${it.projectId}/${it.projectId}_cover.jpg"
|
||||
initialized = false
|
||||
status = 0
|
||||
}
|
||||
projectList.listChapter.filter { !existingProject.contains(it.projectId) }.map {
|
||||
SManga.create().apply {
|
||||
url = it.projectId
|
||||
title = it.projectName
|
||||
thumbnail_url = "$fileHost/collectManga/${it.projectId}/${it.projectId}_cover.jpg"
|
||||
initialized = false
|
||||
status = 0
|
||||
}
|
||||
}
|
||||
} else {
|
||||
firstPageNulled = true // API has a bug that sometime it returns null on first page
|
||||
return MangasPage(emptyList(), hasNextPage = false)
|
||||
|
@ -198,51 +170,27 @@ class Nekopost : ParsedHttpSource() {
|
|||
return MangasPage(mangaList, hasNextPage = true)
|
||||
}
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga =
|
||||
throw NotImplementedError("Unused")
|
||||
|
||||
override fun popularMangaNextPageSelector(): String = throw Exception("Unused")
|
||||
|
||||
override fun popularMangaSelector(): String = throw Exception("Unused")
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Unused")
|
||||
|
||||
override fun searchMangaNextPageSelector(): String = throw Exception("Unused")
|
||||
|
||||
override fun fetchSearchManga(
|
||||
page: Int,
|
||||
query: String,
|
||||
filters: FilterList,
|
||||
): Observable<MangasPage> {
|
||||
return client.newCall(GET("$fileHost/dataJson/dataProjectName.json"))
|
||||
.asObservableSuccess()
|
||||
.map { response ->
|
||||
val responseBody = response.body
|
||||
val projectList: List<RawProjectNameListItem> =
|
||||
json.decodeFromString(responseBody.string())
|
||||
|
||||
val mangaList: List<SManga> = projectList.filter { project ->
|
||||
Regex(
|
||||
query,
|
||||
setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE),
|
||||
).find(project.npName) != null
|
||||
}.map { project ->
|
||||
SManga.create().apply {
|
||||
url = project.npProjectId
|
||||
title = project.npName
|
||||
status = getStatus(project.npStatus)
|
||||
initialized = false
|
||||
}
|
||||
}
|
||||
|
||||
MangasPage(mangaList, false)
|
||||
}
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val headers = Headers.headersOf("accept", "*/*", "content-type", "text/plain;charset=UTF-8", "origin", nekopostUrl)
|
||||
val requestBody = "{\"keyword\":\"$query\"}".toRequestBody()
|
||||
return POST("$nekopostUrl/api/explore/search", headers, requestBody)
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
|
||||
throw Exception("Unused")
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val responseBody = response.body.string()
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage = throw Exception("Unused")
|
||||
val projectList: List<RawProjectSearchSummary> = json.decodeFromString(responseBody)
|
||||
val mangaList: List<SManga> = projectList.filter { project ->
|
||||
project.projectType == "m"
|
||||
}.map { project ->
|
||||
SManga.create().apply {
|
||||
url = project.projectId.toString()
|
||||
title = project.projectName
|
||||
status = project.status
|
||||
initialized = false
|
||||
}
|
||||
}
|
||||
|
||||
override fun searchMangaSelector(): String = throw Exception("Unused")
|
||||
return MangasPage(mangaList, false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
data class RawProjectSearchSummary(
|
||||
val projectId: Int,
|
||||
val projectName: String,
|
||||
val projectType: String,
|
||||
@SerialName("STATUS")
|
||||
val status: Int,
|
||||
val noChapter: Int,
|
||||
val coverVersion: Int,
|
||||
val info: String,
|
||||
val views: Int,
|
||||
@SerialName("lastUpdate")
|
||||
val lastUpdateDate: String,
|
||||
)
|
Loading…
Reference in New Issue