Remove NetComics (#7167)
This commit is contained in:
parent
e12546007e
commit
9f62ebd9a3
|
@ -1,8 +0,0 @@
|
||||||
ext {
|
|
||||||
extName = 'NETCOMICS'
|
|
||||||
extClass = '.NetcomicsFactory'
|
|
||||||
extVersionCode = 3
|
|
||||||
isNsfw = true
|
|
||||||
}
|
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
|
Binary file not shown.
Before Width: | Height: | Size: 9.5 KiB |
Binary file not shown.
Before Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
Before Width: | Height: | Size: 14 KiB |
Binary file not shown.
Before Width: | Height: | Size: 26 KiB |
Binary file not shown.
Before Width: | Height: | Size: 38 KiB |
|
@ -1,23 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.netcomics
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
|
||||||
|
|
||||||
internal class GenreFilter(
|
|
||||||
values: Array<String> = genres,
|
|
||||||
) : Filter.Select<String>("Genre", values) {
|
|
||||||
override fun toString() = if (state == 0) "" else values[state]
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
internal val NOTE = Header("NOTE: can't be used with text search!")
|
|
||||||
|
|
||||||
private val genres = arrayOf(
|
|
||||||
"All",
|
|
||||||
"BL",
|
|
||||||
"Action",
|
|
||||||
"Comedy",
|
|
||||||
"Romance",
|
|
||||||
"Thriller",
|
|
||||||
"Drama",
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,265 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.netcomics
|
|
||||||
|
|
||||||
import android.app.Application
|
|
||||||
import androidx.preference.EditTextPreference
|
|
||||||
import androidx.preference.ListPreference
|
|
||||||
import androidx.preference.PreferenceScreen
|
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.asObservable
|
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
||||||
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 kotlinx.serialization.json.Json
|
|
||||||
import kotlinx.serialization.json.decodeFromJsonElement
|
|
||||||
import kotlinx.serialization.json.jsonObject
|
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
|
||||||
import okhttp3.HttpUrl
|
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
|
||||||
import okhttp3.Response
|
|
||||||
import uy.kohesive.injekt.Injekt
|
|
||||||
import uy.kohesive.injekt.api.get
|
|
||||||
import java.util.Calendar
|
|
||||||
|
|
||||||
class Netcomics(
|
|
||||||
override val lang: String,
|
|
||||||
private val site: String,
|
|
||||||
) : ConfigurableSource, HttpSource() {
|
|
||||||
override val name = "NETCOMICS"
|
|
||||||
|
|
||||||
override val baseUrl = "https://www.netcomics.com"
|
|
||||||
|
|
||||||
override val supportsLatest = true
|
|
||||||
|
|
||||||
private val json by lazy { Injekt.get<Json>() }
|
|
||||||
|
|
||||||
private val preferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)!!
|
|
||||||
}
|
|
||||||
|
|
||||||
private val adult by lazy {
|
|
||||||
if (preferences.getBoolean("18+", false)) "Y" else "N"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val token by lazy {
|
|
||||||
preferences.getString("token", "")!!
|
|
||||||
}
|
|
||||||
|
|
||||||
private val quality by lazy {
|
|
||||||
preferences.getString("quality", "625")!!
|
|
||||||
}
|
|
||||||
|
|
||||||
private val did by lazy {
|
|
||||||
System.currentTimeMillis().toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val apiUrl by lazy { API_URL.toHttpUrl() }
|
|
||||||
|
|
||||||
private val apiHeaders by lazy {
|
|
||||||
headers.newBuilder()
|
|
||||||
.set("Origin", baseUrl)
|
|
||||||
.set("platform", "android")
|
|
||||||
.set("adult", adult)
|
|
||||||
.set("token", token)
|
|
||||||
.set("site", site)
|
|
||||||
.set("did", did)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val day by lazy {
|
|
||||||
when (Calendar.getInstance()[Calendar.DAY_OF_WEEK]) {
|
|
||||||
Calendar.MONDAY -> "1"
|
|
||||||
Calendar.TUESDAY -> "2"
|
|
||||||
Calendar.WEDNESDAY -> "3"
|
|
||||||
Calendar.THURSDAY -> "4"
|
|
||||||
Calendar.FRIDAY -> "5"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun searchMangaParse(response: Response) =
|
|
||||||
response.data<List<Title>>().ifEmpty {
|
|
||||||
error("No more pages")
|
|
||||||
}.map {
|
|
||||||
SManga.create().apply {
|
|
||||||
url = it.slug
|
|
||||||
title = it.toString()
|
|
||||||
genre = it.genres
|
|
||||||
author = it.authors
|
|
||||||
artist = it.artists
|
|
||||||
description = it.description
|
|
||||||
thumbnail_url = it.thumbnail
|
|
||||||
status = when {
|
|
||||||
it.isCompleted -> SManga.COMPLETED
|
|
||||||
else -> SManga.ONGOING
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}.run { MangasPage(this, size == 20) }
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response) =
|
|
||||||
response.data<List<Chapter>>().map {
|
|
||||||
SChapter.create().apply {
|
|
||||||
url = it.path
|
|
||||||
name = it.toString()
|
|
||||||
date_upload = it.timestamp
|
|
||||||
chapter_number = it.number
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun pageListParse(response: Response) =
|
|
||||||
response.data<PageList>().map {
|
|
||||||
Page(it.seq, "", it.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchLatestUpdates(page: Int) =
|
|
||||||
apiUrl.fetch("title", ::searchMangaParse) {
|
|
||||||
addEncodedPathSegment("new")
|
|
||||||
addEncodedQueryParameter("no", page.toString())
|
|
||||||
addEncodedQueryParameter("size", "20")
|
|
||||||
addEncodedQueryParameter("day", day)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchPopularManga(page: Int) =
|
|
||||||
apiUrl.fetch("title", ::searchMangaParse) {
|
|
||||||
addEncodedPathSegment("free")
|
|
||||||
addEncodedQueryParameter("no", page.toString())
|
|
||||||
addEncodedQueryParameter("size", "20")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList) =
|
|
||||||
apiUrl.fetch("title", ::searchMangaParse) {
|
|
||||||
if (query.isNotBlank()) {
|
|
||||||
addEncodedPathSegments("search/text")
|
|
||||||
addQueryParameter("text", query)
|
|
||||||
} else {
|
|
||||||
addEncodedPathSegment("genre")
|
|
||||||
addQueryParameter("genre", filters.genre)
|
|
||||||
}
|
|
||||||
addEncodedQueryParameter("no", page.toString())
|
|
||||||
addEncodedQueryParameter("size", "20")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchMangaDetails(manga: SManga) =
|
|
||||||
rx.Observable.just(manga.apply { initialized = true })!!
|
|
||||||
|
|
||||||
override fun fetchChapterList(manga: SManga) =
|
|
||||||
apiUrl.fetch("chapter", ::chapterListParse) {
|
|
||||||
addEncodedPathSegment("list")
|
|
||||||
addEncodedPathSegment(manga.id)
|
|
||||||
addEncodedPathSegment("rent")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun fetchPageList(chapter: SChapter) =
|
|
||||||
apiUrl.fetch("chapter", ::pageListParse) {
|
|
||||||
addEncodedPathSegment("viewer")
|
|
||||||
addEncodedPathSegment(quality)
|
|
||||||
addEncodedPathSegments(chapter.url)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMangaUrl(manga: SManga) =
|
|
||||||
"$baseUrl/$site/comic/${manga.slug}"
|
|
||||||
|
|
||||||
override fun getChapterUrl(chapter: SChapter) =
|
|
||||||
"$baseUrl/viewer/${chapter.url}"
|
|
||||||
|
|
||||||
override fun getFilterList() =
|
|
||||||
FilterList(GenreFilter.NOTE, GenreFilter())
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
|
||||||
SwitchPreferenceCompat(screen.context).apply {
|
|
||||||
key = "18+"
|
|
||||||
title = "Show 18+"
|
|
||||||
summaryOff = "18+ OFF"
|
|
||||||
summaryOn = "18+ ON"
|
|
||||||
setDefaultValue(false)
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
preferences.edit().putBoolean(key, newValue as Boolean).commit()
|
|
||||||
}
|
|
||||||
}.let(screen::addPreference)
|
|
||||||
|
|
||||||
// TODO: grab from the webview somehow
|
|
||||||
EditTextPreference(screen.context).apply {
|
|
||||||
key = "token"
|
|
||||||
title = "API key"
|
|
||||||
dialogTitle = "localStorage['ncx.user.token']"
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
preferences.edit().putString(key, newValue as String).commit()
|
|
||||||
}
|
|
||||||
}.let(screen::addPreference)
|
|
||||||
|
|
||||||
ListPreference(screen.context).apply {
|
|
||||||
key = "quality"
|
|
||||||
title = "Image quality"
|
|
||||||
summary = "%s"
|
|
||||||
entries = arrayOf("HD", "Medium")
|
|
||||||
entryValues = arrayOf("1024", "625")
|
|
||||||
setDefaultValue("625")
|
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
|
||||||
preferences.edit().putString(key, newValue as String).commit()
|
|
||||||
}
|
|
||||||
}.let(screen::addPreference)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun latestUpdatesParse(response: Response) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response) =
|
|
||||||
throw UnsupportedOperationException()
|
|
||||||
|
|
||||||
private inline val SManga.slug: String
|
|
||||||
get() = url.substringBefore('|')
|
|
||||||
|
|
||||||
private inline val SManga.id: String
|
|
||||||
get() = url.substringAfter('|')
|
|
||||||
|
|
||||||
private inline val FilterList.genre: String
|
|
||||||
get() = find { it is GenreFilter }?.toString() ?: ""
|
|
||||||
|
|
||||||
private inline fun <reified T> Response.data() =
|
|
||||||
json.decodeFromJsonElement<T>(
|
|
||||||
json.parseToJsonElement(body.string()).run {
|
|
||||||
jsonObject["data"] ?: throw Error(
|
|
||||||
jsonObject["message"]!!.jsonPrimitive.content,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
private inline fun <R> HttpUrl.fetch(
|
|
||||||
path: String,
|
|
||||||
noinline parse: (Response) -> R,
|
|
||||||
block: HttpUrl.Builder.() -> HttpUrl.Builder,
|
|
||||||
) = newBuilder().addEncodedPathSegment(path).let(block).run {
|
|
||||||
client.newCall(GET(build(), apiHeaders)).asObservable().map(parse)!!
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,103 +0,0 @@
|
||||||
@file:Suppress("PrivatePropertyName")
|
|
||||||
|
|
||||||
package eu.kanade.tachiyomi.extension.all.netcomics
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
|
|
||||||
internal const val API_URL = "https://beta-api.netcomics.com/api/v1"
|
|
||||||
|
|
||||||
private const val CDN_URL =
|
|
||||||
"https://cdn.netcomics.com/img/fill/324/0/sm/0/plain/s3://"
|
|
||||||
|
|
||||||
private val isoDate by lazy {
|
|
||||||
SimpleDateFormat("yyyy-MM-d'T'HH:mm:ss.SSS'Z'", Locale.ROOT)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Title(
|
|
||||||
private val title_id: Int,
|
|
||||||
private val site: String,
|
|
||||||
private val title_name: String,
|
|
||||||
private val title_slug: String,
|
|
||||||
private val story: String,
|
|
||||||
private val genre: String,
|
|
||||||
private val age_grade: String,
|
|
||||||
private val is_end: String,
|
|
||||||
private val v_cover_img: String,
|
|
||||||
private val author_story_arr: List<Author>,
|
|
||||||
private val author_picture_arr: List<Author>,
|
|
||||||
private val author_origin_arr: List<Author>,
|
|
||||||
) {
|
|
||||||
val slug: String
|
|
||||||
get() = "$title_slug|$title_id"
|
|
||||||
|
|
||||||
val description: String?
|
|
||||||
get() = Jsoup.parse(story).text()
|
|
||||||
|
|
||||||
val thumbnail: String
|
|
||||||
get() = CDN_URL + v_cover_img
|
|
||||||
|
|
||||||
val genres: String
|
|
||||||
get() = "$genre, $age_grade+"
|
|
||||||
|
|
||||||
val authors: String
|
|
||||||
get() = (author_story_arr + author_origin_arr).names
|
|
||||||
|
|
||||||
val artists: String
|
|
||||||
get() = author_picture_arr.names
|
|
||||||
|
|
||||||
val isCompleted: Boolean
|
|
||||||
get() = is_end == "Y"
|
|
||||||
|
|
||||||
override fun toString() = title_name
|
|
||||||
|
|
||||||
private inline val List<Author>.names: String
|
|
||||||
get() = joinToString { if (site == "KR") it.text else it.text_en }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Author(val text: String, val text_en: String)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Chapter(
|
|
||||||
private val chapter_id: Int,
|
|
||||||
private val chapter_no: Int,
|
|
||||||
private val chapter_name: String,
|
|
||||||
private val created_at: String,
|
|
||||||
private val title_id: Int,
|
|
||||||
private val is_free: String,
|
|
||||||
private val is_order: String? = null,
|
|
||||||
) {
|
|
||||||
val path: String
|
|
||||||
get() = "$title_id/$chapter_id"
|
|
||||||
|
|
||||||
val number: Float
|
|
||||||
get() = chapter_no.toFloat()
|
|
||||||
|
|
||||||
val timestamp: Long
|
|
||||||
get() = isoDate.parse(created_at)?.time ?: 0L
|
|
||||||
|
|
||||||
private inline val isLocked: Boolean
|
|
||||||
get() = is_free == "N" && is_order != "Y"
|
|
||||||
|
|
||||||
override fun toString() = buildString {
|
|
||||||
if (chapter_name.isEmpty()) {
|
|
||||||
append("Ch.")
|
|
||||||
append(chapter_no)
|
|
||||||
} else {
|
|
||||||
append(chapter_name)
|
|
||||||
}
|
|
||||||
if (isLocked) append(" \uD83D\uDD12")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PageList(private val images: List<Image>) : List<Image> by images
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Image(val seq: Int, private val image_url: String) {
|
|
||||||
override fun toString() = image_url
|
|
||||||
}
|
|
|
@ -1,18 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.netcomics
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
|
||||||
|
|
||||||
class NetcomicsFactory : SourceFactory {
|
|
||||||
override fun createSources() = listOf(
|
|
||||||
Netcomics("en", "EN"),
|
|
||||||
Netcomics("ja", "JA"),
|
|
||||||
Netcomics("zh", "CN"),
|
|
||||||
Netcomics("ko", "KO"),
|
|
||||||
Netcomics("es", "ES"),
|
|
||||||
Netcomics("fr", "FR"),
|
|
||||||
Netcomics("de", "DE"),
|
|
||||||
Netcomics("id", "ID"),
|
|
||||||
Netcomics("vi", "VI"),
|
|
||||||
Netcomics("th", "TH"),
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in New Issue