diff --git a/src/all/netcomics/build.gradle b/src/all/netcomics/build.gradle deleted file mode 100644 index ca30f6d45..000000000 --- a/src/all/netcomics/build.gradle +++ /dev/null @@ -1,8 +0,0 @@ -ext { - extName = 'NETCOMICS' - extClass = '.NetcomicsFactory' - extVersionCode = 3 - isNsfw = true -} - -apply from: "$rootDir/common.gradle" diff --git a/src/all/netcomics/res/mipmap-hdpi/ic_launcher.png b/src/all/netcomics/res/mipmap-hdpi/ic_launcher.png deleted file mode 100644 index cab06b68e..000000000 Binary files a/src/all/netcomics/res/mipmap-hdpi/ic_launcher.png and /dev/null differ diff --git a/src/all/netcomics/res/mipmap-mdpi/ic_launcher.png b/src/all/netcomics/res/mipmap-mdpi/ic_launcher.png deleted file mode 100644 index ebb334fce..000000000 Binary files a/src/all/netcomics/res/mipmap-mdpi/ic_launcher.png and /dev/null differ diff --git a/src/all/netcomics/res/mipmap-xhdpi/ic_launcher.png b/src/all/netcomics/res/mipmap-xhdpi/ic_launcher.png deleted file mode 100644 index 45d5f283e..000000000 Binary files a/src/all/netcomics/res/mipmap-xhdpi/ic_launcher.png and /dev/null differ diff --git a/src/all/netcomics/res/mipmap-xxhdpi/ic_launcher.png b/src/all/netcomics/res/mipmap-xxhdpi/ic_launcher.png deleted file mode 100644 index 3d518758d..000000000 Binary files a/src/all/netcomics/res/mipmap-xxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/all/netcomics/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/netcomics/res/mipmap-xxxhdpi/ic_launcher.png deleted file mode 100644 index 3ef0eaa15..000000000 Binary files a/src/all/netcomics/res/mipmap-xxxhdpi/ic_launcher.png and /dev/null differ diff --git a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/GenreFilter.kt b/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/GenreFilter.kt deleted file mode 100644 index 4e5c0932e..000000000 --- a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/GenreFilter.kt +++ /dev/null @@ -1,23 +0,0 @@ -package eu.kanade.tachiyomi.extension.all.netcomics - -import eu.kanade.tachiyomi.source.model.Filter - -internal class GenreFilter( - values: Array = genres, -) : Filter.Select("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", - ) - } -} diff --git a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/Netcomics.kt b/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/Netcomics.kt deleted file mode 100644 index d19a7d527..000000000 --- a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/Netcomics.kt +++ /dev/null @@ -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() } - - private val preferences by lazy { - Injekt.get().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>().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>().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().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 Response.data() = - json.decodeFromJsonElement( - json.parseToJsonElement(body.string()).run { - jsonObject["data"] ?: throw Error( - jsonObject["message"]!!.jsonPrimitive.content, - ) - }, - ) - - private inline fun 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)!! - } -} diff --git a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/NetcomicsAPI.kt b/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/NetcomicsAPI.kt deleted file mode 100644 index cf72bbcd0..000000000 --- a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/NetcomicsAPI.kt +++ /dev/null @@ -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, - private val author_picture_arr: List, - private val author_origin_arr: List, -) { - 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.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) : List by images - -@Serializable -data class Image(val seq: Int, private val image_url: String) { - override fun toString() = image_url -} diff --git a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/NetcomicsFactory.kt b/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/NetcomicsFactory.kt deleted file mode 100644 index d0163e3df..000000000 --- a/src/all/netcomics/src/eu/kanade/tachiyomi/extension/all/netcomics/NetcomicsFactory.kt +++ /dev/null @@ -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"), - ) -}