From 4f208803da0486726b9c8d7822ac0014713bfd39 Mon Sep 17 00:00:00 2001 From: Alessandro Jean Date: Tue, 14 Dec 2021 13:14:30 -0300 Subject: [PATCH] Add Chinese to Bilibili (#10098) * Add Chinese to Bilibili (closes #9150). * Refactor the extension and class names. Co-authored-by: FourTOne5 <59261191+FourTOne5@users.noreply.github.com> Co-authored-by: FourTOne5 <59261191+FourTOne5@users.noreply.github.com> --- .../bilibili}/AndroidManifest.xml | 0 .../bilibili}/build.gradle | 8 +- .../bilibili}/res/mipmap-hdpi/ic_launcher.png | Bin .../bilibili}/res/mipmap-mdpi/ic_launcher.png | Bin .../res/mipmap-xhdpi/ic_launcher.png | Bin .../res/mipmap-xxhdpi/ic_launcher.png | Bin .../res/mipmap-xxxhdpi/ic_launcher.png | Bin .../bilibili}/res/web_hi_res_512.png | Bin .../extension/all/bilibili/Bilibili.kt} | 227 ++++++++++++------ .../extension/all/bilibili}/BilibiliDto.kt | 2 +- .../extension/all/bilibili/BilibiliFactory.kt | 96 ++++++++ .../extension/all/bilibili/BilibiliFilters.kt | 28 +++ .../all/bilibili/BilibiliUrlActivity.kt} | 6 +- 13 files changed, 290 insertions(+), 77 deletions(-) rename src/{en/bilibilicomics => all/bilibili}/AndroidManifest.xml (100%) rename src/{en/bilibilicomics => all/bilibili}/build.gradle (64%) rename src/{en/bilibilicomics => all/bilibili}/res/mipmap-hdpi/ic_launcher.png (100%) rename src/{en/bilibilicomics => all/bilibili}/res/mipmap-mdpi/ic_launcher.png (100%) rename src/{en/bilibilicomics => all/bilibili}/res/mipmap-xhdpi/ic_launcher.png (100%) rename src/{en/bilibilicomics => all/bilibili}/res/mipmap-xxhdpi/ic_launcher.png (100%) rename src/{en/bilibilicomics => all/bilibili}/res/mipmap-xxxhdpi/ic_launcher.png (100%) rename src/{en/bilibilicomics => all/bilibili}/res/web_hi_res_512.png (100%) rename src/{en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComics.kt => all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/Bilibili.kt} (64%) rename src/{en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics => all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili}/BilibiliDto.kt (96%) create mode 100644 src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFactory.kt create mode 100644 src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFilters.kt rename src/{en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComicsUrlActivity.kt => all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliUrlActivity.kt} (88%) diff --git a/src/en/bilibilicomics/AndroidManifest.xml b/src/all/bilibili/AndroidManifest.xml similarity index 100% rename from src/en/bilibilicomics/AndroidManifest.xml rename to src/all/bilibili/AndroidManifest.xml diff --git a/src/en/bilibilicomics/build.gradle b/src/all/bilibili/build.gradle similarity index 64% rename from src/en/bilibilicomics/build.gradle rename to src/all/bilibili/build.gradle index b180cdd9d..e79d9d19c 100644 --- a/src/en/bilibilicomics/build.gradle +++ b/src/all/bilibili/build.gradle @@ -3,10 +3,10 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlinx-serialization' ext { - extName = 'BILIBILI COMICS' - pkgNameSuffix = 'en.bilibilicomics' - extClass = '.BilibiliComics' - extVersionCode = 9 + extName = 'BILIBILI' + pkgNameSuffix = 'all.bilibili' + extClass = '.BilibiliFactory' + extVersionCode = 1 isNsfw = true } diff --git a/src/en/bilibilicomics/res/mipmap-hdpi/ic_launcher.png b/src/all/bilibili/res/mipmap-hdpi/ic_launcher.png similarity index 100% rename from src/en/bilibilicomics/res/mipmap-hdpi/ic_launcher.png rename to src/all/bilibili/res/mipmap-hdpi/ic_launcher.png diff --git a/src/en/bilibilicomics/res/mipmap-mdpi/ic_launcher.png b/src/all/bilibili/res/mipmap-mdpi/ic_launcher.png similarity index 100% rename from src/en/bilibilicomics/res/mipmap-mdpi/ic_launcher.png rename to src/all/bilibili/res/mipmap-mdpi/ic_launcher.png diff --git a/src/en/bilibilicomics/res/mipmap-xhdpi/ic_launcher.png b/src/all/bilibili/res/mipmap-xhdpi/ic_launcher.png similarity index 100% rename from src/en/bilibilicomics/res/mipmap-xhdpi/ic_launcher.png rename to src/all/bilibili/res/mipmap-xhdpi/ic_launcher.png diff --git a/src/en/bilibilicomics/res/mipmap-xxhdpi/ic_launcher.png b/src/all/bilibili/res/mipmap-xxhdpi/ic_launcher.png similarity index 100% rename from src/en/bilibilicomics/res/mipmap-xxhdpi/ic_launcher.png rename to src/all/bilibili/res/mipmap-xxhdpi/ic_launcher.png diff --git a/src/en/bilibilicomics/res/mipmap-xxxhdpi/ic_launcher.png b/src/all/bilibili/res/mipmap-xxxhdpi/ic_launcher.png similarity index 100% rename from src/en/bilibilicomics/res/mipmap-xxxhdpi/ic_launcher.png rename to src/all/bilibili/res/mipmap-xxxhdpi/ic_launcher.png diff --git a/src/en/bilibilicomics/res/web_hi_res_512.png b/src/all/bilibili/res/web_hi_res_512.png similarity index 100% rename from src/en/bilibilicomics/res/web_hi_res_512.png rename to src/all/bilibili/res/web_hi_res_512.png diff --git a/src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComics.kt b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/Bilibili.kt similarity index 64% rename from src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComics.kt rename to src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/Bilibili.kt index 4f57dae63..0d12c498a 100644 --- a/src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComics.kt +++ b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/Bilibili.kt @@ -1,9 +1,14 @@ -package eu.kanade.tachiyomi.extension.en.bilibilicomics +package eu.kanade.tachiyomi.extension.all.bilibili -import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor +import android.app.Application +import android.content.SharedPreferences +import android.util.Log +import androidx.preference.ListPreference +import androidx.preference.PreferenceScreen +import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor import eu.kanade.tachiyomi.network.POST import eu.kanade.tachiyomi.network.asObservableSuccess -import eu.kanade.tachiyomi.source.model.Filter +import eu.kanade.tachiyomi.source.ConfigurableSource import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.Page @@ -11,13 +16,14 @@ import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.online.HttpSource import kotlinx.serialization.decodeFromString +import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import kotlinx.serialization.json.add -import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.put import okhttp3.Headers import okhttp3.HttpUrl.Companion.toHttpUrl +import okhttp3.Interceptor import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request @@ -25,23 +31,25 @@ import okhttp3.RequestBody.Companion.toRequestBody import okhttp3.Response import org.jsoup.Jsoup import rx.Observable +import uy.kohesive.injekt.Injekt +import uy.kohesive.injekt.api.get import uy.kohesive.injekt.injectLazy import java.text.SimpleDateFormat import java.util.Locale -import java.util.concurrent.TimeUnit -class BilibiliComics : HttpSource() { - - override val name = "BILIBILI COMICS" - - override val baseUrl = "https://www.bilibilicomics.com" - - override val lang = "en" +abstract class Bilibili( + override val name: String, + final override val baseUrl: String, + override val lang: String +) : HttpSource(), ConfigurableSource { override val supportsLatest = true override val client: OkHttpClient = network.cloudflareClient.newBuilder() - .addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS)) + .addInterceptor(::expiredTokenIntercept) + .addInterceptor(SpecificHostRateLimitInterceptor(baseUrl.toHttpUrl(), 1)) + .addInterceptor(SpecificHostRateLimitInterceptor(CDN_URL.toHttpUrl(), 2)) + .addInterceptor(SpecificHostRateLimitInterceptor(COVER_CDN_URL.toHttpUrl(), 2)) .build() override fun headersBuilder(): Headers.Builder = Headers.Builder() @@ -49,14 +57,47 @@ class BilibiliComics : HttpSource() { .add("Origin", baseUrl) .add("Referer", "$baseUrl/") + protected open val statusLabel: String = "Status" + + protected open val sortLabel: String = "Sort by" + + protected open val genreLabel: String = "Genre" + + protected open val areaLabel: String = "Area" + + protected open val priceLabel: String = "Price" + + protected open val episodePrefix: String = "Ep. " + + protected open val defaultPopularSort: Int = 1 + + protected open val defaultLatestSort: Int = 2 + + protected open val hasPaidChaptersWarning: String = "This series has paid chapters that " + + "were filtered out from the chapter list. Use the BILIBILI website or the official app " + + "to read them for now." + + protected open val resolutionPrefTitle: String = "Chapter image resolution" + + protected open val resolutionPrefEntries: Array = arrayOf("Raw", "HD", "SD") + + protected open val resolutionPrefEntryValues: Array = arrayOf("@1200w.jpg", "@800w.jpg", "@600w_50q.jpg") + + private val preferences: SharedPreferences by lazy { + Injekt.get().getSharedPreferences("source_$id", 0x0000) + } + private val json: Json by injectLazy() + private val chapterImageResolution: String + get() = preferences.getString("${RESOLUTION_PREF_KEY}_$lang", RESOLUTION_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", 0) + put("order", defaultPopularSort) put("page_num", page) put("page_size", POPULAR_PER_PAGE) put("style_id", -1) @@ -91,7 +132,7 @@ class BilibiliComics : HttpSource() { private fun popularMangaFromObject(comic: BilibiliComicDto): SManga = SManga.create().apply { title = comic.title - thumbnail_url = comic.verticalCover + thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION url = "/detail/mc${comic.seasonId}" } @@ -100,7 +141,7 @@ class BilibiliComics : HttpSource() { put("area_id", -1) put("is_finish", -1) put("is_free", -1) - put("order", 1) + put("order", defaultLatestSort) put("page_num", page) put("page_size", POPULAR_PER_PAGE) put("style_id", -1) @@ -135,7 +176,7 @@ class BilibiliComics : HttpSource() { private fun latestMangaFromObject(comic: BilibiliComicDto): SManga = SManga.create().apply { title = comic.title - thumbnail_url = comic.verticalCover + thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION url = "/detail/mc${comic.seasonId}" } @@ -153,15 +194,21 @@ class BilibiliComics : HttpSource() { val status = filters.filterIsInstance() .firstOrNull()?.state?.minus(1) ?: -1 + val price = filters.filterIsInstance() + .firstOrNull()?.state ?: 0 + val styleId = filters.filterIsInstance() .firstOrNull()?.selected?.id ?: -1 + val areaId = filters.filterIsInstance() + .firstOrNull()?.selected?.id ?: -1 + val pageSize = if (query.isBlank()) POPULAR_PER_PAGE else SEARCH_PER_PAGE val jsonPayload = buildJsonObject { - put("area_id", -1) + put("area_id", areaId) put("is_finish", status) - put("is_free", -1) + put("is_free", if (price == 0) -1 else price) put("order", order) put("page_num", page) put("page_size", pageSize) @@ -174,6 +221,7 @@ class BilibiliComics : HttpSource() { } } val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE) + Log.d("Bilibili", jsonPayload.toString()) val refererUrl = if (query.isBlank()) "$baseUrl/genre" else "$baseUrl/search".toHttpUrl().newBuilder() @@ -227,7 +275,7 @@ class BilibiliComics : HttpSource() { private fun searchMangaFromObject(comic: BilibiliComicDto): SManga = SManga.create().apply { title = Jsoup.parse(comic.title).text() - thumbnail_url = comic.verticalCover + thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION val comicId = if (comic.id == 0) comic.seasonId else comic.id url = "/detail/mc$comicId" @@ -270,12 +318,11 @@ class BilibiliComics : HttpSource() { status = if (comic.isFinish == 1) SManga.COMPLETED else SManga.ONGOING genre = comic.styles.joinToString() description = comic.classicLines - thumbnail_url = comic.verticalCover + thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION url = "/detail/mc" + comic.id if (comic.episodeList.any { episode -> episode.payMode == 1 && episode.payGold > 0 }) { - description += "\n\nThis series have paid chapters that were filtered out from the " + - "chapter list. Use the BILIBILI website or the official app to read them for now." + description += "\n\n$hasPaidChaptersWarning" } } @@ -294,7 +341,7 @@ class BilibiliComics : HttpSource() { } private fun chapterFromObject(episode: BilibiliEpisodeDto, comicId: Int): SChapter = SChapter.create().apply { - name = "Ep. " + episode.shortTitle + " - " + episode.title + name = episodePrefix + episode.shortTitle + " - " + episode.title date_upload = episode.publicationTime.substringBefore("T").toDate() url = "/mc$comicId/${episode.id}" } @@ -328,13 +375,19 @@ class BilibiliComics : HttpSource() { return emptyList() } - return result.data!!.images - .mapIndexed { i, page -> Page(i, page.path, "") } + val imageQuality = chapterImageResolution + + val imageTokenRequest = imageTokenRequest(result.data!!.images.map { it.path + imageQuality }) + val imageTokenResponse = client.newCall(imageTokenRequest).execute() + val imageTokenResult = imageTokenResponse.parseAs>() + + return imageTokenResult.data!! + .mapIndexed { i, page -> Page(i, "", "${page.url}?token=${page.token}") } } - override fun imageUrlRequest(page: Page): Request { + protected open fun imageTokenRequest(urls: List): Request { val jsonPayload = buildJsonObject { - put("urls", buildJsonArray { add(page.url) }.toString()) + put("urls", json.encodeToString(urls)) } val requestBody = jsonPayload.toString().toRequestBody(JSON_MEDIA_TYPE) @@ -350,54 +403,82 @@ class BilibiliComics : HttpSource() { ) } - override fun imageUrlParse(response: Response): String { - val result = response.parseAs>() - val page = result.data!![0] + override fun imageUrlParse(response: Response): String = "" - return "${page.url}?token=${page.token}" + override fun setupPreferenceScreen(screen: PreferenceScreen) { + val resolutionPref = ListPreference(screen.context).apply { + key = "${RESOLUTION_PREF_KEY}_$lang" + title = resolutionPrefTitle + entries = resolutionPrefEntries + entryValues = resolutionPrefEntryValues + setDefaultValue(RESOLUTION_PREF_DEFAULT_VALUE) + summary = "%s" + + setOnPreferenceChangeListener { _, newValue -> + val selected = newValue as String + val index = findIndexOfValue(selected) + val entry = entryValues[index] as String + + preferences.edit() + .putString("${RESOLUTION_PREF_KEY}_$lang", entry) + .commit() + } + } + + screen.addPreference(resolutionPref) } - private data class Genre(val name: String, val id: Int) { - override fun toString(): String = name + abstract fun getAllGenres(): Array + + protected open fun getAllAreas(): Array = emptyArray() + + protected open fun getAllSortOptions(): Array = arrayOf("Interest", "Popular", "Updated") + + protected open fun getAllStatus(): Array = arrayOf("All", "Ongoing", "Completed") + + protected open fun getAllPrices(): Array = arrayOf("All", "Free", "Paid") + + override fun getFilterList(): FilterList { + val filters = mutableListOf( + StatusFilter(statusLabel, getAllStatus()), + SortFilter(sortLabel, getAllSortOptions(), defaultPopularSort), + PriceFilter(priceLabel, getAllPrices()), + GenreFilter(genreLabel, getAllGenres()) + ) + + val allAreas = getAllAreas() + + if (allAreas.isNotEmpty()) { + filters.add(AreaFilter(areaLabel, allAreas)) + } + + return FilterList(filters) } - private class GenreFilter(genres: Array) : Filter.Select("Genre", genres) { - val selected: Genre - get() = values[state] + private fun expiredTokenIntercept(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)) { + 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>() + + val newPage = imageTokenResult.data!![0] + val newPageUrl = "${newPage.url}?token=${newPage.token}" + + val newRequest = imageRequest(Page(0, "", newPageUrl)) + + response.close() + return chain.proceed(newRequest) + } + + return response } - private class SortFilter(options: Array) : Filter.Select("Sort by", options) - private class StatusFilter(statuses: Array) : Filter.Select("Status", statuses) - - private fun getAllGenres(): Array = arrayOf( - Genre("All", -1), - Genre("Action", 19), - Genre("Adventure", 22), - Genre("BL", 3), - Genre("Comedy", 14), - Genre("Eastern", 30), - Genre("Fantasy", 11), - Genre("GL", 16), - Genre("Harem", 15), - Genre("Historical", 12), - Genre("Horror", 23), - Genre("Mistery", 17), - Genre("Romance", 13), - Genre("Slice of Life", 21), - Genre("Suspense", 41), - Genre("Teen", 20) - ) - - private fun getAllSortOptions(): Array = arrayOf("Popular", "Updated") - - private fun getAllStatus(): Array = arrayOf("All", "Ongoing", "Completed") - - override fun getFilterList(): FilterList = FilterList( - StatusFilter(getAllStatus()), - SortFilter(getAllSortOptions()), - GenreFilter(getAllGenres()) - ) - private inline fun Response.parseAs(): BilibiliResultDto = use { json.decodeFromString(it.body?.string().orEmpty()) } @@ -408,6 +489,9 @@ class BilibiliComics : HttpSource() { } companion object { + private const val CDN_URL = "https://manga.hdslb.com" + private const val COVER_CDN_URL = "https://i0.hdslb.com" + private const val BASE_API_ENDPOINT = "twirp/comic.v1.Comic" private const val ACCEPT_JSON = "application/json, text/plain, */*" @@ -420,6 +504,11 @@ class BilibiliComics : HttpSource() { const val PREFIX_ID_SEARCH = "id:" private val ID_SEARCH_PATTERN = "^id:(mc)?(\\d+)$".toRegex() + private const val RESOLUTION_PREF_KEY = "imageResolution" + private const val RESOLUTION_PREF_DEFAULT_VALUE = "" + + private const val THUMBNAIL_RESOLUTION = "@512w.jpg" + private val DATE_FORMATTER by lazy { SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH) } diff --git a/src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliDto.kt b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliDto.kt similarity index 96% rename from src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliDto.kt rename to src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliDto.kt index 6e099bdbd..042f56b8c 100644 --- a/src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliDto.kt +++ b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliDto.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.extension.en.bilibilicomics +package eu.kanade.tachiyomi.extension.all.bilibili import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable diff --git a/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFactory.kt b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFactory.kt new file mode 100644 index 000000000..51d8ec5f1 --- /dev/null +++ b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFactory.kt @@ -0,0 +1,96 @@ +package eu.kanade.tachiyomi.extension.all.bilibili + +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.SourceFactory + +class BilibiliFactory : SourceFactory { + override fun createSources(): List = listOf( + BilibiliComics(), + BilibiliManhua() + ) +} + +class BilibiliComics : Bilibili("BILIBILI COMICS", "https://www.bilibilicomics.com", "en") { + + override fun getAllGenres(): Array = arrayOf( + BilibiliTag("All", -1), + BilibiliTag("Action", 19), + BilibiliTag("Adventure", 22), + BilibiliTag("BL", 3), + BilibiliTag("Comedy", 14), + BilibiliTag("Eastern", 30), + BilibiliTag("Fantasy", 11), + BilibiliTag("GL", 16), + BilibiliTag("Harem", 15), + BilibiliTag("Historical", 12), + BilibiliTag("Horror", 23), + BilibiliTag("Mistery", 17), + BilibiliTag("Romance", 13), + BilibiliTag("Slice of Life", 21), + BilibiliTag("Suspense", 41), + BilibiliTag("Teen", 20) + ) +} + +class BilibiliManhua : Bilibili("哔哩哔哩漫画", "https://manga.bilibili.com", "zh") { + + override val statusLabel: String = "进度" + + override val sortLabel: String = "排序" + + override val genreLabel: String = "题材" + + override val areaLabel: String = "地区" + + override val priceLabel: String = "收费" + + override val episodePrefix: String = "" + + override val defaultPopularSort: Int = 0 + + override val defaultLatestSort: Int = 1 + + // Machine translated, needs to be revisited. + override val hasPaidChaptersWarning: String = "本系列已付费章节从章节列表中过滤掉。 " + + "暂时使用哔哩哔哩网站或官方应用程序阅读它们。" + + // Machine translated, needs to be revisited. + override val resolutionPrefTitle: String = "章节图像分辨率" + + override fun getAllStatus(): Array = arrayOf("全部", "连载", "完结") + + override fun getAllSortOptions(): Array = arrayOf("人气推荐", "更新时间", "追漫人数", "上架时间") + + override fun getAllPrices(): Array = arrayOf("全部", "免费", "付费", "等就免费") + + override fun getAllGenres(): Array = arrayOf( + BilibiliTag("全部", -1), + BilibiliTag("竞技", 1034), + BilibiliTag("冒险", 1013), + BilibiliTag("热血", 999), + BilibiliTag("搞笑", 994), + BilibiliTag("恋爱", 995), + BilibiliTag("少女", 1026), + BilibiliTag("日常", 1020), + BilibiliTag("校园", 1001), + BilibiliTag("治愈", 1007), + BilibiliTag("古风", 997), + BilibiliTag("玄幻", 1016), + BilibiliTag("奇幻", 998), + BilibiliTag("惊奇", 996), + BilibiliTag("悬疑", 1023), + BilibiliTag("都市", 1002), + BilibiliTag("剧情", 1030), + BilibiliTag("总裁", 1004), + BilibiliTag("科幻", 1015), + BilibiliTag("正能量", 1028), + ) + + override fun getAllAreas(): Array = arrayOf( + BilibiliTag("全部", -1), + BilibiliTag("大陆", 1), + BilibiliTag("日本", 2), + BilibiliTag("韩国", 6), + BilibiliTag("其他", 5), + ) +} diff --git a/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFilters.kt b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFilters.kt new file mode 100644 index 000000000..9905c8cf2 --- /dev/null +++ b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliFilters.kt @@ -0,0 +1,28 @@ +package eu.kanade.tachiyomi.extension.all.bilibili + +import eu.kanade.tachiyomi.source.model.Filter + +data class BilibiliTag(val name: String, val id: Int) { + override fun toString(): String = name +} + +class GenreFilter(label: String, genres: Array) : + Filter.Select(label, genres) { + val selected: BilibiliTag + get() = values[state] +} + +class AreaFilter(label: String, genres: Array) : + Filter.Select(label, genres) { + val selected: BilibiliTag + get() = values[state] +} + +class SortFilter(label: String, options: Array, state: Int = 0) : + Filter.Select(label, options, state) + +class StatusFilter(label: String, statuses: Array) : + Filter.Select(label, statuses) + +class PriceFilter(label: String, prices: Array) : + Filter.Select(label, prices) diff --git a/src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComicsUrlActivity.kt b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliUrlActivity.kt similarity index 88% rename from src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComicsUrlActivity.kt rename to src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliUrlActivity.kt index 03e07c713..b92c985a1 100644 --- a/src/en/bilibilicomics/src/eu/kanade/tachiyomi/extension/en/bilibilicomics/BilibiliComicsUrlActivity.kt +++ b/src/all/bilibili/src/eu/kanade/tachiyomi/extension/all/bilibili/BilibiliUrlActivity.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.extension.en.bilibilicomics +package eu.kanade.tachiyomi.extension.all.bilibili import android.app.Activity import android.content.ActivityNotFoundException @@ -16,7 +16,7 @@ import kotlin.system.exitProcess * 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() { +class BilibiliUrlActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -27,7 +27,7 @@ class BilibiliComicsUrlActivity : Activity() { val mainIntent = Intent().apply { action = "eu.kanade.tachiyomi.SEARCH" - putExtra("query", BilibiliComics.PREFIX_ID_SEARCH + titleId) + putExtra("query", Bilibili.PREFIX_ID_SEARCH + titleId) putExtra("filter", packageName) }