Bilibili (Multisrc): Refactor some codes (#14164)
* Bilibili (Multisrc): Refactor some codes * Lint * Fix import
This commit is contained in:
parent
a55da72c76
commit
a3b612a940
@ -14,25 +14,13 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="www.bilibilicomics.com"
|
||||
android:pathPattern="/detail/mc..*"
|
||||
android:scheme="https" />
|
||||
<data android:scheme="https" />
|
||||
|
||||
<data
|
||||
android:host="bilibilicomics.com"
|
||||
android:pathPattern="/detail/mc..*"
|
||||
android:scheme="https" />
|
||||
<data android:host="bilibilicomics.com" />
|
||||
<data android:host="m.bilibilicomics.com" />
|
||||
<data android:host="www.bilibilicomics.com" />
|
||||
|
||||
<data
|
||||
android:host="www.m.bilibilicomics.com"
|
||||
android:pathPattern="/detail/mc..*"
|
||||
android:scheme="https" />
|
||||
|
||||
<data
|
||||
android:host="m.bilibilicomics.com"
|
||||
android:pathPattern="/detail/mc..*"
|
||||
android:scheme="https" />
|
||||
<data android:pathPattern="/detail/mc..*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
@ -31,6 +31,7 @@ import okhttp3.Response
|
||||
import okio.Buffer
|
||||
import java.io.IOException
|
||||
import java.net.URLDecoder
|
||||
import java.util.Calendar
|
||||
|
||||
class BilibiliComicsFactory : SourceFactory {
|
||||
override fun createSources() = listOf(
|
||||
@ -67,6 +68,9 @@ abstract class BilibiliComics(lang: String) : Bilibili(
|
||||
|
||||
private var accessTokenCookie: BilibiliAccessTokenCookie? = null
|
||||
|
||||
private val dayOfWeek: Int
|
||||
get() = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val jsonPayload = buildJsonObject { put("day", dayOfWeek) }
|
||||
val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
|
||||
|
@ -14,15 +14,12 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="manga.bilibili.com"
|
||||
android:pathPattern="/detail/mc..*"
|
||||
android:scheme="https" />
|
||||
<data android:scheme="https" />
|
||||
|
||||
<data
|
||||
android:host="manga.bilibili.com"
|
||||
android:pathPattern="/m/detail/mc..*"
|
||||
android:scheme="https" />
|
||||
<data android:host="manga.bilibili.com" />
|
||||
|
||||
<data android:pathPattern="/detail/mc..*" />
|
||||
<data android:pathPattern="/m/detail/mc..*" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
|
@ -34,7 +34,6 @@ import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
import java.util.Locale
|
||||
|
||||
abstract class Bilibili(
|
||||
@ -46,7 +45,7 @@ abstract class Bilibili(
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(::expiredTokenIntercept)
|
||||
.addInterceptor(::expiredImageTokenIntercept)
|
||||
.rateLimitHost(baseUrl.toHttpUrl(), 1)
|
||||
.rateLimitHost(CDN_URL.toHttpUrl(), 2)
|
||||
.rateLimitHost(COVER_CDN_URL.toHttpUrl(), 2)
|
||||
@ -76,9 +75,6 @@ abstract class Bilibili(
|
||||
|
||||
protected open val signedIn: Boolean = false
|
||||
|
||||
protected val dayOfWeek: Int
|
||||
get() = Calendar.getInstance().get(Calendar.DAY_OF_WEEK) - 1
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request = searchMangaRequest(
|
||||
page = page,
|
||||
query = "",
|
||||
@ -100,11 +96,9 @@ abstract class Bilibili(
|
||||
override fun latestUpdatesParse(response: Response): MangasPage = searchMangaParse(response)
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
if (query.startsWith(PREFIX_ID_SEARCH) && query.matches(ID_SEARCH_PATTERN)) {
|
||||
val comicId = query
|
||||
.removePrefix(PREFIX_ID_SEARCH)
|
||||
.removePrefix("mc")
|
||||
return mangaDetailsApiRequest("/detail/mc$comicId")
|
||||
ID_SEARCH_PATTERN.matchEntire(query)?.let {
|
||||
val (id) = it.destructured
|
||||
return mangaDetailsApiRequest("/detail/mc$id")
|
||||
}
|
||||
|
||||
val price = filters.firstInstanceOrNull<PriceFilter>()?.state ?: 0
|
||||
@ -144,12 +138,13 @@ abstract class Bilibili(
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
if (response.request.url.toString().contains("ComicDetail")) {
|
||||
val requestUrl = response.request.url.toString()
|
||||
if (requestUrl.contains("ComicDetail")) {
|
||||
val comic = mangaDetailsParse(response)
|
||||
return MangasPage(listOf(comic), hasNextPage = false)
|
||||
}
|
||||
|
||||
if (response.request.url.toString().contains("ClassPage")) {
|
||||
if (requestUrl.contains("ClassPage")) {
|
||||
val result = response.parseAs<List<BilibiliComicDto>>()
|
||||
|
||||
if (result.code != 0) {
|
||||
@ -210,8 +205,7 @@ abstract class Bilibili(
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
|
||||
val result = response.parseAs<BilibiliComicDto>()
|
||||
val comic = result.data!!
|
||||
val comic = response.parseAs<BilibiliComicDto>().data!!
|
||||
|
||||
title = comic.title
|
||||
author = comic.authorName.joinToString()
|
||||
@ -231,7 +225,7 @@ abstract class Bilibili(
|
||||
append("\n• ${intl.totalChapterCount}: ${intl.localize(comic.episodeList.size)}")
|
||||
|
||||
if (comic.updateWeekdays.isNotEmpty() && status == SManga.ONGOING) {
|
||||
append("\n• ${intl.updatedEvery}: ${intl.getWeekdays(comic.updateWeekdays)}")
|
||||
append("\n• ${intl.getUpdateDays(comic.updateWeekdays)}")
|
||||
}
|
||||
}
|
||||
thumbnail_url = comic.verticalCover
|
||||
@ -254,9 +248,8 @@ abstract class Bilibili(
|
||||
}
|
||||
|
||||
protected open fun chapterFromObject(episode: BilibiliEpisodeDto, comicId: Int): SChapter = SChapter.create().apply {
|
||||
name = intl.episodePrefix + episode.shortTitle +
|
||||
(if (episode.title.isNotBlank()) " - " + episode.title else "")
|
||||
date_upload = episode.publicationTime.substringBefore("T").toDate()
|
||||
name = episode.shortTitle.plus(if (episode.title.isNotBlank()) " - ${episode.title}" else "")
|
||||
date_upload = episode.publicationTime.toDate()
|
||||
url = "/mc$comicId/${episode.id}"
|
||||
}
|
||||
|
||||
@ -373,46 +366,45 @@ abstract class Bilibili(
|
||||
return FilterList(filters)
|
||||
}
|
||||
|
||||
private fun expiredTokenIntercept(chain: Interceptor.Chain): Response {
|
||||
private fun expiredImageTokenIntercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
|
||||
// Get a new image token if the current one expired.
|
||||
if (response.code == 403 && chain.request().url.toString().contains(CDN_URL)) {
|
||||
response.close()
|
||||
val imagePath = chain.request().url.toString()
|
||||
.substringAfter(CDN_URL)
|
||||
.substringBefore("?token=")
|
||||
val imageTokenRequest = imageTokenRequest(listOf(imagePath))
|
||||
val imageTokenResponse = chain.proceed(imageTokenRequest)
|
||||
val imageTokenResult = imageTokenResponse.parseAs<List<BilibiliPageDto>>()
|
||||
imageTokenResponse.close()
|
||||
|
||||
val newPage = imageTokenResult.data!![0]
|
||||
val newPage = imageTokenResult.data!!.first()
|
||||
val newPageUrl = "${newPage.url}?token=${newPage.token}"
|
||||
|
||||
val newRequest = imageRequest(Page(0, "", newPageUrl))
|
||||
|
||||
imageTokenResponse.close()
|
||||
response.close()
|
||||
return chain.proceed(newRequest)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
protected val SharedPreferences.chapterImageQuality
|
||||
private val SharedPreferences.chapterImageQuality
|
||||
get() = when (getString("${IMAGE_QUALITY_PREF_KEY}_$lang", IMAGE_QUALITY_PREF_DEFAULT_VALUE)!!) {
|
||||
"raw" -> "1600w"
|
||||
"hd" -> "1000w"
|
||||
"sd" -> "800w_50q"
|
||||
else -> "raw+"
|
||||
"hd" -> "1600w"
|
||||
"sd" -> "1000w"
|
||||
"low" -> "800w_50q"
|
||||
else -> "raw"
|
||||
}
|
||||
|
||||
protected val SharedPreferences.chapterImageFormat
|
||||
private val SharedPreferences.chapterImageFormat
|
||||
get() = getString("${IMAGE_FORMAT_PREF_KEY}_$lang", IMAGE_FORMAT_PREF_DEFAULT_VALUE)!!
|
||||
|
||||
private inline fun <reified R> List<*>.firstInstanceOrNull(): R? =
|
||||
filterIsInstance<R>().firstOrNull()
|
||||
private inline fun <reified R> List<*>.firstInstanceOrNull(): R? = firstOrNull { it is R } as? R
|
||||
|
||||
protected open fun HttpUrl.Builder.addCommonParameters(): HttpUrl.Builder = let {
|
||||
protected open fun HttpUrl.Builder.addCommonParameters(): HttpUrl.Builder = apply {
|
||||
if (name == "BILIBILI COMICS") {
|
||||
addQueryParameter("lang", apiLang)
|
||||
addQueryParameter("sys_lang", apiLang)
|
||||
@ -420,8 +412,6 @@ abstract class Bilibili(
|
||||
|
||||
addQueryParameter("device", "pc")
|
||||
addQueryParameter("platform", "web")
|
||||
|
||||
return@let it
|
||||
}
|
||||
|
||||
protected inline fun <reified T> Response.parseAs(): BilibiliResultDto<T> = use {
|
||||
@ -447,10 +437,10 @@ abstract class Bilibili(
|
||||
private const val SEARCH_PER_PAGE = 9
|
||||
|
||||
const val PREFIX_ID_SEARCH = "id:"
|
||||
private val ID_SEARCH_PATTERN = "^id:(mc)?(\\d+)$".toRegex()
|
||||
private val ID_SEARCH_PATTERN = "^${PREFIX_ID_SEARCH}mc(\\d+)$".toRegex()
|
||||
|
||||
private const val IMAGE_QUALITY_PREF_KEY = "chapterImageQuality"
|
||||
private val IMAGE_QUALITY_PREF_ENTRY_VALUES = arrayOf("raw+", "raw", "hd", "sd")
|
||||
private val IMAGE_QUALITY_PREF_ENTRY_VALUES = arrayOf("raw", "hd", "sd", "low")
|
||||
private val IMAGE_QUALITY_PREF_DEFAULT_VALUE = IMAGE_QUALITY_PREF_ENTRY_VALUES[1]
|
||||
|
||||
private const val IMAGE_FORMAT_PREF_KEY = "chapterImageFormat"
|
||||
@ -461,7 +451,7 @@ abstract class Bilibili(
|
||||
const val THUMBNAIL_RESOLUTION = "@512w.jpg"
|
||||
|
||||
private val DATE_FORMATTER by lazy {
|
||||
SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.ENGLISH)
|
||||
}
|
||||
|
||||
private const val EMOJI_LOCKED = "\uD83D\uDD12"
|
||||
|
@ -65,7 +65,7 @@ data class BilibiliImageDto(
|
||||
) {
|
||||
|
||||
fun url(quality: String, format: String): String {
|
||||
val imageWidth = if (quality == "raw+") "${width}w" else quality
|
||||
val imageWidth = if (quality == "raw") "${width}w" else quality
|
||||
|
||||
return "$path@$imageWidth.$format"
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ class BilibiliGenerator : ThemeSourceGenerator {
|
||||
|
||||
override val themeClass = "Bilibili"
|
||||
|
||||
override val baseVersionCode: Int = 7
|
||||
override val baseVersionCode: Int = 8
|
||||
|
||||
override val sources = listOf(
|
||||
MultiLang(
|
||||
|
@ -43,12 +43,6 @@ class BilibiliIntl(private val lang: String) {
|
||||
else -> "Price"
|
||||
}
|
||||
|
||||
val episodePrefix: String = when (lang) {
|
||||
CHINESE, SIMPLIFIED_CHINESE -> ""
|
||||
SPANISH -> "Cap. "
|
||||
else -> "Ep. "
|
||||
}
|
||||
|
||||
fun hasPaidChaptersWarning(chapterCount: Int): String = when (lang) {
|
||||
CHINESE, SIMPLIFIED_CHINESE ->
|
||||
"${Bilibili.EMOJI_WARNING} 此漫画有 ${chapterCount.localized} 个付费章节,已在目录中隐藏。" +
|
||||
@ -73,8 +67,8 @@ class BilibiliIntl(private val lang: String) {
|
||||
}
|
||||
|
||||
val imageQualityPrefEntries: Array<String> = when (lang) {
|
||||
CHINESE, SIMPLIFIED_CHINESE -> arrayOf("原图+", "原图 (1600w)", "高 (1000w)", "低 (800w)")
|
||||
else -> arrayOf("Raw+", "Raw (1600w)", "HD (1000w)", "SD (800w)")
|
||||
CHINESE, SIMPLIFIED_CHINESE -> arrayOf("原图", "高清 (1600w)", "标清 (1000w)", "低清 (800w)")
|
||||
else -> arrayOf("Raw", "HD (1600w)", "SD (1000w)", "Low (800w)")
|
||||
}
|
||||
|
||||
val imageFormatPrefTitle: String = when (lang) {
|
||||
@ -191,18 +185,27 @@ class BilibiliIntl(private val lang: String) {
|
||||
else -> "Total chapter count"
|
||||
}
|
||||
|
||||
val updatedEvery: String = when (lang) {
|
||||
CHINESE, SIMPLIFIED_CHINESE -> "每周更新时间"
|
||||
SPANISH -> "Actualizado en"
|
||||
else -> "Updated every"
|
||||
private val updatesDaily: String = when (lang) {
|
||||
CHINESE, SIMPLIFIED_CHINESE -> "每日更新"
|
||||
SPANISH -> "Actualizaciones diarias"
|
||||
else -> "Updates daily"
|
||||
}
|
||||
|
||||
fun getWeekdays(dayIndexes: List<Int>): String {
|
||||
val weekdays = dateFormatSymbols.weekdays
|
||||
.filter(String::isNotBlank)
|
||||
.map { dayName -> dayName.replaceFirstChar { it.uppercase(locale) } }
|
||||
private fun updatesEvery(days: String): String = when (lang) {
|
||||
CHINESE, SIMPLIFIED_CHINESE -> "${days}更新"
|
||||
SPANISH -> "Actualizaciones todos los $days"
|
||||
else -> "Updates every $days"
|
||||
}
|
||||
|
||||
return dayIndexes.joinToString { weekdays[it] }
|
||||
fun getUpdateDays(dayIndexes: List<Int>): String {
|
||||
val shortWeekDays = dateFormatSymbols.shortWeekdays.filterNot(String::isBlank)
|
||||
if (dayIndexes.size == shortWeekDays.size) return updatesDaily
|
||||
val shortWeekDaysUpperCased = shortWeekDays.map {
|
||||
it.replaceFirstChar { char -> char.uppercase(locale) }
|
||||
}
|
||||
|
||||
val days = dayIndexes.joinToString { shortWeekDaysUpperCased[it] }
|
||||
return updatesEvery(days)
|
||||
}
|
||||
|
||||
fun localize(value: Int) = value.localized
|
||||
|
@ -23,7 +23,8 @@ class BilibiliUrlActivity : Activity() {
|
||||
|
||||
val pathSegments = intent?.data?.pathSegments
|
||||
if (pathSegments != null && pathSegments.size > 1) {
|
||||
val titleId = if (pathSegments.size == 3) pathSegments[2] else pathSegments[1]
|
||||
// Mobile site of https://manga.bilibili.com starts with path "m"
|
||||
val titleId = if (pathSegments[0] == "m") pathSegments[2] else pathSegments[1]
|
||||
|
||||
val mainIntent = Intent().apply {
|
||||
action = "eu.kanade.tachiyomi.SEARCH"
|
||||
|
Loading…
x
Reference in New Issue
Block a user