Yeet Neox for good. (#12695)

This commit is contained in:
Alessandro Jean 2022-07-22 19:33:16 -03:00 committed by GitHub
parent 3ff93b4d09
commit 69aec03657
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1 additions and 292 deletions

View File

@ -35,7 +35,7 @@ jobs:
}, },
{ {
"type": "both", "type": "both",
"regex": ".*(mangago|mangafox|hq\\s*dragon|manga\\s*host|supermangas|superhentais|union\\s*mangas|yes\\s*mangas|manhuascan|heroscan|manhwahot|leitor\\.?net|manga\\s*livre|tsuki\\s*mangas|manga\\s*yabu|mangas\\.in|mangas\\.pw|hentaikai|toptoon\\+?|read\\s*comic\\s*online|coco\\s*manhua|hitomi\\.la|copymanga).*", "regex": ".*(mangago|mangafox|hq\\s*dragon|manga\\s*host|supermangas|superhentais|union\\s*mangas|yes\\s*mangas|manhuascan|heroscan|manhwahot|leitor\\.?net|manga\\s*livre|tsuki\\s*mangas|manga\\s*yabu|mangas\\.in|mangas\\.pw|hentaikai|toptoon\\+?|read\\s*comic\\s*online|coco\\s*manhua|hitomi\\.la|copymanga|neox).*",
"ignoreCase": true, "ignoreCase": true,
"message": "{match} will not be added back as it is too difficult to maintain. Read #3475 for more information" "message": "{match} will not be added back as it is too difficult to maintain. Read #3475 for more information"
}, },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

View File

@ -1,290 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.neoxscanlator
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.AppInfo
import eu.kanade.tachiyomi.multisrc.madara.Madara
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservable
import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.ConfigurableSource
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 kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Call
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.UUID
import java.util.concurrent.TimeUnit
import kotlin.Exception
class NeoxScanlator :
Madara(
"Neox Scanlator",
DEFAULT_BASE_URL,
"pt-BR",
SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR"))
),
ConfigurableSource {
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.addInterceptor(::titleCollectionIntercept)
.addInterceptor(::obsoleteCheckIntercept)
.rateLimit(1, 2, TimeUnit.SECONDS)
.build()
override val altNameSelector = ".post-content_item:contains(Alternativo) .summary-content"
override val chapterUrlSelector = "a:not(:has(img.thumb))"
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override val baseUrl: String by lazy {
preferences.getString(BASE_URL_PREF_KEY, DEFAULT_BASE_URL)!!
}
private var titleCollectionPath: String? = null
private var extIsObsolete: Boolean? = null
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
.add("Accept", ACCEPT)
.add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", REFERER)
override fun popularMangaParse(response: Response): MangasPage {
val popularPage = super.popularMangaParse(response)
titleCollectionPath = popularPage.mangas.firstOrNull()?.url
?.removePrefix("/")
?.removeSuffix("/")
?.substringBeforeLast("/")
return popularPage
}
override fun latestUpdatesParse(response: Response): MangasPage {
val latestPage = super.latestUpdatesParse(response)
titleCollectionPath = latestPage.mangas.firstOrNull()?.url
?.removePrefix("/")
?.removeSuffix("/")
?.substringBeforeLast("/")
return latestPage
}
override fun searchMangaParse(response: Response): MangasPage {
val searchPage = super.searchMangaParse(response)
titleCollectionPath = searchPage.mangas.firstOrNull()?.url
?.removePrefix("/")
?.removeSuffix("/")
?.substringBeforeLast("/")
return searchPage
}
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsRequest(manga))
.asCustomObservable()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
override fun mangaDetailsRequest(manga: SManga): Request {
val titleSlug = manga.url
.removeSuffix("/")
.substringAfterLast("/")
val fixedPath = titleCollectionPath ?: TITLE_PATH_PLACEHOLDER
return GET("$baseUrl/$fixedPath/$titleSlug", headers)
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return client.newCall(chapterListRequest(manga))
.asCustomObservable()
.map(::chapterListParse)
}
override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
override fun xhrChaptersRequest(mangaUrl: String): Request {
val xhrHeaders = headersBuilder()
.add("Referer", baseUrl)
.add("X-Requested-With", "XMLHttpRequest")
.build()
val titleSlug = mangaUrl
.substringAfter(baseUrl)
.removeSuffix("/")
.substringAfterLast("/")
val fixedPath = titleCollectionPath ?: TITLE_PATH_PLACEHOLDER
return POST("$baseUrl/$fixedPath/$titleSlug/ajax/chapters", xhrHeaders)
}
override fun pageListRequest(chapter: SChapter): Request {
val chapterUrl = chapter.url.toHttpUrlOrNull()
?: return super.pageListRequest(chapter)
val chapterSlug = chapterUrl.pathSegments
.takeLast(3)
.joinToString("/")
val fixedPath = titleCollectionPath ?: TITLE_PATH_PLACEHOLDER
return GET("$baseUrl/$fixedPath/$chapterSlug", headers)
}
override fun imageRequest(page: Page): Request {
val newHeaders = headersBuilder()
.set("Accept", ACCEPT_IMAGE)
.set("Referer", page.url)
.build()
return GET(page.imageUrl!!, newHeaders)
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val baseUrlPref = EditTextPreference(screen.context).apply {
key = BASE_URL_PREF_KEY
title = BASE_URL_PREF_TITLE
summary = BASE_URL_PREF_SUMMARY
setDefaultValue(DEFAULT_BASE_URL)
dialogTitle = BASE_URL_PREF_TITLE
dialogMessage = "Padrão: $DEFAULT_BASE_URL"
setOnPreferenceChangeListener { _, newValue ->
try {
val res = preferences.edit()
.putString(BASE_URL_PREF_KEY, newValue as String)
.commit()
Toast.makeText(screen.context, RESTART_TACHIYOMI, Toast.LENGTH_LONG).show()
res
} catch (e: Exception) {
e.printStackTrace()
false
}
}
}
screen.addPreference(baseUrlPref)
}
private fun titleCollectionIntercept(chain: Interceptor.Chain): Response {
val request = chain.request()
if (!request.url.toString().contains(TITLE_PATH_PLACEHOLDER)) {
return chain.proceed(request)
}
val titlePathResult = runCatching {
val popularResponse = chain.proceed(popularMangaRequest(1))
val popularPage = popularMangaParse(popularResponse)
popularPage.mangas.firstOrNull()?.url
?.removePrefix("/")
?.removeSuffix("/")
?.substringBeforeLast("/")
}
titleCollectionPath = titlePathResult.getOrNull()
val fixedUrl = request.url.toString()
.replace(TITLE_PATH_PLACEHOLDER, titleCollectionPath ?: "manga")
val fixedRequest = request.newBuilder()
.url(fixedUrl)
.build()
return chain.proceed(fixedRequest)
}
private fun obsoleteCheckIntercept(chain: Interceptor.Chain): Response {
if (extIsObsolete == null) {
val repoRequest = GET(EXT_REPO_JSON)
val repoResponse = chain.proceed(repoRequest)
val repoJson = json.parseToJsonElement(repoResponse.body!!.string()).jsonArray
val extDetails = repoJson.firstOrNull { it.jsonObject["pkg"]!!.jsonPrimitive.content == EXT_PKG }
extIsObsolete = extDetails == null
repoResponse.close()
}
if (extIsObsolete == true) {
throw IOException(OBSOLETE_ERROR)
}
return chain.proceed(chain.request())
}
private fun Call.asCustomObservable(): Observable<Response> {
return asObservable().doOnNext { response ->
if (!response.isSuccessful) {
response.close()
val message = if (response.code == 404 || response.code == 403)
MIGRATION_MESSAGE else "HTTP error ${response.code}"
throw Exception(message)
}
if (response.request.url.toString() == "$baseUrl/" && response.code == 200) {
response.close()
throw Exception(MIGRATION_MESSAGE)
}
if (!response.headers["Content-Type"]!!.contains("text/html")) {
response.close()
throw Exception(MIGRATION_MESSAGE)
}
}
}
companion object {
private const val MIGRATION_MESSAGE = "A URL deste título mudou. " +
"Faça a migração da Neox para a Neox para atualizar a URL."
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
"image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
private const val ACCEPT_IMAGE = "image/webp,image/apng,image/*,*/*;q=0.8"
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
private const val REFERER = "https://google.com/"
private const val DEFAULT_BASE_URL = "https://neoxscans.net"
private val BASE_URL_PREF_KEY = "base_url_${AppInfo.getVersionName()}"
private const val BASE_URL_PREF_TITLE = "URL da fonte"
private const val BASE_URL_PREF_SUMMARY = "Para uso temporário. Quando você atualizar a " +
"extensão, esta configuração será apagada."
private const val RESTART_TACHIYOMI = "Reinicie o Tachiyomi para aplicar as configurações."
private val TITLE_PATH_PLACEHOLDER = UUID.randomUUID().toString()
private const val EXT_REPO_JSON = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/index.json"
private const val EXT_PKG = "eu.kanade.tachiyomi.extension.pt.neoxscanlator"
private const val OBSOLETE_ERROR = "Extensão obsoleta. Migre para fontes melhores."
}
}

View File

@ -367,7 +367,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("NeatManga", "https://neatmanga.com", "en", overrideVersionCode = 2), SingleLang("NeatManga", "https://neatmanga.com", "en", overrideVersionCode = 2),
SingleLang("NekoBreaker Scan", "https://nekobreakerscan.com", "pt-BR", overrideVersionCode = 1), SingleLang("NekoBreaker Scan", "https://nekobreakerscan.com", "pt-BR", overrideVersionCode = 1),
SingleLang("NekoScan", "https://nekoscan.com", "en", overrideVersionCode = 2), SingleLang("NekoScan", "https://nekoscan.com", "en", overrideVersionCode = 2),
SingleLang("Neox Scanlator", "https://neoxscans.net", "pt-BR", overrideVersionCode = 14),
SingleLang("Night Comic", "https://www.nightcomic.com", "en", overrideVersionCode = 1), SingleLang("Night Comic", "https://www.nightcomic.com", "en", overrideVersionCode = 1),
SingleLang("Niji Translations", "https://niji-translations.com", "ar", overrideVersionCode = 1), SingleLang("Niji Translations", "https://niji-translations.com", "ar", overrideVersionCode = 1),
SingleLang("Ninja Scan", "https://ninjascan.xyz", "pt-BR", overrideVersionCode = 1), SingleLang("Ninja Scan", "https://ninjascan.xyz", "pt-BR", overrideVersionCode = 1),