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:
parent
cd1c762ec5
commit
2a391a6139
|
@ -6,7 +6,7 @@ ext {
|
|||
extName = 'Bilibili Comics'
|
||||
pkgNameSuffix = 'en.bilibilicomics'
|
||||
extClass = '.BilibiliComics'
|
||||
extVersionCode = 3
|
||||
extVersionCode = 4
|
||||
libVersion = '1.2'
|
||||
containsNsfw = true
|
||||
}
|
||||
|
|
|
@ -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) }
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
|
|
Loading…
Reference in New Issue