Bilibili (Multisrc): Cleanup (#13083)

* Bilibili (Multisrc): Cleanup

* Use `.also()` to get rid of extra function

* Use apply instead of also

Also change function name from `setAuthCookie` to `setAccessTokenCookie`
This commit is contained in:
AntsyLich 2022-08-20 00:18:42 +06:00 committed by GitHub
parent a13b3ffce6
commit b8b4e2746e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 52 additions and 122 deletions

View File

@ -11,7 +11,6 @@ import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliTag
import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliUnlockedEpisode
import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliUserEpisodes
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.SourceFactory
import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
@ -19,6 +18,7 @@ import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import okhttp3.HttpUrl
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
@ -45,13 +45,13 @@ abstract class BilibiliComics(lang: String) : Bilibili(
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::signedInIntercept)
.addInterceptor(::expiredTokenIntercept)
.rateLimitHost(baseUrl.toHttpUrl(), 1)
.rateLimitHost(CDN_URL.toHttpUrl(), 2)
.rateLimitHost(COVER_CDN_URL.toHttpUrl(), 2)
.apply { interceptors().add(0, Interceptor { chain -> signedInIntercept(chain) }) }
.build()
init {
setAccessTokenCookie(baseUrl.toHttpUrl())
}
override val signedIn: Boolean
get() = accessTokenCookie != null
@ -96,7 +96,7 @@ abstract class BilibiliComics(lang: String) : Bilibili(
.set("Referer", baseUrl)
.build()
val apiUrl = "$globalApiBaseUrl/$GLOBAL_BASE_API_COMIC_ENDPOINT/GetUserEpisodes".toHttpUrl()
val apiUrl = "$globalApiBaseUrl/$API_COMIC_V1_USER_ENDPOINT/GetUserEpisodes".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
@ -135,7 +135,7 @@ abstract class BilibiliComics(lang: String) : Bilibili(
.set("Referer", baseUrl + chapter.url)
.build()
val apiUrl = "$globalApiBaseUrl/$GLOBAL_BASE_API_USER_ENDPOINT/GetCredential".toHttpUrl()
val apiUrl = "$globalApiBaseUrl/$API_GLOBAL_V1_USER_ENDPOINT/GetCredential".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
@ -165,15 +165,8 @@ abstract class BilibiliComics(lang: String) : Bilibili(
return super.pageListParse(imageIndexResponse)
}
private fun signedInIntercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val requestUrl = request.url.toString()
if (!requestUrl.contains("bilibilicomics.com")) {
return chain.proceed(request)
}
val authCookie = client.cookieJar.loadForRequest(request.url)
private fun setAccessTokenCookie(url: HttpUrl) {
val authCookie = client.cookieJar.loadForRequest(url)
.firstOrNull { cookie -> cookie.name == ACCESS_TOKEN_COOKIE_NAME }
?.let { cookie -> URLDecoder.decode(cookie.value, "UTF-8") }
?.let { jsonString -> json.decodeFromString<BilibiliAccessTokenCookie>(jsonString) }
@ -183,6 +176,17 @@ abstract class BilibiliComics(lang: String) : Bilibili(
} else if (authCookie == null) {
accessTokenCookie = null
}
}
private fun signedInIntercept(chain: Interceptor.Chain): Response {
var request = chain.request()
val requestUrl = request.url.toString()
if (!requestUrl.contains("bilibilicomics.com")) {
return chain.proceed(request)
}
setAccessTokenCookie(request.url)
if (!accessTokenCookie?.accessToken.isNullOrEmpty()) {
request = request.newBuilder()
@ -222,7 +226,7 @@ abstract class BilibiliComics(lang: String) : Bilibili(
.set("Referer", baseUrl)
.build()
val apiUrl = "$globalApiBaseUrl/$GLOBAL_BASE_API_USER_ENDPOINT/RefreshToken".toHttpUrl()
val apiUrl = "$globalApiBaseUrl/$API_GLOBAL_V1_USER_ENDPOINT/RefreshToken".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
@ -263,8 +267,8 @@ abstract class BilibiliComics(lang: String) : Bilibili(
private const val ACCESS_TOKEN_COOKIE_NAME = "access_token"
private val GLOBAL_API_SUBDOMAINS = arrayOf("us-user", "sg-user")
private const val GLOBAL_BASE_API_USER_ENDPOINT = "twirp/global.v1.User"
private const val GLOBAL_BASE_API_COMIC_ENDPOINT = "twirp/comic.v1.User"
private const val API_GLOBAL_V1_USER_ENDPOINT = "twirp/global.v1.User"
private const val API_COMIC_V1_USER_ENDPOINT = "twirp/comic.v1.User"
}
}

View File

@ -4,11 +4,8 @@ import eu.kanade.tachiyomi.multisrc.bilibili.Bilibili
import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliComicDto
import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliIntl
import eu.kanade.tachiyomi.multisrc.bilibili.BilibiliTag
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.model.SChapter
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Response
class BilibiliManga : Bilibili(
@ -19,13 +16,6 @@ class BilibiliManga : Bilibili(
override val id: Long = 3561131545129718586
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::expiredTokenIntercept)
.rateLimitHost(baseUrl.toHttpUrl(), 1)
.rateLimitHost(CDN_URL.toHttpUrl(), 2)
.rateLimitHost(COVER_CDN_URL.toHttpUrl(), 2)
.build()
override fun headersBuilder() = Headers.Builder().apply {
add("User-Agent", DEFAULT_USER_AGENT)
}

View File

@ -6,6 +6,7 @@ import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
@ -43,14 +44,19 @@ abstract class Bilibili(
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(::expiredTokenIntercept)
.rateLimitHost(baseUrl.toHttpUrl(), 1)
.rateLimitHost(CDN_URL.toHttpUrl(), 2)
.rateLimitHost(COVER_CDN_URL.toHttpUrl(), 2)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", ACCEPT_JSON)
.add("Origin", baseUrl)
.add("Referer", "$baseUrl/")
protected val intl by lazy { BilibiliIntl(lang) }
protected open val intl by lazy { BilibiliIntl(lang) }
private val apiLang: String = when (lang) {
BilibiliIntl.SIMPLIFIED_CHINESE -> "cn"
@ -75,85 +81,15 @@ abstract class Bilibili(
private val chapterImageFormat: String
get() = preferences.getString("${IMAGE_FORMAT_PREF_KEY}_$lang", IMAGE_FORMAT_PREF_DEFAULT_VALUE)!!
override fun popularMangaRequest(page: Int): Request {
val requestPayload = buildJsonObject {
put("area_id", -1)
put("is_finish", -1)
put("is_free", -1)
put("order", defaultPopularSort)
put("page_num", page)
put("page_size", POPULAR_PER_PAGE)
put("style_id", -1)
put("style_prefer", "[]")
}
val requestBody = requestPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
override fun popularMangaRequest(page: Int): Request =
searchMangaRequest(page, "", FilterList(SortFilter("", emptyArray(), defaultPopularSort)))
val apiUrl = "$baseUrl/$BASE_API_COMIC_ENDPOINT/ClassPage".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
override fun popularMangaParse(response: Response): MangasPage = searchMangaParse(response)
return POST(apiUrl, headers, requestBody)
}
override fun latestUpdatesRequest(page: Int): Request =
searchMangaRequest(page, "", FilterList(SortFilter("", emptyArray(), defaultLatestSort)))
override fun popularMangaParse(response: Response): MangasPage {
val result = response.parseAs<List<BilibiliComicDto>>()
if (result.code != 0) {
return MangasPage(emptyList(), hasNextPage = false)
}
val comicList = result.data!!.map(::popularMangaFromObject)
val hasNextPage = comicList.size == POPULAR_PER_PAGE
return MangasPage(comicList, hasNextPage)
}
private fun popularMangaFromObject(comic: BilibiliComicDto): SManga = SManga.create().apply {
title = comic.title
thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION
url = "/detail/mc${comic.seasonId}"
}
override fun latestUpdatesRequest(page: Int): Request {
val requestPayload = buildJsonObject {
put("area_id", -1)
put("is_finish", -1)
put("is_free", -1)
put("order", defaultLatestSort)
put("page_num", page)
put("page_size", POPULAR_PER_PAGE)
put("style_id", -1)
put("style_prefer", "[]")
}
val requestBody = requestPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
val apiUrl = "$baseUrl/$BASE_API_COMIC_ENDPOINT/ClassPage".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
return POST(apiUrl, headers, requestBody)
}
override fun latestUpdatesParse(response: Response): MangasPage {
val result = response.parseAs<List<BilibiliComicDto>>()
if (result.code != 0) {
return MangasPage(emptyList(), hasNextPage = false)
}
val comicList = result.data!!.map(::latestMangaFromObject)
val hasNextPage = comicList.size == POPULAR_PER_PAGE
return MangasPage(comicList, hasNextPage)
}
private fun latestMangaFromObject(comic: BilibiliComicDto): SManga = SManga.create().apply {
title = comic.title
thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION
url = "/detail/mc${comic.seasonId}"
}
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)) {
@ -206,7 +142,7 @@ abstract class Bilibili(
.set("Referer", refererUrl)
.build()
val apiUrl = "$baseUrl/$BASE_API_COMIC_ENDPOINT/".toHttpUrl().newBuilder()
val apiUrl = "$baseUrl/$API_COMIC_V1_COMIC_ENDPOINT/".toHttpUrl().newBuilder()
.addPathSegment(if (query.isBlank()) "ClassPage" else "Search")
.addCommonParameters()
.toString()
@ -272,7 +208,7 @@ abstract class Bilibili(
.set("Referer", baseUrl + mangaUrl)
.build()
val apiUrl = "$baseUrl/$BASE_API_COMIC_ENDPOINT/ComicDetail".toHttpUrl()
val apiUrl = "$baseUrl/$API_COMIC_V1_COMIC_ENDPOINT/ComicDetail".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
@ -312,19 +248,19 @@ abstract class Bilibili(
.map { ep -> chapterFromObject(ep, result.data.id) }
}
protected fun chapterFromObject(episode: BilibiliEpisodeDto, comicId: Int): SChapter = SChapter.create().apply {
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()
url = "/mc$comicId/${episode.id}"
}
override fun pageListRequest(chapter: SChapter): Request =
imageIndexRequest(chapter.url, "")
override fun pageListRequest(chapter: SChapter): Request = imageIndexRequest(chapter.url, "")
override fun pageListParse(response: Response): List<Page> = imageIndexParse(response)
protected fun imageIndexRequest(chapterUrl: String, credential: String): Request {
@Suppress("SameParameterValue")
protected open fun imageIndexRequest(chapterUrl: String, credential: String): Request {
val chapterId = chapterUrl.substringAfterLast("/").toInt()
val jsonPayload = buildJsonObject {
@ -337,7 +273,7 @@ abstract class Bilibili(
.set("Referer", baseUrl + chapterUrl)
.build()
val apiUrl = "$baseUrl/$BASE_API_COMIC_ENDPOINT/GetImageIndex".toHttpUrl()
val apiUrl = "$baseUrl/$API_COMIC_V1_COMIC_ENDPOINT/GetImageIndex".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
@ -345,7 +281,7 @@ abstract class Bilibili(
return POST(apiUrl, newHeaders, requestBody)
}
protected fun imageIndexParse(response: Response): List<Page> {
protected open fun imageIndexParse(response: Response): List<Page> {
val result = response.parseAs<BilibiliReader>()
if (result.code != 0) {
@ -370,7 +306,7 @@ abstract class Bilibili(
}
val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
val apiUrl = "$baseUrl/$BASE_API_COMIC_ENDPOINT/ImageToken".toHttpUrl()
val apiUrl = "$baseUrl/$API_COMIC_V1_COMIC_ENDPOINT/ImageToken".toHttpUrl()
.newBuilder()
.addCommonParameters()
.toString()
@ -453,7 +389,7 @@ abstract class Bilibili(
return FilterList(filters)
}
protected fun expiredTokenIntercept(chain: Interceptor.Chain): Response {
private fun expiredTokenIntercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
// Get a new image token if the current one expired.
@ -470,6 +406,7 @@ abstract class Bilibili(
val newRequest = imageRequest(Page(0, "", newPageUrl))
imageTokenResponse.close()
response.close()
return chain.proceed(newRequest)
}
@ -477,7 +414,7 @@ abstract class Bilibili(
return response
}
protected fun HttpUrl.Builder.addCommonParameters(): HttpUrl.Builder = let {
protected open fun HttpUrl.Builder.addCommonParameters(): HttpUrl.Builder = let {
if (name == "BILIBILI COMICS") {
addQueryParameter("lang", apiLang)
addQueryParameter("sys_lang", apiLang)
@ -502,8 +439,7 @@ abstract class Bilibili(
const val CDN_URL = "https://manga.hdslb.com"
const val COVER_CDN_URL = "https://i0.hdslb.com"
const val BASE_API_COMIC_ENDPOINT = "twirp/comic.v1.Comic"
const val BASE_API_USER_ENDPOINT = "twirp/comic.v1.User"
const val API_COMIC_V1_COMIC_ENDPOINT = "twirp/comic.v1.Comic"
private const val ACCEPT_JSON = "application/json, text/plain, */*"

View File

@ -10,7 +10,7 @@ class BilibiliGenerator : ThemeSourceGenerator {
override val themeClass = "Bilibili"
override val baseVersionCode: Int = 3
override val baseVersionCode: Int = 4
override val sources = listOf(
MultiLang(