Add Nicomanga

This commit is contained in:
CodeSpoof 2024-01-09 18:07:44 +01:00
parent 7c2da7007f
commit 338ffc747e
10 changed files with 180 additions and 0 deletions

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View File

@ -0,0 +1,12 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Nicomanga'
pkgNameSuffix = 'ja.nicomanga'
extClass = '.Nicomanga'
extVersionCode = 1
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

View File

@ -0,0 +1,9 @@
package eu.kanade.tachiyomi.extension.ja.nicomanga
object NMRegex {
val thumbnailURLRegex: Regex = "background-image:[^;]url\\s*\\(\\s*'([^?']+)".toRegex()
val statusRegex: Regex = "(?<=-)[^.]+".toRegex()
val urlRegex: Regex = "(?<=manga-)[^/]+(?=\\.html\$)".toRegex()
val floatRegex: Regex = "\\d+(?:\\.\\d+)?".toRegex()
val chapterIdRegex: Regex = "(?<=imgsListchap\\()\\d+".toRegex()
}

View File

@ -0,0 +1,157 @@
package eu.kanade.tachiyomi.extension.ja.nicomanga
import eu.kanade.tachiyomi.extension.ja.nicomanga.NMRegex.chapterIdRegex
import eu.kanade.tachiyomi.extension.ja.nicomanga.NMRegex.floatRegex
import eu.kanade.tachiyomi.extension.ja.nicomanga.NMRegex.statusRegex
import eu.kanade.tachiyomi.extension.ja.nicomanga.NMRegex.thumbnailURLRegex
import eu.kanade.tachiyomi.extension.ja.nicomanga.NMRegex.urlRegex
import eu.kanade.tachiyomi.network.GET
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.HttpSource
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import org.jsoup.nodes.Element
import java.net.URL
class Nicomanga : HttpSource() {
override val baseUrl: String = "https://nicomanga.com"
override val lang: String = "ja"
override val name: String = "Nicomanga"
override val supportsLatest: Boolean = true
override val client: OkHttpClient = network.cloudflareClient
private fun mangaListParse(response: Response): MangasPage {
val doc = Jsoup.parse(response.body.string())
val mangaList: ArrayList<Element> = doc.select(".row > .thumb-item-flow")
val hasNextPage =
if (doc.select(".pagination li:last-of-type").size > 0 &&
doc.select(".pagination li:last-of-type")[0].text() == "»"
) {
doc.select(".pagination li:last-of-type a.disabled").size == 0
} else {
doc.select(".pagination li:last-of-type a.active").size == 0
}
val mangas = mangaList.map { manga ->
SManga.create().apply {
val relURL = manga.selectFirst(".series-title a")?.attr("href") ?: ""
setUrlWithoutDomain(URL(URL(baseUrl), relURL).toString())
title = manga.selectFirst(".series-title")?.text() ?: ""
thumbnail_url = thumbnailURLRegex.find(manga.selectFirst(".img-in-ratio.lazyloaded")?.attr("style") ?: "")?.groupValues?.get(1)
}
}
return MangasPage(mangas, hasNextPage)
}
override fun latestUpdatesParse(response: Response): MangasPage = mangaListParse(response)
override fun latestUpdatesRequest(page: Int): Request {
val url = "$baseUrl/manga-list.html".toHttpUrl().newBuilder()
.addQueryParameter("page", page.toString())
.addQueryParameter("sort", "last_update")
.addQueryParameter("sort_type", "DESC")
.build()
return GET(url)
}
override fun popularMangaParse(response: Response): MangasPage = mangaListParse(response)
override fun popularMangaRequest(page: Int): Request {
val url = "$baseUrl/manga-list.html".toHttpUrl().newBuilder()
.addQueryParameter("page", page.toString())
.addQueryParameter("sort", "views")
.addQueryParameter("sort_type", "DESC")
.build()
return GET(url)
}
override fun searchMangaParse(response: Response): MangasPage = mangaListParse(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = "$baseUrl/manga-list.html".toHttpUrl().newBuilder()
.addQueryParameter("page", page.toString())
.addQueryParameter("artist", "")
.addQueryParameter("author", "")
.addQueryParameter("group", "")
.addQueryParameter("m_status", "")
.addQueryParameter("name", query)
.addQueryParameter("genre", "")
.addQueryParameter("ungenre", "")
.addQueryParameter("magazine", "")
.addQueryParameter("sort", "last_update")
.addQueryParameter("sort_type", "DESC")
.build()
return GET(url, headers)
}
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
val doc = Jsoup.parse(response.body.string())
author = doc.select("ul.manga-info a[href^=\"manga-author\"]").joinToString { it.text() }
genre = doc.select("ul.manga-info a[href^=\"manga-list-genre\"]").joinToString { it.text() }
val statusText = statusRegex.find(doc.select(".manga-info li:has(i.fa-spinner) a").attr("href"))?.groupValues?.get(0) ?: ""
status = when (statusText) {
"on-going" -> {
SManga.ONGOING
}
"completed" -> {
SManga.COMPLETED
}
else -> {
SManga.UNKNOWN
}
}
}
override fun chapterListParse(response: Response): List<SChapter> {
val doc = Jsoup.parse(response.body.string())
val chapterList = doc.select("ul > a")
var lastNum = 0f
val chapters = chapterList.map { chapter ->
SChapter.create().apply {
name = chapter.attr("title").trim()
setUrlWithoutDomain(URL(URL(baseUrl), chapter.attr("href")).toString())
chapter_number = floatRegex.find(chapter.attr("title").trim())?.groupValues?.get(0)?.toFloat() ?: (lastNum + 0.01f)
lastNum = chapter_number
}
}
return chapters
}
override fun chapterListRequest(manga: SManga): Request {
val slug = urlRegex.find(manga.url)?.groupValues?.get(0) ?: ""
return GET("$baseUrl/app/manga/controllers/cont.Listchapterapi.php?slug=$slug")
}
override fun pageListParse(response: Response): List<Page> {
val doc = Jsoup.parse(response.body.string())
val pages = ArrayList<Page>()
// Nicovideo will refuse to serve any pages if the user has not logged in
val pageList = doc.select("img.chapter-img")
for ((i, page) in pageList.withIndex()) {
val url = page.attr("data-src")
pages.add(Page(i + 1, url, url))
}
return pages
}
override fun pageListRequest(chapter: SChapter): Request {
val r = client.newCall(GET(getChapterUrl(chapter))).execute()
val id = chapterIdRegex.find(r.body.string())?.groupValues?.get(0) ?: throw Exception("chapter-id not found")
val headers = headersBuilder().set("referer", getChapterUrl(chapter)).build()
return GET("$baseUrl/app/manga/controllers/cont.imgsList.php?cid=$id", headers)
}
override fun imageRequest(page: Page): Request {
val headers = headersBuilder().set("referer", baseUrl).build()
return GET(page.imageUrl!!, headers)
}
override fun imageUrlParse(response: Response): String =
throw UnsupportedOperationException("Not used")
}