Comick: fix new chapters delay and small refactor (#1354)
* remove chapter pagination page parameter seems to trigger some cache issue in their api * update baseUrl * data class -> class micro optimization * small refactor * remove useless interceptor * oops * mutable not needed
This commit is contained in:
parent
9fa6b8cb51
commit
9602aa5dd5
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
<activity
|
<activity
|
||||||
android:name=".all.comickfun.ComickFunUrlActivity"
|
android:name=".all.comickfun.ComickUrlActivity"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:theme="@android:style/Theme.NoDisplay">
|
android:theme="@android:style/Theme.NoDisplay">
|
||||||
|
@ -14,6 +14,7 @@
|
||||||
<category android:name="android.intent.category.BROWSABLE" />
|
<category android:name="android.intent.category.BROWSABLE" />
|
||||||
|
|
||||||
<data android:scheme="https" />
|
<data android:scheme="https" />
|
||||||
|
<data android:host="comick.io" />
|
||||||
<data android:host="comick.cc" />
|
<data android:host="comick.cc" />
|
||||||
<data android:host="comick.ink" />
|
<data android:host="comick.ink" />
|
||||||
<data android:host="comick.app" />
|
<data android:host="comick.app" />
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Comick'
|
extName = 'Comick'
|
||||||
extClass = '.ComickFunFactory'
|
extClass = '.ComickFactory'
|
||||||
extVersionCode = 41
|
extVersionCode = 42
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,19 +26,16 @@ import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import uy.kohesive.injekt.Injekt
|
import uy.kohesive.injekt.Injekt
|
||||||
import uy.kohesive.injekt.api.get
|
import uy.kohesive.injekt.api.get
|
||||||
import java.text.SimpleDateFormat
|
|
||||||
import java.util.Locale
|
|
||||||
import java.util.TimeZone
|
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
|
|
||||||
abstract class ComickFun(
|
abstract class Comick(
|
||||||
override val lang: String,
|
override val lang: String,
|
||||||
private val comickFunLang: String,
|
private val comickLang: String,
|
||||||
) : ConfigurableSource, HttpSource() {
|
) : ConfigurableSource, HttpSource() {
|
||||||
|
|
||||||
override val name = "Comick"
|
override val name = "Comick"
|
||||||
|
|
||||||
override val baseUrl = "https://comick.cc"
|
override val baseUrl = "https://comick.io"
|
||||||
|
|
||||||
private val apiUrl = "https://api.comick.fun"
|
private val apiUrl = "https://api.comick.fun"
|
||||||
|
|
||||||
|
@ -62,8 +59,9 @@ abstract class ComickFun(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
|
.newLineIgnoredGroups()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
|
@ -151,23 +149,18 @@ abstract class ComickFun(
|
||||||
private val SharedPreferences.scorePosition: String
|
private val SharedPreferences.scorePosition: String
|
||||||
get() = getString(SCORE_POSITION_PREF, SCORE_POSITION_DEFAULT) ?: SCORE_POSITION_DEFAULT
|
get() = getString(SCORE_POSITION_PREF, SCORE_POSITION_DEFAULT) ?: SCORE_POSITION_DEFAULT
|
||||||
|
|
||||||
init {
|
|
||||||
preferences.newLineIgnoredGroups()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun headersBuilder() = Headers.Builder().apply {
|
override fun headersBuilder() = Headers.Builder().apply {
|
||||||
add("Referer", "$baseUrl/")
|
add("Referer", "$baseUrl/")
|
||||||
add("User-Agent", "Tachiyomi ${System.getProperty("http.agent")}")
|
add("User-Agent", "Tachiyomi ${System.getProperty("http.agent")}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val client = network.client.newBuilder()
|
override val client = network.client.newBuilder()
|
||||||
.addInterceptor(::thumbnailIntercept)
|
|
||||||
.rateLimit(3, 1)
|
.rateLimit(3, 1)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
/** Popular Manga **/
|
/** Popular Manga **/
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
val url = "$apiUrl/v1.0/search?sort=follow&limit=$limit&page=$page&tachiyomi=true"
|
val url = "$apiUrl/v1.0/search?sort=follow&limit=$LIMIT&page=$page&tachiyomi=true"
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -175,13 +168,13 @@ abstract class ComickFun(
|
||||||
val result = response.parseAs<List<SearchManga>>()
|
val result = response.parseAs<List<SearchManga>>()
|
||||||
return MangasPage(
|
return MangasPage(
|
||||||
result.map(SearchManga::toSManga),
|
result.map(SearchManga::toSManga),
|
||||||
hasNextPage = result.size >= limit,
|
hasNextPage = result.size >= LIMIT,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Latest Manga **/
|
/** Latest Manga **/
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
val url = "$apiUrl/v1.0/search?sort=uploaded&limit=$limit&page=$page&tachiyomi=true"
|
val url = "$apiUrl/v1.0/search?sort=uploaded&limit=$LIMIT&page=$page&tachiyomi=true"
|
||||||
return GET(url, headers)
|
return GET(url, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,8 +226,8 @@ abstract class ComickFun(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun paginatedSearchPage(page: Int): MangasPage {
|
private fun paginatedSearchPage(page: Int): MangasPage {
|
||||||
val end = min(page * limit, searchResponse.size)
|
val end = min(page * LIMIT, searchResponse.size)
|
||||||
val entries = searchResponse.subList((page - 1) * limit, end)
|
val entries = searchResponse.subList((page - 1) * LIMIT, end)
|
||||||
.map(SearchManga::toSManga)
|
.map(SearchManga::toSManga)
|
||||||
return MangasPage(entries, end < searchResponse.size)
|
return MangasPage(entries, end < searchResponse.size)
|
||||||
}
|
}
|
||||||
|
@ -317,7 +310,7 @@ abstract class ComickFun(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
addQueryParameter("tachiyomi", "true")
|
addQueryParameter("tachiyomi", "true")
|
||||||
addQueryParameter("limit", "$limit")
|
addQueryParameter("limit", "$LIMIT")
|
||||||
addQueryParameter("page", "$page")
|
addQueryParameter("page", "$page")
|
||||||
}.build()
|
}.build()
|
||||||
|
|
||||||
|
@ -367,7 +360,7 @@ abstract class ComickFun(
|
||||||
val coversUrl =
|
val coversUrl =
|
||||||
"$apiUrl/comic/${mangaData.comic.slug ?: mangaData.comic.hid}/covers?tachiyomi=true"
|
"$apiUrl/comic/${mangaData.comic.slug ?: mangaData.comic.hid}/covers?tachiyomi=true"
|
||||||
val covers = client.newCall(GET(coversUrl)).execute()
|
val covers = client.newCall(GET(coversUrl)).execute()
|
||||||
.parseAs<Covers>().md_covers.reversed()
|
.parseAs<Covers>().mdCovers.reversed()
|
||||||
return mangaData.toSManga(
|
return mangaData.toSManga(
|
||||||
includeMuTags = preferences.includeMuTags,
|
includeMuTags = preferences.includeMuTags,
|
||||||
covers = if (covers.any { it.vol == "1" }) covers.filter { it.vol == "1" } else covers,
|
covers = if (covers.any { it.vol == "1" }) covers.filter { it.vol == "1" } else covers,
|
||||||
|
@ -387,19 +380,15 @@ abstract class ComickFun(
|
||||||
throw Exception("Migrate from Comick to Comick")
|
throw Exception("Migrate from Comick to Comick")
|
||||||
}
|
}
|
||||||
|
|
||||||
return paginatedChapterListRequest(manga.url.removeSuffix("#"), 1)
|
val mangaUrl = manga.url.removeSuffix("#")
|
||||||
}
|
val url = "$apiUrl$mangaUrl".toHttpUrl().newBuilder().apply {
|
||||||
|
addPathSegment("chapters")
|
||||||
|
if (comickLang != "all") addQueryParameter("lang", comickLang)
|
||||||
|
addQueryParameter("tachiyomi", "true")
|
||||||
|
addQueryParameter("limit", "$CHAPTERS_LIMIT")
|
||||||
|
}.build()
|
||||||
|
|
||||||
private fun paginatedChapterListRequest(mangaUrl: String, page: Int): Request {
|
return GET(url, headers)
|
||||||
return GET(
|
|
||||||
"$apiUrl$mangaUrl".toHttpUrl().newBuilder().apply {
|
|
||||||
addPathSegment("chapters")
|
|
||||||
if (comickFunLang != "all") addQueryParameter("lang", comickFunLang)
|
|
||||||
addQueryParameter("tachiyomi", "true")
|
|
||||||
addQueryParameter("page", "$page")
|
|
||||||
}.build(),
|
|
||||||
headers,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
@ -409,20 +398,6 @@ abstract class ComickFun(
|
||||||
.substringBefore("/chapters")
|
.substringBefore("/chapters")
|
||||||
.substringAfter(apiUrl)
|
.substringAfter(apiUrl)
|
||||||
|
|
||||||
var resultSize = chapterListResponse.chapters.size
|
|
||||||
var page = 2
|
|
||||||
|
|
||||||
while (chapterListResponse.total > resultSize) {
|
|
||||||
val newRequest = paginatedChapterListRequest(mangaUrl, page)
|
|
||||||
val newResponse = client.newCall(newRequest).execute()
|
|
||||||
val newChapterListResponse = newResponse.parseAs<ChapterList>()
|
|
||||||
|
|
||||||
chapterListResponse.chapters += newChapterListResponse.chapters
|
|
||||||
|
|
||||||
resultSize += newChapterListResponse.chapters.size
|
|
||||||
page += 1
|
|
||||||
}
|
|
||||||
|
|
||||||
return chapterListResponse.chapters
|
return chapterListResponse.chapters
|
||||||
.filter {
|
.filter {
|
||||||
it.groups.map { g -> g.lowercase() }.intersect(preferences.ignoredGroups).isEmpty()
|
it.groups.map { g -> g.lowercase() }.intersect(preferences.ignoredGroups).isEmpty()
|
||||||
|
@ -457,8 +432,8 @@ abstract class ComickFun(
|
||||||
|
|
||||||
override fun getFilterList() = getFilters()
|
override fun getFilterList() = getFilters()
|
||||||
|
|
||||||
private fun SharedPreferences.newLineIgnoredGroups() {
|
private fun SharedPreferences.newLineIgnoredGroups(): SharedPreferences {
|
||||||
if (getBoolean(MIGRATED_IGNORED_GROUPS, false)) return
|
if (getBoolean(MIGRATED_IGNORED_GROUPS, false)) return this
|
||||||
val ignoredGroups = getString(IGNORED_GROUPS_PREF, "").orEmpty()
|
val ignoredGroups = getString(IGNORED_GROUPS_PREF, "").orEmpty()
|
||||||
|
|
||||||
edit()
|
edit()
|
||||||
|
@ -472,6 +447,8 @@ abstract class ComickFun(
|
||||||
)
|
)
|
||||||
.putBoolean(MIGRATED_IGNORED_GROUPS, true)
|
.putBoolean(MIGRATED_IGNORED_GROUPS, true)
|
||||||
.apply()
|
.apply()
|
||||||
|
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -484,14 +461,7 @@ abstract class ComickFun(
|
||||||
private const val FIRST_COVER_DEFAULT = true
|
private const val FIRST_COVER_DEFAULT = true
|
||||||
private const val SCORE_POSITION_PREF = "ScorePosition"
|
private const val SCORE_POSITION_PREF = "ScorePosition"
|
||||||
private const val SCORE_POSITION_DEFAULT = "top"
|
private const val SCORE_POSITION_DEFAULT = "top"
|
||||||
private const val limit = 20
|
private const val LIMIT = 20
|
||||||
val dateFormat by lazy {
|
private const val CHAPTERS_LIMIT = 99999
|
||||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH).apply {
|
|
||||||
timeZone = TimeZone.getTimeZone("UTC")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val markdownLinksRegex = "\\[([^]]+)]\\(([^)]+)\\)".toRegex()
|
|
||||||
val markdownItalicBoldRegex = "\\*+\\s*([^*]*)\\s*\\*+".toRegex()
|
|
||||||
val markdownItalicRegex = "_+\\s*([^_]*)\\s*_+".toRegex()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -10,7 +10,7 @@ val legacyLanguageMappings = mapOf(
|
||||||
"zh" to "zh-Hans", // Simplified Chinese
|
"zh" to "zh-Hans", // Simplified Chinese
|
||||||
).withDefault { it } // country code matches language code
|
).withDefault { it } // country code matches language code
|
||||||
|
|
||||||
class ComickFunFactory : SourceFactory {
|
class ComickFactory : SourceFactory {
|
||||||
private val idMap = listOf(
|
private val idMap = listOf(
|
||||||
"all" to 982606170401027267,
|
"all" to 982606170401027267,
|
||||||
"en" to 2971557565147974499,
|
"en" to 2971557565147974499,
|
||||||
|
@ -55,7 +55,7 @@ class ComickFunFactory : SourceFactory {
|
||||||
"da" to 7137437402245830147,
|
"da" to 7137437402245830147,
|
||||||
).toMap()
|
).toMap()
|
||||||
override fun createSources(): List<Source> = idMap.keys.map {
|
override fun createSources(): List<Source> = idMap.keys.map {
|
||||||
object : ComickFun(legacyLanguageMappings.getValue(it), it) {
|
object : Comick(legacyLanguageMappings.getValue(it), it) {
|
||||||
override val id: Long = idMap[it]!!
|
override val id: Long = idMap[it]!!
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,7 +7,7 @@ import android.os.Bundle
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import kotlin.system.exitProcess
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
class ComickFunUrlActivity : Activity() {
|
class ComickUrlActivity : Activity() {
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
val pathSegments = intent?.data?.pathSegments
|
val pathSegments = intent?.data?.pathSegments
|
||||||
|
@ -15,7 +15,7 @@ class ComickFunUrlActivity : Activity() {
|
||||||
val slug = pathSegments[1]
|
val slug = pathSegments[1]
|
||||||
val mainIntent = Intent().apply {
|
val mainIntent = Intent().apply {
|
||||||
action = "eu.kanade.tachiyomi.SEARCH"
|
action = "eu.kanade.tachiyomi.SEARCH"
|
||||||
putExtra("query", "${ComickFun.SLUG_SEARCH_PREFIX}$slug")
|
putExtra("query", "${Comick.SLUG_SEARCH_PREFIX}$slug")
|
||||||
putExtra("filter", packageName)
|
putExtra("filter", packageName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,9 @@ import java.math.BigDecimal
|
||||||
import java.math.RoundingMode
|
import java.math.RoundingMode
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SearchManga(
|
class SearchManga(
|
||||||
val hid: String,
|
private val hid: String,
|
||||||
val title: String,
|
private val title: String,
|
||||||
@SerialName("md_covers") val mdCovers: List<MDcovers> = emptyList(),
|
@SerialName("md_covers") val mdCovers: List<MDcovers> = emptyList(),
|
||||||
@SerialName("cover_url") val cover: String? = null,
|
@SerialName("cover_url") val cover: String? = null,
|
||||||
) {
|
) {
|
||||||
|
@ -23,12 +23,12 @@ data class SearchManga(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Manga(
|
class Manga(
|
||||||
val comic: Comic,
|
val comic: Comic,
|
||||||
val artists: List<Name> = emptyList(),
|
private val artists: List<Name> = emptyList(),
|
||||||
val authors: List<Name> = emptyList(),
|
private val authors: List<Name> = emptyList(),
|
||||||
val genres: List<Name> = emptyList(),
|
private val genres: List<Name> = emptyList(),
|
||||||
val demographic: String? = null,
|
private val demographic: String? = null,
|
||||||
) {
|
) {
|
||||||
fun toSManga(
|
fun toSManga(
|
||||||
includeMuTags: Boolean = false,
|
includeMuTags: Boolean = false,
|
||||||
|
@ -90,10 +90,10 @@ data class Manga(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Comic(
|
class Comic(
|
||||||
val hid: String,
|
val hid: String,
|
||||||
val title: String,
|
val title: String,
|
||||||
val country: String? = null,
|
private val country: String? = null,
|
||||||
val slug: String? = null,
|
val slug: String? = null,
|
||||||
@SerialName("md_titles") val altTitles: List<Title> = emptyList(),
|
@SerialName("md_titles") val altTitles: List<Title> = emptyList(),
|
||||||
val desc: String? = null,
|
val desc: String? = null,
|
||||||
|
@ -125,55 +125,54 @@ data class Comic(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MdGenres(
|
class MdGenres(
|
||||||
@SerialName("md_genres") val name: Name? = null,
|
@SerialName("md_genres") val name: Name? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MuComicCategories(
|
class MuComicCategories(
|
||||||
@SerialName("mu_comic_categories") val categories: List<MuCategories?> = emptyList(),
|
@SerialName("mu_comic_categories") val categories: List<MuCategories?> = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MuCategories(
|
class MuCategories(
|
||||||
@SerialName("mu_categories") val category: Title? = null,
|
@SerialName("mu_categories") val category: Title? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Covers(
|
class Covers(
|
||||||
val md_covers: List<MDcovers> = emptyList(),
|
@SerialName("md_covers") val mdCovers: List<MDcovers> = emptyList(),
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MDcovers(
|
class MDcovers(
|
||||||
val b2key: String?,
|
val b2key: String?,
|
||||||
val vol: String? = null,
|
val vol: String? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Title(
|
class Title(
|
||||||
val title: String?,
|
val title: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Name(
|
class Name(
|
||||||
val name: String,
|
val name: String,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ChapterList(
|
class ChapterList(
|
||||||
val chapters: MutableList<Chapter>,
|
val chapters: List<Chapter>,
|
||||||
val total: Int,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Chapter(
|
class Chapter(
|
||||||
val hid: String,
|
private val hid: String,
|
||||||
val lang: String = "",
|
private val lang: String = "",
|
||||||
val title: String = "",
|
private val title: String = "",
|
||||||
@SerialName("created_at") val createdAt: String = "",
|
@SerialName("created_at") val createdAt: String = "",
|
||||||
val chap: String = "",
|
private val chap: String = "",
|
||||||
val vol: String = "",
|
private val vol: String = "",
|
||||||
@SerialName("group_name") val groups: List<String> = emptyList(),
|
@SerialName("group_name") val groups: List<String> = emptyList(),
|
||||||
) {
|
) {
|
||||||
fun toSChapter(mangaUrl: String) = SChapter.create().apply {
|
fun toSChapter(mangaUrl: String) = SChapter.create().apply {
|
||||||
|
@ -185,16 +184,16 @@ data class Chapter(
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PageList(
|
class PageList(
|
||||||
val chapter: ChapterPageData,
|
val chapter: ChapterPageData,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class ChapterPageData(
|
class ChapterPageData(
|
||||||
val images: List<Page>,
|
val images: List<Page>,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Page(
|
class Page(
|
||||||
val url: String? = null,
|
val url: String? = null,
|
||||||
)
|
)
|
|
@ -1,13 +1,19 @@
|
||||||
package eu.kanade.tachiyomi.extension.all.comickfun
|
package eu.kanade.tachiyomi.extension.all.comickfun
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.dateFormat
|
|
||||||
import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.markdownItalicBoldRegex
|
|
||||||
import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.markdownItalicRegex
|
|
||||||
import eu.kanade.tachiyomi.extension.all.comickfun.ComickFun.Companion.markdownLinksRegex
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.parser.Parser
|
import org.jsoup.parser.Parser
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Locale
|
||||||
|
import java.util.TimeZone
|
||||||
|
|
||||||
|
private val dateFormat by lazy {
|
||||||
|
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH).apply {
|
||||||
|
timeZone = TimeZone.getTimeZone("UTC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private val markdownLinksRegex = "\\[([^]]+)]\\(([^)]+)\\)".toRegex()
|
||||||
|
private val markdownItalicBoldRegex = "\\*+\\s*([^*]*)\\s*\\*+".toRegex()
|
||||||
|
private val markdownItalicRegex = "_+\\s*([^_]*)\\s*_+".toRegex()
|
||||||
|
|
||||||
internal fun String.beautifyDescription(): String {
|
internal fun String.beautifyDescription(): String {
|
||||||
return Parser.unescapeEntities(this, false)
|
return Parser.unescapeEntities(this, false)
|
||||||
|
@ -42,25 +48,6 @@ internal fun parseCover(thumbnailUrl: String?, mdCovers: List<MDcovers>): String
|
||||||
return thumbnailUrl?.replaceAfterLast("/", "$b2key#$vol")
|
return thumbnailUrl?.replaceAfterLast("/", "$b2key#$vol")
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun thumbnailIntercept(chain: Interceptor.Chain): Response {
|
|
||||||
val request = chain.request()
|
|
||||||
val frag = request.url.fragment
|
|
||||||
if (frag.isNullOrEmpty()) return chain.proceed(request)
|
|
||||||
val response = chain.proceed(request)
|
|
||||||
if (!response.isSuccessful && response.code == 404) {
|
|
||||||
response.close()
|
|
||||||
val url = request.url.toString()
|
|
||||||
.replaceAfterLast("/", frag)
|
|
||||||
|
|
||||||
return chain.proceed(
|
|
||||||
request.newBuilder()
|
|
||||||
.url(url)
|
|
||||||
.build(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return response
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun beautifyChapterName(vol: String, chap: String, title: String): String {
|
internal fun beautifyChapterName(vol: String, chap: String, title: String): String {
|
||||||
return buildString {
|
return buildString {
|
||||||
if (vol.isNotEmpty()) {
|
if (vol.isNotEmpty()) {
|
Loading…
Reference in New Issue