mirror of
https://github.com/keiyoushi/extensions-source.git
synced 2024-11-25 11:42:47 +01:00
Improve Luminous Scans Functionality (Permanent URLs) (#44)
This commit is contained in:
parent
69f97415b7
commit
2ef685d0b3
@ -1,10 +1,235 @@
|
||||
package eu.kanade.tachiyomi.extension.en.luminousscans
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import rx.Observable
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.io.IOException
|
||||
|
||||
class LuminousScans : MangaThemesia("Luminous Scans", "https://luminousscans.net", "en", mangaUrlDirectory = "/series") {
|
||||
override val client = super.client.newBuilder()
|
||||
.addInterceptor(::urlChangeInterceptor)
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
|
||||
private val preferences by lazy {
|
||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
// Permanent Url for Manga/Chapter End
|
||||
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||
return super.fetchPopularManga(page).tempUrlToPermIfNeeded()
|
||||
}
|
||||
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||
return super.fetchLatestUpdates(page).tempUrlToPermIfNeeded()
|
||||
}
|
||||
|
||||
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
|
||||
return super.fetchSearchManga(page, query, filters).tempUrlToPermIfNeeded()
|
||||
}
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val request = super.searchMangaRequest(page, query, filters)
|
||||
if (query.isBlank()) return request
|
||||
|
||||
val url = request.url.newBuilder()
|
||||
.addPathSegment("page/$page/")
|
||||
.removeAllQueryParameters("page")
|
||||
.removeAllQueryParameters("title")
|
||||
.addQueryParameter("s", query)
|
||||
.build()
|
||||
|
||||
return request.newBuilder()
|
||||
.url(url)
|
||||
.build()
|
||||
}
|
||||
|
||||
// Temp Url for manga/chapter
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
val newManga = manga.titleToUrlFrag()
|
||||
|
||||
return super.fetchChapterList(newManga)
|
||||
}
|
||||
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
val newManga = manga.titleToUrlFrag()
|
||||
|
||||
return super.fetchMangaDetails(newManga)
|
||||
}
|
||||
|
||||
override fun getMangaUrl(manga: SManga): String {
|
||||
val dbSlug = manga.url
|
||||
.substringBefore("#")
|
||||
.removeSuffix("/")
|
||||
.substringAfterLast("/")
|
||||
|
||||
val storedSlug = preferences.slugMap[dbSlug] ?: dbSlug
|
||||
|
||||
return "$baseUrl$mangaUrlDirectory/$storedSlug/"
|
||||
}
|
||||
|
||||
private fun Observable<MangasPage>.tempUrlToPermIfNeeded(): Observable<MangasPage> {
|
||||
return this.map { mangasPage ->
|
||||
MangasPage(
|
||||
mangasPage.mangas.map { it.tempUrlToPermIfNeeded() },
|
||||
mangasPage.hasNextPage,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun SManga.tempUrlToPermIfNeeded(): SManga {
|
||||
if (!preferences.permaUrlPref) return this
|
||||
|
||||
val slugMap = preferences.slugMap
|
||||
|
||||
val sMangaTitleFirstWord = this.title.split(" ")[0]
|
||||
if (!this.url.contains("/$sMangaTitleFirstWord", ignoreCase = true)) {
|
||||
val currentSlug = this.url
|
||||
.removeSuffix("/")
|
||||
.substringAfterLast("/")
|
||||
|
||||
val permaSlug = currentSlug.replaceFirst(TEMP_TO_PERM_REGEX, "")
|
||||
|
||||
slugMap[permaSlug] = currentSlug
|
||||
|
||||
this.url = "$mangaUrlDirectory/$permaSlug/"
|
||||
}
|
||||
preferences.slugMap = slugMap
|
||||
return this
|
||||
}
|
||||
|
||||
private fun SManga.titleToUrlFrag(): SManga {
|
||||
return try {
|
||||
this.apply {
|
||||
url = "$url#${title.toSearchQuery()}"
|
||||
}
|
||||
} catch (e: UninitializedPropertyAccessException) {
|
||||
// when called from deep link, title is not present
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
private fun urlChangeInterceptor(chain: Interceptor.Chain): Response {
|
||||
val request = chain.request()
|
||||
|
||||
val frag = request.url.fragment
|
||||
|
||||
if (frag.isNullOrEmpty()) {
|
||||
return chain.proceed(request)
|
||||
}
|
||||
|
||||
val dbSlug = request.url.toString()
|
||||
.substringBefore("#")
|
||||
.removeSuffix("/")
|
||||
.substringAfterLast("/")
|
||||
|
||||
val slugMap = preferences.slugMap
|
||||
|
||||
val storedSlug = slugMap[dbSlug] ?: dbSlug
|
||||
|
||||
val response = chain.proceed(
|
||||
request.newBuilder()
|
||||
.url("$baseUrl$mangaUrlDirectory/$storedSlug/")
|
||||
.build(),
|
||||
)
|
||||
|
||||
if (!response.isSuccessful && response.code == 404) {
|
||||
response.close()
|
||||
|
||||
val newSlug = getNewSlug(storedSlug, frag)
|
||||
?: throw IOException("Migrate from Luminous to Luminous")
|
||||
|
||||
slugMap[dbSlug] = newSlug
|
||||
preferences.slugMap = slugMap
|
||||
|
||||
return chain.proceed(
|
||||
request.newBuilder()
|
||||
.url("$baseUrl$mangaUrlDirectory/$newSlug/")
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
private fun getNewSlug(existingSlug: String, frag: String): String? {
|
||||
val permaSlug = existingSlug
|
||||
.replaceFirst(TEMP_TO_PERM_REGEX, "")
|
||||
|
||||
val search = frag.substringBefore("#")
|
||||
|
||||
val mangas = client.newCall(searchMangaRequest(1, search, FilterList()))
|
||||
.execute()
|
||||
.use {
|
||||
searchMangaParse(it)
|
||||
}
|
||||
|
||||
return mangas.mangas.firstOrNull { newManga ->
|
||||
newManga.url.contains(permaSlug, true)
|
||||
}
|
||||
?.url
|
||||
?.removeSuffix("/")
|
||||
?.substringAfterLast("/")
|
||||
}
|
||||
|
||||
private fun String.toSearchQuery(): String {
|
||||
return this.trim()
|
||||
.lowercase()
|
||||
.replace(titleSpecialCharactersRegex, "+")
|
||||
.replace(trailingPlusRegex, "")
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_PERM_MANGA_URL_KEY_PREFIX + lang
|
||||
title = PREF_PERM_MANGA_URL_TITLE
|
||||
summary = PREF_PERM_MANGA_URL_SUMMARY
|
||||
setDefaultValue(true)
|
||||
}.also(screen::addPreference)
|
||||
|
||||
super.setupPreferenceScreen(screen)
|
||||
}
|
||||
|
||||
private val SharedPreferences.permaUrlPref
|
||||
get() = getBoolean(PREF_PERM_MANGA_URL_KEY_PREFIX + lang, true)
|
||||
|
||||
private var SharedPreferences.slugMap: MutableMap<String, String>
|
||||
get() {
|
||||
val serialized = getString(PREF_URL_MAP, null) ?: return mutableMapOf()
|
||||
|
||||
return try {
|
||||
json.decodeFromString(serialized)
|
||||
} catch (e: Exception) {
|
||||
mutableMapOf()
|
||||
}
|
||||
}
|
||||
set(slugMap) {
|
||||
val serialized = json.encodeToString(slugMap)
|
||||
edit().putString(PREF_URL_MAP, serialized).commit()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val PREF_PERM_MANGA_URL_KEY_PREFIX = "pref_permanent_manga_url_2_"
|
||||
private const val PREF_PERM_MANGA_URL_TITLE = "Permanent Manga URL"
|
||||
private const val PREF_PERM_MANGA_URL_SUMMARY = "Turns all manga urls into permanent ones."
|
||||
private const val PREF_URL_MAP = "pref_url_map"
|
||||
private val TEMP_TO_PERM_REGEX = Regex("""^\d+-""")
|
||||
private val titleSpecialCharactersRegex = Regex("""[^a-z0-9]+""")
|
||||
private val trailingPlusRegex = Regex("""\++$""")
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ class MangaThemesiaGenerator : ThemeSourceGenerator {
|
||||
SingleLang("Legacy Scans", "https://legacy-scans.com", "fr", pkgName = "flamescansfr"),
|
||||
SingleLang("Lelmanga", "https://www.lelmanga.com", "fr"),
|
||||
SingleLang("LianScans", "https://www.lianscans.my.id", "id", isNsfw = true),
|
||||
SingleLang("Luminous Scans", "https://luminousscans.net", "en"),
|
||||
SingleLang("Luminous Scans", "https://luminousscans.net", "en", overrideVersionCode = 1),
|
||||
SingleLang("Lunar Scans", "https://lunarscan.org", "en", isNsfw = true, overrideVersionCode = 1),
|
||||
SingleLang("LynxScans", "https://lynxscans.com", "en"),
|
||||
SingleLang("Lyra Scans", "https://lyrascans.com", "en"),
|
||||
|
Loading…
Reference in New Issue
Block a user