Bilibili Comics Update (#7889)

* Update BilibiliComics.kt

* Update BilibiliDto.kt

* Create BilibiliComicsUrlActivity.kt

* Update BilibiliComics.kt

* Update build.gradle

* Update BilibiliComicsUrlActivity.kt
This commit is contained in:
FourTOne5 2021-06-27 01:46:41 +06:00 committed by GitHub
parent cd1c762ec5
commit 2a391a6139
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 143 additions and 6 deletions

View File

@ -6,7 +6,7 @@ ext {
extName = 'Bilibili Comics'
pkgNameSuffix = 'en.bilibilicomics'
extClass = '.BilibiliComics'
extVersionCode = 3
extVersionCode = 4
libVersion = '1.2'
containsNsfw = true
}

View File

@ -28,6 +28,7 @@ import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import java.util.concurrent.TimeUnit
@ -40,7 +41,7 @@ class BilibiliComics : HttpSource() {
override val lang = "en"
override val supportsLatest = false
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS))
@ -93,6 +94,62 @@ class BilibiliComics : HttpSource() {
url = "/detail/mc${comic.comicId}"
}
override fun latestUpdatesRequest(page: Int): Request {
val requestPayload = buildJsonObject {
put("day", day)
}
val requestBody = requestPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", requestBody.contentLength().toString())
.add("Content-Type", requestBody.contentType().toString())
.build()
return POST(
"$baseUrl/$BASE_API_ENDPOINT/GetSchedule?device=pc&platform=web",
headers = newHeaders,
body = requestBody
)
}
override fun latestUpdatesParse(response: Response): MangasPage {
val result = json.decodeFromString<BilibiliResultDto<BilibiliScheduleDto>>(response.body!!.string())
if (result.code != 0) {
return MangasPage(emptyList(), hasNextPage = false)
}
val comicList = result.data!!.list
.map(::latestMangaFromObject)
return MangasPage(comicList, hasNextPage = false)
}
private fun latestMangaFromObject(comic: BilibiliComicDto): SManga = SManga.create().apply {
title = comic.title
thumbnail_url = comic.verticalCover
url = "/detail/mc${comic.comicId}"
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return when {
query.startsWith(prefixIdSearch) -> {
val id = query.removePrefix(prefixIdSearch)
client.newCall(mangaDetailsApiRequestById(id)).asObservableSuccess()
.map { response ->
mangaDetailsParse(response).let { MangasPage(listOf(it), false) }
}
}
else -> {
client.newCall(searchMangaRequest(page, query, filters)).asObservableSuccess()
.map { response ->
searchMangaParse(response)
}
}
}
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val jsonPayload = buildJsonObject {
put("area_id", -1)
@ -170,6 +227,25 @@ class BilibiliComics : HttpSource() {
)
}
private fun mangaDetailsApiRequestById(id: String): Request {
val comicId = id.toInt()
val jsonPayload = buildJsonObject { put("comic_id", comicId) }
val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", requestBody.contentLength().toString())
.add("Content-Type", requestBody.contentType().toString())
.set("Referer", "$baseUrl/detail/mc$id")
.build()
return POST(
"$baseUrl/$BASE_API_ENDPOINT/ComicDetail?device=pc&platform=web",
headers = newHeaders,
body = requestBody
)
}
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
val result = json.decodeFromString<BilibiliResultDto<BilibiliComicDto>>(response.body!!.string())
val comic = result.data!!
@ -260,10 +336,6 @@ class BilibiliComics : HttpSource() {
return "${page.url}?token=${page.token}"
}
override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException("Not used")
override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException("Not used")
private fun String.toDate(): Long {
return try {
DATE_FORMATTER.parse(this)?.time ?: 0L
@ -272,6 +344,20 @@ class BilibiliComics : HttpSource() {
}
}
private val day: Int
get() {
return when (Calendar.getInstance().get(Calendar.DAY_OF_WEEK)) {
Calendar.SUNDAY -> 0
Calendar.MONDAY -> 1
Calendar.TUESDAY -> 2
Calendar.WEDNESDAY -> 3
Calendar.THURSDAY -> 4
Calendar.FRIDAY -> 5
Calendar.SATURDAY -> 6
else -> 0
}
}
companion object {
private const val BASE_API_ENDPOINT = "twirp/comic.v1.Comic"
@ -280,6 +366,8 @@ class BilibiliComics : HttpSource() {
private val JSON_MEDIA_TYPE = "application/json;charset=UTF-8".toMediaType()
private const val FEATURED_ID = 3
const val prefixIdSearch = "id:"
private val DATE_FORMATTER by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) }
}

View File

@ -0,0 +1,44 @@
package eu.kanade.tachiyomi.extension.en.bilibilicomics
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Bundle
import android.util.Log
import kotlin.system.exitProcess
/**
* Springboard that accepts https://www.bilibilicomics.com/detail/xxx intents and redirects them to
* the main tachiyomi process. The idea is to not install the intent filter unless
* you have this extension installed, but still let the main tachiyomi app control
* things.
*
* Main goal was to make it easier to open manga in Tachiyomi in spite of the DDoS blocking
* the usual search screen from working.
*/
class BilibiliComicsUrlActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val pathSegments = intent?.data?.pathSegments
if (pathSegments != null && pathSegments.size > 1) {
val titleid = pathSegments[1]
val mainIntent = Intent().apply {
action = "eu.kanade.tachiyomi.SEARCH"
putExtra("query", "${BilibiliComics.prefixIdSearch}${titleid.removePrefix("mc")}")
putExtra("filter", packageName)
}
try {
startActivity(mainIntent)
} catch (e: ActivityNotFoundException) {
Log.e("BilibiliUrlActivity", e.toString())
}
} else {
Log.e("BilibiliUrlActivity", "could not parse uri from intent $intent")
}
finish()
exitProcess(0)
}
}

View File

@ -15,6 +15,11 @@ data class BilibiliFeaturedDto(
@SerialName("roll_six_comics") val rollSixComics: List<BilibiliComicDto> = emptyList()
)
@Serializable
data class BilibiliScheduleDto(
val list: List<BilibiliComicDto> = emptyList()
)
@Serializable
data class BilibiliSearchDto(
val list: List<BilibiliComicDto> = emptyList()