[TH] Nekopost - Fix unable to read saved manga (#9459)
* Fix not found error and add all api types * Update build.gradle * Disable latest feature and use popular as latest instead * Add logic to prevent duplicate projects * Clear fetched list each time fetching from page 1 * Fix search logic * Fix invalid genre joining
This commit is contained in:
parent
cc792ccfb1
commit
9badbeb0db
|
@ -5,7 +5,8 @@ ext {
|
||||||
extName = 'Nekopost'
|
extName = 'Nekopost'
|
||||||
pkgNameSuffix = 'th.nekopost'
|
pkgNameSuffix = 'th.nekopost'
|
||||||
extClass = '.Nekopost'
|
extClass = '.Nekopost'
|
||||||
extVersionCode = 4
|
extVersionCode = 5
|
||||||
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
|
|
@ -1,153 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.th.nekopost
|
|
||||||
|
|
||||||
data class RawMangaData(
|
|
||||||
val no_new_chapter: String,
|
|
||||||
val nc_chapter_id: String,
|
|
||||||
val np_project_id: String,
|
|
||||||
val np_name: String,
|
|
||||||
val np_name_link: String,
|
|
||||||
val nc_chapter_no: String,
|
|
||||||
val nc_chapter_name: String,
|
|
||||||
val nc_chapter_cover: String,
|
|
||||||
val nc_provider: String,
|
|
||||||
val np_group_dir: String,
|
|
||||||
val nc_created_date: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RawMangaDataList(
|
|
||||||
val code: String,
|
|
||||||
val listItem: Array<RawMangaData>?
|
|
||||||
) {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as RawMangaDataList
|
|
||||||
|
|
||||||
if (code != other.code) return false
|
|
||||||
if (listItem != null) {
|
|
||||||
if (other.listItem == null) return false
|
|
||||||
if (!listItem.contentEquals(other.listItem)) return false
|
|
||||||
} else if (other.listItem != null) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = code.hashCode()
|
|
||||||
result = 31 * result + (listItem?.contentHashCode() ?: 0)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class RawProjectData(
|
|
||||||
val np_status: String,
|
|
||||||
val np_project_id: String,
|
|
||||||
val np_type: String,
|
|
||||||
val np_name: String,
|
|
||||||
val np_name_link: String,
|
|
||||||
val np_flag_mature: String,
|
|
||||||
val np_info: String,
|
|
||||||
val np_view: String,
|
|
||||||
val np_comment: String,
|
|
||||||
val np_created_date: String,
|
|
||||||
val np_updated_date: String,
|
|
||||||
val author_name: String,
|
|
||||||
val artist_name: String,
|
|
||||||
val np_web: String,
|
|
||||||
val np_licenced_by: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RawProjectGenre(
|
|
||||||
val npc_name: String,
|
|
||||||
val npc_name_link: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RawChapterData(
|
|
||||||
val nc_chapter_id: String,
|
|
||||||
val nc_chapter_no: String,
|
|
||||||
val nc_chapter_name: String,
|
|
||||||
val nc_provider: String,
|
|
||||||
val cu_displayname: String,
|
|
||||||
val nc_created_date: String,
|
|
||||||
val nc_data_file: String,
|
|
||||||
val nc_owner_id: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RawMangaDetailedData(
|
|
||||||
val code: String,
|
|
||||||
val projectInfo: RawProjectData,
|
|
||||||
val projectCategoryUsed: Array<RawProjectGenre>?,
|
|
||||||
val projectChapterList: Array<RawChapterData>,
|
|
||||||
) {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as RawMangaDetailedData
|
|
||||||
|
|
||||||
if (code != other.code) return false
|
|
||||||
if (projectInfo != other.projectInfo) return false
|
|
||||||
if (projectCategoryUsed != null) {
|
|
||||||
if (other.projectCategoryUsed == null) return false
|
|
||||||
if (!projectCategoryUsed.contentEquals(other.projectCategoryUsed)) return false
|
|
||||||
} else if (other.projectCategoryUsed != null) return false
|
|
||||||
if (!projectChapterList.contentEquals(other.projectChapterList)) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = code.hashCode()
|
|
||||||
result = 31 * result + projectInfo.hashCode()
|
|
||||||
result = 31 * result + (projectCategoryUsed?.contentHashCode() ?: 0)
|
|
||||||
result = 31 * result + projectChapterList.contentHashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class RawPageData(
|
|
||||||
val pageNo: Int,
|
|
||||||
val fileName: String,
|
|
||||||
val width: Int,
|
|
||||||
val height: Int,
|
|
||||||
val pageCount: Int
|
|
||||||
)
|
|
||||||
|
|
||||||
data class RawChapterDetailedData(
|
|
||||||
val projectId: String,
|
|
||||||
val chapterId: Int,
|
|
||||||
val chapterNo: String,
|
|
||||||
val pageItem: Array<RawPageData>,
|
|
||||||
) {
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
if (this === other) return true
|
|
||||||
if (javaClass != other?.javaClass) return false
|
|
||||||
|
|
||||||
other as RawChapterDetailedData
|
|
||||||
|
|
||||||
if (projectId != other.projectId) return false
|
|
||||||
if (chapterId != other.chapterId) return false
|
|
||||||
if (chapterNo != other.chapterNo) return false
|
|
||||||
if (!pageItem.contentEquals(other.pageItem)) return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode(): Int {
|
|
||||||
var result = projectId.hashCode()
|
|
||||||
result = 31 * result + chapterId
|
|
||||||
result = 31 * result + chapterNo.hashCode()
|
|
||||||
result = 31 * result + pageItem.contentHashCode()
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class MangaNameList(
|
|
||||||
val np_project_id: String,
|
|
||||||
val np_name: String,
|
|
||||||
val np_name_link: String,
|
|
||||||
val np_type: String,
|
|
||||||
val np_status: String,
|
|
||||||
val np_no_chapter: String,
|
|
||||||
)
|
|
|
@ -1,6 +1,10 @@
|
||||||
package eu.kanade.tachiyomi.extension.th.nekopost
|
package eu.kanade.tachiyomi.extension.th.nekopost
|
||||||
|
|
||||||
import com.google.gson.Gson
|
import com.google.gson.Gson
|
||||||
|
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.RawProjectNameList
|
||||||
|
import eu.kanade.tachiyomi.extension.th.nekopost.model.RawProjectSummaryList
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
@ -20,11 +24,14 @@ import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
class Nekopost : ParsedHttpSource() {
|
class Nekopost : ParsedHttpSource() {
|
||||||
override val baseUrl: String = "https://www.nekopost.net/manga/"
|
private val gson: Gson = Gson()
|
||||||
|
override val baseUrl: String = "https://www.nekopost.net/project"
|
||||||
|
|
||||||
private val mangaListUrl: String = "https://tuner.nekopost.net/ApiTest/getLatestChapterOffset/m/"
|
private val latestMangaEndpoint: String =
|
||||||
private val projectDataUrl: String = "https://tuner.nekopost.net/ApiTest/getProjectDetailFull/"
|
"https://tuner.nekopost.net/ApiTest/getLatestChapterOffset/m"
|
||||||
private val fileUrl: String = "https://fs.nekopost.net/"
|
private val projectDataEndpoint: String =
|
||||||
|
"https://tuner.nekopost.net/ApiTest/getProjectDetailFull"
|
||||||
|
private val fileHost: String = "https://fs.nekopost.net"
|
||||||
|
|
||||||
override val client: OkHttpClient = network.cloudflareClient
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
|
|
||||||
|
@ -32,34 +39,12 @@ class Nekopost : ParsedHttpSource() {
|
||||||
return super.headersBuilder().add("Referer", baseUrl)
|
return super.headersBuilder().add("Referer", baseUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val existingProject: HashSet<String> = HashSet()
|
||||||
|
|
||||||
override val lang: String = "th"
|
override val lang: String = "th"
|
||||||
override val name: String = "Nekopost"
|
override val name: String = "Nekopost"
|
||||||
|
|
||||||
override val supportsLatest: Boolean = true
|
override val supportsLatest: Boolean = false
|
||||||
|
|
||||||
private data class MangaListTracker(
|
|
||||||
var offset: Int = 0,
|
|
||||||
val list: HashSet<String> = HashSet()
|
|
||||||
)
|
|
||||||
|
|
||||||
private var latestMangaTracker = MangaListTracker()
|
|
||||||
private var popularMangaTracker = MangaListTracker()
|
|
||||||
|
|
||||||
data class ProjectRecord(
|
|
||||||
val project: SManga,
|
|
||||||
val project_id: String,
|
|
||||||
val chapter_list: HashSet<String> = HashSet(),
|
|
||||||
)
|
|
||||||
|
|
||||||
data class ChapterRecord(
|
|
||||||
val chapter: SChapter,
|
|
||||||
val chapter_id: String,
|
|
||||||
val project: ProjectRecord,
|
|
||||||
val pages_data: String,
|
|
||||||
)
|
|
||||||
|
|
||||||
private var projectUrlMap = HashMap<String, ProjectRecord>()
|
|
||||||
private var chapterList = HashMap<String, ChapterRecord>()
|
|
||||||
|
|
||||||
private fun getStatus(status: String) = when (status) {
|
private fun getStatus(status: String) = when (status) {
|
||||||
"1" -> SManga.ONGOING
|
"1" -> SManga.ONGOING
|
||||||
|
@ -68,132 +53,76 @@ class Nekopost : ParsedHttpSource() {
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fetchMangas(page: Int, tracker: MangaListTracker): Observable<MangasPage> {
|
override fun latestUpdatesRequest(page: Int): Request = throw NotImplementedError("Unused")
|
||||||
if (page == 1) {
|
|
||||||
tracker.list.clear()
|
|
||||||
tracker.offset = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
return client.newCall(latestUpdatesRequest(page + tracker.offset))
|
override fun latestUpdatesParse(response: Response): MangasPage =
|
||||||
.asObservableSuccess()
|
throw NotImplementedError("Unused")
|
||||||
.concatMap { response ->
|
|
||||||
latestUpdatesParse(response).let {
|
|
||||||
if (it.mangas.isEmpty() && it.hasNextPage) {
|
|
||||||
tracker.offset++
|
|
||||||
fetchLatestUpdates(page)
|
|
||||||
} else {
|
|
||||||
Observable.just(it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun mangasRequest(page: Int): Request = GET("$mangaListUrl${page - 1}")
|
|
||||||
|
|
||||||
private fun mangasParse(response: Response, tracker: MangaListTracker): MangasPage {
|
|
||||||
val mangaData = Gson().fromJson(response.body!!.string(), RawMangaDataList::class.java)
|
|
||||||
|
|
||||||
return if (mangaData.listItem != null) {
|
|
||||||
val mangas: List<SManga> = mangaData.listItem.filter {
|
|
||||||
!tracker.list.contains(it.np_project_id)
|
|
||||||
}.map {
|
|
||||||
tracker.list.add(it.np_project_id)
|
|
||||||
SManga.create().apply {
|
|
||||||
url = it.np_project_id
|
|
||||||
title = it.np_name
|
|
||||||
thumbnail_url = "${fileUrl}collectManga/${it.np_project_id}/${it.np_project_id}_cover.jpg"
|
|
||||||
initialized = false
|
|
||||||
|
|
||||||
projectUrlMap[it.np_project_id] = ProjectRecord(
|
|
||||||
project = this,
|
|
||||||
project_id = it.np_project_id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MangasPage(mangas, true)
|
|
||||||
} else {
|
|
||||||
MangasPage(emptyList(), true)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListSelector(): String = throw NotImplementedError("Unused")
|
override fun chapterListSelector(): String = throw NotImplementedError("Unused")
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element): SChapter = throw NotImplementedError("Unused")
|
override fun chapterFromElement(element: Element): SChapter =
|
||||||
|
throw NotImplementedError("Unused")
|
||||||
|
|
||||||
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl)
|
override fun fetchImageUrl(page: Page): Observable<String> = Observable.just(page.imageUrl)
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String = throw NotImplementedError("Unused")
|
override fun imageUrlParse(document: Document): String = throw NotImplementedError("Unused")
|
||||||
|
|
||||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> = fetchMangas(page, latestMangaTracker)
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response): MangasPage = mangasParse(response, latestMangaTracker)
|
|
||||||
|
|
||||||
override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Unused")
|
override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Unused")
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector(): String = throw Exception("Unused")
|
override fun latestUpdatesNextPageSelector(): String = throw Exception("Unused")
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int): Request = mangasRequest(page)
|
|
||||||
|
|
||||||
override fun latestUpdatesSelector(): String = throw Exception("Unused")
|
override fun latestUpdatesSelector(): String = throw Exception("Unused")
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document): SManga = throw NotImplementedError("Unused")
|
override fun mangaDetailsParse(document: Document): SManga = throw NotImplementedError("Unused")
|
||||||
|
|
||||||
override fun fetchMangaDetails(sManga: SManga): Observable<SManga> {
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
val manga = projectUrlMap[sManga.url]!!
|
return client.newCall(GET("$projectDataEndpoint/${manga.url}"))
|
||||||
|
|
||||||
return client.newCall(GET("$projectDataUrl${manga.project_id}"))
|
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.concatMap {
|
.map { response ->
|
||||||
val mangaData = Gson().fromJson(it.body!!.string(), RawMangaDetailedData::class.java)
|
val responseBody =
|
||||||
|
response.body ?: throw Error("Unable to fetch manga detail of ${manga.title}")
|
||||||
|
val projectInfo = gson.fromJson(responseBody.string(), RawProjectInfo::class.java)
|
||||||
|
|
||||||
Observable.just(
|
manga.apply {
|
||||||
manga.project.apply {
|
projectInfo.projectData.let {
|
||||||
mangaData.projectInfo.also { projectData ->
|
url = it.npProjectId
|
||||||
artist = projectData.artist_name
|
title = it.npName
|
||||||
author = projectData.author_name
|
artist = it.artistName
|
||||||
description = projectData.np_info
|
author = it.authorName
|
||||||
status = getStatus(projectData.np_status)
|
description = it.npInfo
|
||||||
|
status = getStatus(it.npStatus)
|
||||||
initialized = true
|
initialized = true
|
||||||
}
|
}
|
||||||
genre = mangaData.projectCategoryUsed?.joinToString(", ") { cat -> cat.npc_name }
|
|
||||||
?: ""
|
genre =
|
||||||
|
projectInfo.projectCategoryUsed.map { it.npcName }.joinToString(", ")
|
||||||
}
|
}
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchChapterList(sManga: SManga): Observable<List<SChapter>> {
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||||
val manga = projectUrlMap[sManga.url]!!
|
return if (manga.status != SManga.LICENSED) {
|
||||||
|
client.newCall(GET("$projectDataEndpoint/${manga.url}"))
|
||||||
return if (manga.project.status != SManga.LICENSED) {
|
|
||||||
client.newCall(GET("$projectDataUrl${manga.project_id}"))
|
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map {
|
.map { response ->
|
||||||
val mangaData = Gson().fromJson(it.body!!.string(), RawMangaDetailedData::class.java)
|
val responseBody =
|
||||||
|
response.body
|
||||||
|
?: throw Error("Unable to fetch manga detail of ${manga.title}")
|
||||||
|
val projectInfo =
|
||||||
|
gson.fromJson(responseBody.string(), RawProjectInfo::class.java)
|
||||||
|
|
||||||
mangaData.projectChapterList.map { chapter ->
|
projectInfo.projectChapterList.map { chapter ->
|
||||||
val chapterUrl = "$baseUrl${manga.project_id}/${chapter.nc_chapter_no}"
|
SChapter.create().apply {
|
||||||
|
url = "${manga.url}/${chapter.ncChapterId}/${chapter.ncDataFile}"
|
||||||
manga.chapter_list.add(chapterUrl)
|
name = chapter.ncChapterName
|
||||||
|
date_upload = SimpleDateFormat(
|
||||||
val createdChapter = SChapter.create().apply {
|
"yyyy-MM-dd HH:mm:ss",
|
||||||
url = chapterUrl
|
Locale("th")
|
||||||
name = chapter.nc_chapter_name
|
).parse(chapter.ncCreatedDate)?.time
|
||||||
date_upload = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale("th")).parse(chapter.nc_created_date)?.time
|
|
||||||
?: 0L
|
?: 0L
|
||||||
chapter_number = chapter.nc_chapter_no.toFloat()
|
chapter_number = chapter.ncChapterNo.toFloat()
|
||||||
scanlator = chapter.cu_displayname
|
scanlator = chapter.cuDisplayname
|
||||||
}
|
}
|
||||||
|
|
||||||
chapterList[chapterUrl] = ChapterRecord(
|
|
||||||
chapter = createdChapter,
|
|
||||||
project = manga,
|
|
||||||
chapter_id = chapter.nc_chapter_id,
|
|
||||||
pages_data = chapter.nc_data_file,
|
|
||||||
)
|
|
||||||
|
|
||||||
createdChapter
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -201,18 +130,20 @@ class Nekopost : ParsedHttpSource() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchPageList(sChapter: SChapter): Observable<List<Page>> {
|
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||||
val chapter = chapterList[sChapter.url]!!
|
return client.newCall(GET("$fileHost/collectManga/${chapter.url}"))
|
||||||
|
|
||||||
return client.newCall(GET("${fileUrl}collectManga/${chapter.project.project_id}/${chapter.chapter_id}/${chapter.pages_data}"))
|
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map {
|
.map { response ->
|
||||||
val chapterData = Gson().fromJson(it.body!!.string(), RawChapterDetailedData::class.java)
|
val responseBody =
|
||||||
|
response.body
|
||||||
|
?: throw Error("Unable to fetch page list of chapter ${chapter.chapter_number}")
|
||||||
|
val chapterInfo =
|
||||||
|
gson.fromJson(responseBody.string(), RawChapterInfo::class.java)
|
||||||
|
|
||||||
chapterData.pageItem.map { pageData ->
|
chapterInfo.pageItem.map { page ->
|
||||||
Page(
|
Page(
|
||||||
index = pageData.pageNo,
|
index = page.pageNo,
|
||||||
imageUrl = "${fileUrl}collectManga/${chapter.project.project_id}/${chapter.chapter_id}/${pageData.fileName}",
|
imageUrl = "$fileHost/collectManga/${chapterInfo.projectId}/${chapterInfo.chapterId}/${page.fileName}",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -220,52 +151,78 @@ class Nekopost : ParsedHttpSource() {
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = throw NotImplementedError("Unused")
|
override fun pageListParse(document: Document): List<Page> = throw NotImplementedError("Unused")
|
||||||
|
|
||||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> = fetchMangas(page, popularMangaTracker)
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
|
if (page <= 1) existingProject.clear()
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage = mangasParse(response, popularMangaTracker)
|
return GET("$latestMangaEndpoint/${page - 1}")
|
||||||
|
}
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element): SManga = throw NotImplementedError("Unused")
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
|
val responseBody = response.body ?: throw Error("Unable to fetch mangas")
|
||||||
|
val projectList = gson.fromJson(responseBody.string(), RawProjectSummaryList::class.java)
|
||||||
|
|
||||||
|
val mangaList: List<SManga> =
|
||||||
|
projectList.listItem
|
||||||
|
?.filter { !existingProject.contains(it.npProjectId) }
|
||||||
|
?.map {
|
||||||
|
SManga.create().apply {
|
||||||
|
url = it.npProjectId
|
||||||
|
title = it.npName
|
||||||
|
thumbnail_url =
|
||||||
|
"$fileHost/collectManga/${it.npProjectId}/${it.npProjectId}_cover.jpg"
|
||||||
|
initialized = false
|
||||||
|
status = 0
|
||||||
|
}
|
||||||
|
} ?: return MangasPage(emptyList(), hasNextPage = false)
|
||||||
|
|
||||||
|
mangaList.forEach { existingProject.add(it.url) }
|
||||||
|
|
||||||
|
return MangasPage(mangaList, hasNextPage = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularMangaFromElement(element: Element): SManga =
|
||||||
|
throw NotImplementedError("Unused")
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector(): String = throw Exception("Unused")
|
override fun popularMangaNextPageSelector(): String = throw Exception("Unused")
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request = mangasRequest(page)
|
|
||||||
|
|
||||||
override fun popularMangaSelector(): String = throw Exception("Unused")
|
override fun popularMangaSelector(): String = throw Exception("Unused")
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Unused")
|
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Unused")
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector(): String = throw Exception("Unused")
|
override fun searchMangaNextPageSelector(): String = throw Exception("Unused")
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
override fun fetchSearchManga(
|
||||||
return client.newCall(GET("${fileUrl}dataJson/dataProjectName.json"))
|
page: Int,
|
||||||
|
query: String,
|
||||||
|
filters: FilterList
|
||||||
|
): Observable<MangasPage> {
|
||||||
|
return client.newCall(GET("$fileHost/dataJson/dataProjectName.json"))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map {
|
.map { response ->
|
||||||
val nameData = Gson().fromJson(it.body!!.string(), Array<MangaNameList>::class.java)
|
val responseBody = response.body ?: throw Error("Unable to fetch title list")
|
||||||
|
val projectList =
|
||||||
|
gson.fromJson(responseBody.string(), RawProjectNameList::class.java)
|
||||||
|
|
||||||
val mangas: List<SManga> = nameData.filter { d -> Regex(query, setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE)).find(d.np_name) != null }
|
val mangaList: List<SManga> = projectList.filter { project ->
|
||||||
.map { matchedManga ->
|
Regex(
|
||||||
if (!projectUrlMap.containsKey(matchedManga.np_project_id)) {
|
query,
|
||||||
|
setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE)
|
||||||
|
).find(project.npName) != null
|
||||||
|
}.map { project ->
|
||||||
SManga.create().apply {
|
SManga.create().apply {
|
||||||
url = matchedManga.np_project_id
|
url = project.npProjectId
|
||||||
title = matchedManga.np_name
|
title = project.npName
|
||||||
thumbnail_url = "${fileUrl}collectManga/${matchedManga.np_project_id}/${matchedManga.np_project_id}_cover.jpg"
|
status = getStatus(project.npStatus)
|
||||||
initialized = false
|
initialized = false
|
||||||
|
|
||||||
projectUrlMap[matchedManga.np_project_id] = ProjectRecord(
|
|
||||||
project = this,
|
|
||||||
project_id = matchedManga.np_project_id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
projectUrlMap[matchedManga.np_project_id]!!.project
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MangasPage(mangas, true)
|
MangasPage(mangaList, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request = throw Exception("Unused")
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request =
|
||||||
|
throw Exception("Unused")
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response): MangasPage = throw Exception("Unused")
|
override fun searchMangaParse(response: Response): MangasPage = throw Exception("Unused")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawChapterInfo(
|
||||||
|
@SerializedName("chapterId")
|
||||||
|
val chapterId: Int,
|
||||||
|
@SerializedName("chapterNo")
|
||||||
|
val chapterNo: String,
|
||||||
|
@SerializedName("pageCount")
|
||||||
|
val pageCount: Int,
|
||||||
|
@SerializedName("pageItem")
|
||||||
|
val pageItem: List<RawPageItem>,
|
||||||
|
@SerializedName("projectId")
|
||||||
|
val projectId: String
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawPageItem(
|
||||||
|
@SerializedName("fileName")
|
||||||
|
val fileName: String,
|
||||||
|
@SerializedName("height")
|
||||||
|
val height: Int,
|
||||||
|
@SerializedName("pageNo")
|
||||||
|
val pageNo: Int,
|
||||||
|
@SerializedName("width")
|
||||||
|
val width: Int
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectCategory(
|
||||||
|
@SerializedName("npc_name")
|
||||||
|
val npcName: String,
|
||||||
|
@SerializedName("npc_name_link")
|
||||||
|
val npcNameLink: String
|
||||||
|
)
|
|
@ -0,0 +1,22 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectChapter(
|
||||||
|
@SerializedName("cu_displayname")
|
||||||
|
val cuDisplayname: String,
|
||||||
|
@SerializedName("nc_chapter_id")
|
||||||
|
val ncChapterId: String,
|
||||||
|
@SerializedName("nc_chapter_name")
|
||||||
|
val ncChapterName: String,
|
||||||
|
@SerializedName("nc_chapter_no")
|
||||||
|
val ncChapterNo: String,
|
||||||
|
@SerializedName("nc_created_date")
|
||||||
|
val ncCreatedDate: String,
|
||||||
|
@SerializedName("nc_data_file")
|
||||||
|
val ncDataFile: String,
|
||||||
|
@SerializedName("nc_owner_id")
|
||||||
|
val ncOwnerId: String,
|
||||||
|
@SerializedName("nc_provider")
|
||||||
|
val ncProvider: String
|
||||||
|
)
|
|
@ -0,0 +1,14 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectInfo(
|
||||||
|
@SerializedName("code")
|
||||||
|
val code: String,
|
||||||
|
@SerializedName("projectCategoryUsed")
|
||||||
|
val projectCategoryUsed: List<RawProjectCategory>,
|
||||||
|
@SerializedName("projectChapterList")
|
||||||
|
val projectChapterList: List<RawProjectChapter>,
|
||||||
|
@SerializedName("projectInfo")
|
||||||
|
val projectData: RawProjectInfoData
|
||||||
|
)
|
|
@ -0,0 +1,36 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectInfoData(
|
||||||
|
@SerializedName("artist_name")
|
||||||
|
val artistName: String,
|
||||||
|
@SerializedName("author_name")
|
||||||
|
val authorName: String,
|
||||||
|
@SerializedName("np_comment")
|
||||||
|
val npComment: String,
|
||||||
|
@SerializedName("np_created_date")
|
||||||
|
val npCreatedDate: String,
|
||||||
|
@SerializedName("np_flag_mature")
|
||||||
|
val npFlagMature: String,
|
||||||
|
@SerializedName("np_info")
|
||||||
|
val npInfo: String,
|
||||||
|
@SerializedName("np_licenced_by")
|
||||||
|
val npLicencedBy: String,
|
||||||
|
@SerializedName("np_name")
|
||||||
|
val npName: String,
|
||||||
|
@SerializedName("np_name_link")
|
||||||
|
val npNameLink: String,
|
||||||
|
@SerializedName("np_project_id")
|
||||||
|
val npProjectId: String,
|
||||||
|
@SerializedName("np_status")
|
||||||
|
val npStatus: String,
|
||||||
|
@SerializedName("np_type")
|
||||||
|
val npType: String,
|
||||||
|
@SerializedName("np_updated_date")
|
||||||
|
val npUpdatedDate: String,
|
||||||
|
@SerializedName("np_view")
|
||||||
|
val npView: String,
|
||||||
|
@SerializedName("np_web")
|
||||||
|
val npWeb: String
|
||||||
|
)
|
|
@ -0,0 +1,3 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
class RawProjectNameList : ArrayList<RawProjectNameListItem>()
|
|
@ -0,0 +1,18 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectNameListItem(
|
||||||
|
@SerializedName("np_name")
|
||||||
|
val npName: String,
|
||||||
|
@SerializedName("np_name_link")
|
||||||
|
val npNameLink: String,
|
||||||
|
@SerializedName("np_no_chapter")
|
||||||
|
val npNoChapter: String,
|
||||||
|
@SerializedName("np_project_id")
|
||||||
|
val npProjectId: String,
|
||||||
|
@SerializedName("np_status")
|
||||||
|
val npStatus: String,
|
||||||
|
@SerializedName("np_type")
|
||||||
|
val npType: String
|
||||||
|
)
|
|
@ -0,0 +1,28 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectSummary(
|
||||||
|
@SerializedName("nc_chapter_cover")
|
||||||
|
val ncChapterCover: String,
|
||||||
|
@SerializedName("nc_chapter_id")
|
||||||
|
val ncChapterId: String,
|
||||||
|
@SerializedName("nc_chapter_name")
|
||||||
|
val ncChapterName: String,
|
||||||
|
@SerializedName("nc_chapter_no")
|
||||||
|
val ncChapterNo: String,
|
||||||
|
@SerializedName("nc_created_date")
|
||||||
|
val ncCreatedDate: String,
|
||||||
|
@SerializedName("nc_provider")
|
||||||
|
val ncProvider: String,
|
||||||
|
@SerializedName("no_new_chapter")
|
||||||
|
val noNewChapter: String,
|
||||||
|
@SerializedName("np_group_dir")
|
||||||
|
val npGroupDir: String,
|
||||||
|
@SerializedName("np_name")
|
||||||
|
val npName: String,
|
||||||
|
@SerializedName("np_name_link")
|
||||||
|
val npNameLink: String,
|
||||||
|
@SerializedName("np_project_id")
|
||||||
|
val npProjectId: String
|
||||||
|
)
|
|
@ -0,0 +1,10 @@
|
||||||
|
package eu.kanade.tachiyomi.extension.th.nekopost.model
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
|
||||||
|
data class RawProjectSummaryList(
|
||||||
|
@SerializedName("code")
|
||||||
|
val code: String,
|
||||||
|
@SerializedName("listItem")
|
||||||
|
val listItem: List<RawProjectSummary>?
|
||||||
|
)
|
Loading…
Reference in New Issue