Add original quality as option in Bilibili (#13719)
* Add original quality as option in Bilibili. Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * Always show the locked chapters count. * Show extra information in the series details. Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * Add missing Chinese translations. Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Co-authored-by: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									09c587a0b4
								
							
						
					
					
						commit
						db71211623
					
				@ -36,8 +36,12 @@ class BilibiliManga : Bilibili(
 | 
			
		||||
 | 
			
		||||
    override val defaultLatestSort: Int = 1
 | 
			
		||||
 | 
			
		||||
    override fun getAllSortOptions(): Array<String> =
 | 
			
		||||
        arrayOf(intl.sortPopular, intl.sortUpdated, intl.sortFollowers, intl.sortAdded)
 | 
			
		||||
    override fun getAllSortOptions(): Array<BilibiliTag> = arrayOf(
 | 
			
		||||
        BilibiliTag(intl.sortPopular, 0),
 | 
			
		||||
        BilibiliTag(intl.sortUpdated, 1),
 | 
			
		||||
        BilibiliTag(intl.sortFollowers, 2),
 | 
			
		||||
        BilibiliTag(intl.sortAdded, 3)
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override fun getAllPrices(): Array<String> =
 | 
			
		||||
        arrayOf(intl.priceAll, intl.priceFree, intl.pricePaid, intl.priceWaitForFree)
 | 
			
		||||
 | 
			
		||||
@ -63,9 +63,9 @@ abstract class Bilibili(
 | 
			
		||||
        else -> lang
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected open val defaultPopularSort: Int = 1
 | 
			
		||||
    protected open val defaultPopularSort: Int = 0
 | 
			
		||||
 | 
			
		||||
    protected open val defaultLatestSort: Int = 2
 | 
			
		||||
    protected open val defaultLatestSort: Int = 1
 | 
			
		||||
 | 
			
		||||
    private val preferences: SharedPreferences by lazy {
 | 
			
		||||
        Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
 | 
			
		||||
@ -75,19 +75,23 @@ abstract class Bilibili(
 | 
			
		||||
 | 
			
		||||
    protected open val signedIn: Boolean = false
 | 
			
		||||
 | 
			
		||||
    private val chapterImageQuality: String
 | 
			
		||||
        get() = preferences.getString("${IMAGE_QUALITY_PREF_KEY}_$lang", IMAGE_QUALITY_PREF_DEFAULT_VALUE)!!
 | 
			
		||||
 | 
			
		||||
    private val chapterImageFormat: String
 | 
			
		||||
        get() = preferences.getString("${IMAGE_FORMAT_PREF_KEY}_$lang", IMAGE_FORMAT_PREF_DEFAULT_VALUE)!!
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaRequest(page: Int): Request =
 | 
			
		||||
        searchMangaRequest(page, "", FilterList(SortFilter("", emptyArray(), defaultPopularSort)))
 | 
			
		||||
    override fun popularMangaRequest(page: Int): Request = searchMangaRequest(
 | 
			
		||||
        page = page,
 | 
			
		||||
        query = "",
 | 
			
		||||
        filters = FilterList(
 | 
			
		||||
            SortFilter("", getAllSortOptions(), defaultPopularSort)
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaParse(response: Response): MangasPage = searchMangaParse(response)
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int): Request =
 | 
			
		||||
        searchMangaRequest(page, "", FilterList(SortFilter("", emptyArray(), defaultLatestSort)))
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int): Request = searchMangaRequest(
 | 
			
		||||
        page = page,
 | 
			
		||||
        query = "",
 | 
			
		||||
        filters = FilterList(
 | 
			
		||||
            SortFilter("", getAllSortOptions(), defaultLatestSort)
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesParse(response: Response): MangasPage = searchMangaParse(response)
 | 
			
		||||
 | 
			
		||||
@ -99,31 +103,16 @@ abstract class Bilibili(
 | 
			
		||||
            return mangaDetailsApiRequest("/detail/mc$comicId")
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val order = filters.filterIsInstance<SortFilter>()
 | 
			
		||||
            .firstOrNull()?.state ?: 0
 | 
			
		||||
 | 
			
		||||
        val status = filters.filterIsInstance<StatusFilter>()
 | 
			
		||||
            .firstOrNull()?.state?.minus(1) ?: -1
 | 
			
		||||
 | 
			
		||||
        val price = filters.filterIsInstance<PriceFilter>()
 | 
			
		||||
            .firstOrNull()?.state ?: 0
 | 
			
		||||
 | 
			
		||||
        val styleId = filters.filterIsInstance<GenreFilter>()
 | 
			
		||||
            .firstOrNull()?.selected?.id ?: -1
 | 
			
		||||
 | 
			
		||||
        val areaId = filters.filterIsInstance<AreaFilter>()
 | 
			
		||||
            .firstOrNull()?.selected?.id ?: -1
 | 
			
		||||
 | 
			
		||||
        val pageSize = if (query.isBlank()) POPULAR_PER_PAGE else SEARCH_PER_PAGE
 | 
			
		||||
        val price = filters.firstInstanceOrNull<PriceFilter>()?.state ?: 0
 | 
			
		||||
 | 
			
		||||
        val jsonPayload = buildJsonObject {
 | 
			
		||||
            put("area_id", areaId)
 | 
			
		||||
            put("is_finish", status)
 | 
			
		||||
            put("area_id", filters.firstInstanceOrNull<AreaFilter>()?.selected?.id ?: -1)
 | 
			
		||||
            put("is_finish", filters.firstInstanceOrNull<StatusFilter>()?.state?.minus(1) ?: -1)
 | 
			
		||||
            put("is_free", if (price == 0) -1 else price)
 | 
			
		||||
            put("order", order)
 | 
			
		||||
            put("order", filters.firstInstanceOrNull<SortFilter>()?.selected?.id ?: 0)
 | 
			
		||||
            put("page_num", page)
 | 
			
		||||
            put("page_size", pageSize)
 | 
			
		||||
            put("style_id", styleId)
 | 
			
		||||
            put("page_size", if (query.isBlank()) POPULAR_PER_PAGE else SEARCH_PER_PAGE)
 | 
			
		||||
            put("style_id", filters.firstInstanceOrNull<GenreFilter>()?.selected?.id ?: -1)
 | 
			
		||||
            put("style_prefer", "[]")
 | 
			
		||||
 | 
			
		||||
            if (query.isNotBlank()) {
 | 
			
		||||
@ -222,15 +211,27 @@ abstract class Bilibili(
 | 
			
		||||
 | 
			
		||||
        title = comic.title
 | 
			
		||||
        author = comic.authorName.joinToString()
 | 
			
		||||
        status = if (comic.isFinish == 1) SManga.COMPLETED else SManga.ONGOING
 | 
			
		||||
        genre = comic.genres(intl.pricePaid, EMOJI_LOCKED).joinToString()
 | 
			
		||||
        description = comic.classicLines
 | 
			
		||||
        thumbnail_url = comic.verticalCover + THUMBNAIL_RESOLUTION
 | 
			
		||||
        url = "/detail/mc" + comic.id
 | 
			
		||||
 | 
			
		||||
        if (comic.hasPaidChapters && !signedIn) {
 | 
			
		||||
            description = "${intl.hasPaidChaptersWarning}\n\n$description"
 | 
			
		||||
        status = when {
 | 
			
		||||
            comic.isFinish == 1 -> SManga.COMPLETED
 | 
			
		||||
            comic.isOnHiatus -> SManga.ON_HIATUS
 | 
			
		||||
            else -> SManga.ONGOING
 | 
			
		||||
        }
 | 
			
		||||
        description = buildString {
 | 
			
		||||
            if (comic.hasPaidChapters && !signedIn) {
 | 
			
		||||
                append("${intl.hasPaidChaptersWarning(comic.paidChaptersCount)}\n\n")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            append("${comic.classicLines}\n\n")
 | 
			
		||||
            append("${intl.informationTitle}:")
 | 
			
		||||
            append("\n• ${intl.totalChapterCount}: ${intl.localize(comic.episodeList.size)}")
 | 
			
		||||
 | 
			
		||||
            if (comic.updateWeekdays.isNotEmpty() && status == SManga.ONGOING) {
 | 
			
		||||
                append("\n• ${intl.updatedEvery}: ${intl.getWeekdays(comic.updateWeekdays)}")
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        thumbnail_url = comic.verticalCover
 | 
			
		||||
        url = "/detail/mc" + comic.id
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Chapters are available in the same url of the manga details.
 | 
			
		||||
@ -288,10 +289,10 @@ abstract class Bilibili(
 | 
			
		||||
            return emptyList()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val imageQuality = chapterImageQuality
 | 
			
		||||
        val imageFormat = chapterImageFormat
 | 
			
		||||
        val imageQuality = preferences.chapterImageQuality
 | 
			
		||||
        val imageFormat = preferences.chapterImageFormat
 | 
			
		||||
 | 
			
		||||
        val imageUrls = result.data!!.images.map { "${it.path}@$imageQuality.$imageFormat" }
 | 
			
		||||
        val imageUrls = result.data!!.images.map { it.url(imageQuality, imageFormat) }
 | 
			
		||||
        val imageTokenRequest = imageTokenRequest(imageUrls)
 | 
			
		||||
        val imageTokenResponse = client.newCall(imageTokenRequest).execute()
 | 
			
		||||
        val imageTokenResult = imageTokenResponse.parseAs<List<BilibiliPageDto>>()
 | 
			
		||||
@ -324,16 +325,6 @@ abstract class Bilibili(
 | 
			
		||||
            entryValues = IMAGE_QUALITY_PREF_ENTRY_VALUES
 | 
			
		||||
            setDefaultValue(IMAGE_QUALITY_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("${IMAGE_QUALITY_PREF_KEY}_$lang", entry)
 | 
			
		||||
                    .commit()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val imageFormatPref = ListPreference(screen.context).apply {
 | 
			
		||||
@ -343,16 +334,6 @@ abstract class Bilibili(
 | 
			
		||||
            entryValues = IMAGE_FORMAT_PREF_ENTRY_VALUES
 | 
			
		||||
            setDefaultValue(IMAGE_FORMAT_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("${IMAGE_FORMAT_PREF_KEY}_$lang", entry)
 | 
			
		||||
                    .commit()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        screen.addPreference(imageQualityPref)
 | 
			
		||||
@ -363,29 +344,28 @@ abstract class Bilibili(
 | 
			
		||||
 | 
			
		||||
    protected open fun getAllAreas(): Array<BilibiliTag> = emptyArray()
 | 
			
		||||
 | 
			
		||||
    protected open fun getAllSortOptions(): Array<String> =
 | 
			
		||||
        arrayOf(intl.sortInterest, intl.sortPopular, intl.sortUpdated)
 | 
			
		||||
    protected open fun getAllSortOptions(): Array<BilibiliTag> = arrayOf(
 | 
			
		||||
        BilibiliTag(intl.sortInterest, 0),
 | 
			
		||||
        BilibiliTag(intl.sortUpdated, 4),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    protected open fun getAllStatus(): Array<String> =
 | 
			
		||||
        arrayOf(intl.statusAll, intl.statusOngoing, intl.statusComplete)
 | 
			
		||||
 | 
			
		||||
    protected open fun getAllPrices(): Array<String> =
 | 
			
		||||
        arrayOf(intl.priceAll, intl.priceFree, intl.pricePaid)
 | 
			
		||||
    protected open fun getAllPrices(): Array<String> = emptyArray()
 | 
			
		||||
 | 
			
		||||
    override fun getFilterList(): FilterList {
 | 
			
		||||
        val filters = mutableListOf(
 | 
			
		||||
        val allAreas = getAllAreas()
 | 
			
		||||
        val allPrices = getAllPrices()
 | 
			
		||||
 | 
			
		||||
        val filters = listOfNotNull(
 | 
			
		||||
            StatusFilter(intl.statusLabel, getAllStatus()),
 | 
			
		||||
            SortFilter(intl.sortLabel, getAllSortOptions(), defaultPopularSort),
 | 
			
		||||
            PriceFilter(intl.priceLabel, getAllPrices()),
 | 
			
		||||
            GenreFilter(intl.genreLabel, getAllGenres())
 | 
			
		||||
            PriceFilter(intl.priceLabel, getAllPrices()).takeIf { allPrices.isNotEmpty() },
 | 
			
		||||
            GenreFilter(intl.genreLabel, getAllGenres()),
 | 
			
		||||
            AreaFilter(intl.areaLabel, allAreas).takeIf { allAreas.isNotEmpty() }
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val allAreas = getAllAreas()
 | 
			
		||||
 | 
			
		||||
        if (allAreas.isNotEmpty()) {
 | 
			
		||||
            filters += AreaFilter(intl.areaLabel, allAreas)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return FilterList(filters)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -414,6 +394,20 @@ abstract class Bilibili(
 | 
			
		||||
        return response
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected 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+"
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    protected 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()
 | 
			
		||||
 | 
			
		||||
    protected open fun HttpUrl.Builder.addCommonParameters(): HttpUrl.Builder = let {
 | 
			
		||||
        if (name == "BILIBILI COMICS") {
 | 
			
		||||
            addQueryParameter("lang", apiLang)
 | 
			
		||||
@ -451,16 +445,16 @@ abstract class Bilibili(
 | 
			
		||||
        const val PREFIX_ID_SEARCH = "id:"
 | 
			
		||||
        private val ID_SEARCH_PATTERN = "^id:(mc)?(\\d+)$".toRegex()
 | 
			
		||||
 | 
			
		||||
        private const val IMAGE_QUALITY_PREF_KEY = "chapterImageResolution"
 | 
			
		||||
        private val IMAGE_QUALITY_PREF_ENTRY_VALUES = arrayOf("1200w", "800w", "600w_50q")
 | 
			
		||||
        private val IMAGE_QUALITY_PREF_DEFAULT_VALUE = IMAGE_QUALITY_PREF_ENTRY_VALUES[0]
 | 
			
		||||
        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_DEFAULT_VALUE = IMAGE_QUALITY_PREF_ENTRY_VALUES[1]
 | 
			
		||||
 | 
			
		||||
        private const val IMAGE_FORMAT_PREF_KEY = "chapterImageFormat"
 | 
			
		||||
        private val IMAGE_FORMAT_PREF_ENTRIES = arrayOf("JPG", "WEBP", "PNG")
 | 
			
		||||
        private val IMAGE_FORMAT_PREF_ENTRY_VALUES = arrayOf("jpg", "webp", "png")
 | 
			
		||||
        private val IMAGE_FORMAT_PREF_DEFAULT_VALUE = IMAGE_FORMAT_PREF_ENTRY_VALUES[0]
 | 
			
		||||
 | 
			
		||||
        private const val THUMBNAIL_RESOLUTION = "@512w.jpg"
 | 
			
		||||
        const val THUMBNAIL_RESOLUTION = "@512w.jpg"
 | 
			
		||||
 | 
			
		||||
        private val DATE_FORMATTER by lazy {
 | 
			
		||||
            SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
 | 
			
		||||
 | 
			
		||||
@ -23,13 +23,18 @@ data class BilibiliComicDto(
 | 
			
		||||
    @SerialName("ep_list") val episodeList: List<BilibiliEpisodeDto> = emptyList(),
 | 
			
		||||
    val id: Int = 0,
 | 
			
		||||
    @SerialName("is_finish") val isFinish: Int = 0,
 | 
			
		||||
    @SerialName("temp_stop_update") val isOnHiatus: Boolean = false,
 | 
			
		||||
    @SerialName("season_id") val seasonId: Int = 0,
 | 
			
		||||
    val styles: List<String> = emptyList(),
 | 
			
		||||
    val title: String,
 | 
			
		||||
    @SerialName("update_weekday") val updateWeekdays: List<Int> = emptyList(),
 | 
			
		||||
    @SerialName("vertical_cover") val verticalCover: String = ""
 | 
			
		||||
) {
 | 
			
		||||
    val hasPaidChapters: Boolean
 | 
			
		||||
        get() = episodeList.any { episode -> episode.payMode == 1 && episode.payGold > 0 }
 | 
			
		||||
        get() = paidChaptersCount > 0
 | 
			
		||||
 | 
			
		||||
    val paidChaptersCount: Int
 | 
			
		||||
        get() = episodeList.filter { episode -> episode.payMode == 1 && episode.payGold > 0 }.size
 | 
			
		||||
 | 
			
		||||
    fun genres(paidLabel: String, emoji: String): List<String> =
 | 
			
		||||
        (if (hasPaidChapters) listOf("$emoji $paidLabel") else emptyList()) + styles
 | 
			
		||||
@ -54,8 +59,17 @@ data class BilibiliReader(
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class BilibiliImageDto(
 | 
			
		||||
    val path: String
 | 
			
		||||
)
 | 
			
		||||
    val path: String,
 | 
			
		||||
    @SerialName("x") val width: Int,
 | 
			
		||||
    @SerialName("y") val height: Int
 | 
			
		||||
) {
 | 
			
		||||
 | 
			
		||||
    fun url(quality: String, format: String): String {
 | 
			
		||||
        val imageWidth = if (quality == "raw+") "${width}w" else quality
 | 
			
		||||
 | 
			
		||||
        return "$path@$imageWidth.$format"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Serializable
 | 
			
		||||
data class BilibiliPageDto(
 | 
			
		||||
 | 
			
		||||
@ -6,20 +6,21 @@ data class BilibiliTag(val name: String, val id: Int) {
 | 
			
		||||
    override fun toString(): String = name
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GenreFilter(label: String, genres: Array<BilibiliTag>) :
 | 
			
		||||
    Filter.Select<BilibiliTag>(label, genres) {
 | 
			
		||||
    val selected: BilibiliTag
 | 
			
		||||
        get() = values[state]
 | 
			
		||||
open class EnhancedSelect<T>(name: String, values: Array<T>, state: Int = 0) :
 | 
			
		||||
    Filter.Select<T>(name, values, state) {
 | 
			
		||||
 | 
			
		||||
    val selected: T?
 | 
			
		||||
        get() = values.getOrNull(state)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GenreFilter(label: String, genres: Array<BilibiliTag>) :
 | 
			
		||||
    EnhancedSelect<BilibiliTag>(label, genres)
 | 
			
		||||
 | 
			
		||||
class AreaFilter(label: String, genres: Array<BilibiliTag>) :
 | 
			
		||||
    Filter.Select<BilibiliTag>(label, genres) {
 | 
			
		||||
    val selected: BilibiliTag
 | 
			
		||||
        get() = values[state]
 | 
			
		||||
}
 | 
			
		||||
    EnhancedSelect<BilibiliTag>(label, genres)
 | 
			
		||||
 | 
			
		||||
class SortFilter(label: String, options: Array<String>, state: Int = 0) :
 | 
			
		||||
    Filter.Select<String>(label, options, state)
 | 
			
		||||
class SortFilter(label: String, options: Array<BilibiliTag>, state: Int = 0) :
 | 
			
		||||
    EnhancedSelect<BilibiliTag>(label, options, state)
 | 
			
		||||
 | 
			
		||||
class StatusFilter(label: String, statuses: Array<String>) :
 | 
			
		||||
    Filter.Select<String>(label, statuses)
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,7 @@ class BilibiliGenerator : ThemeSourceGenerator {
 | 
			
		||||
 | 
			
		||||
    override val themeClass = "Bilibili"
 | 
			
		||||
 | 
			
		||||
    override val baseVersionCode: Int = 4
 | 
			
		||||
    override val baseVersionCode: Int = 5
 | 
			
		||||
 | 
			
		||||
    override val sources = listOf(
 | 
			
		||||
        MultiLang(
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,16 @@
 | 
			
		||||
package eu.kanade.tachiyomi.multisrc.bilibili
 | 
			
		||||
 | 
			
		||||
class BilibiliIntl(lang: String) {
 | 
			
		||||
import java.text.DateFormatSymbols
 | 
			
		||||
import java.text.NumberFormat
 | 
			
		||||
import java.util.Locale
 | 
			
		||||
 | 
			
		||||
class BilibiliIntl(private val lang: String) {
 | 
			
		||||
 | 
			
		||||
    private val locale by lazy { Locale.forLanguageTag(lang) }
 | 
			
		||||
 | 
			
		||||
    private val dateFormatSymbols by lazy { DateFormatSymbols(locale) }
 | 
			
		||||
 | 
			
		||||
    private val numberFormat by lazy { NumberFormat.getInstance(locale) }
 | 
			
		||||
 | 
			
		||||
    val statusLabel: String = when (lang) {
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE -> "进度"
 | 
			
		||||
@ -39,18 +49,20 @@ class BilibiliIntl(lang: String) {
 | 
			
		||||
        else -> "Ep. "
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val hasPaidChaptersWarning: String = when (lang) {
 | 
			
		||||
    fun hasPaidChaptersWarning(chapterCount: Int): String = when (lang) {
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE ->
 | 
			
		||||
            "${Bilibili.EMOJI_WARNING} 此漫画的付费章节已从章节列表中过滤。如果您已购买章节,请在 WebView " +
 | 
			
		||||
                "登录并刷新章节列表以阅读已购章节。"
 | 
			
		||||
            "${Bilibili.EMOJI_WARNING} 此漫画有 ${chapterCount.localized} 个付费章节,已在目录中隐藏。" +
 | 
			
		||||
                "如果你已购买,请在 WebView 登录并刷新目录,即可阅读已购章节。"
 | 
			
		||||
        SPANISH ->
 | 
			
		||||
            "${Bilibili.EMOJI_WARNING} ADVERTENCIA: Esta serie tiene capítulos pagos que fueron " +
 | 
			
		||||
                "filtrados de la lista de capítulos. Si ya compró y tiene alguno en su cuenta, " +
 | 
			
		||||
                "inicie sesión en WebView y actualice la lista de capítulos para leerlos."
 | 
			
		||||
            "${Bilibili.EMOJI_WARNING} ADVERTENCIA: Esta serie tiene ${chapterCount.localized} " +
 | 
			
		||||
                "capítulos pagos que fueron filtrados de la lista de capítulos. Si ya has " +
 | 
			
		||||
                "desbloqueado y tiene alguno en su cuenta, inicie sesión en WebView y " +
 | 
			
		||||
                "actualice la lista de capítulos para leerlos."
 | 
			
		||||
        else ->
 | 
			
		||||
            "${Bilibili.EMOJI_WARNING} WARNING: This series has paid chapters that were filtered " +
 | 
			
		||||
                "out from the chapter list. If you have already bought and have any in your " +
 | 
			
		||||
                "account, sign in through WebView and refresh the chapter list to read them."
 | 
			
		||||
            "${Bilibili.EMOJI_WARNING} WARNING: This series has ${chapterCount.localized} paid " +
 | 
			
		||||
                "chapters that were filtered out from the chapter list. If you have already " +
 | 
			
		||||
                "unlocked and have any in your account, sign in through WebView and refresh " +
 | 
			
		||||
                "the chapter list to read them."
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val imageQualityPrefTitle: String = when (lang) {
 | 
			
		||||
@ -61,8 +73,8 @@ class BilibiliIntl(lang: String) {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val imageQualityPrefEntries: Array<String> = when (lang) {
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE -> arrayOf("原图", "高", "低")
 | 
			
		||||
        else -> arrayOf("Raw", "HD", "SD")
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE -> arrayOf("原图+", "原图 (1600w)", "高 (1000w)", "低 (800w)")
 | 
			
		||||
        else -> arrayOf("Raw+", "Raw (1600w)", "HD (1000w)", "SD (800w)")
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val imageFormatPrefTitle: String = when (lang) {
 | 
			
		||||
@ -167,6 +179,37 @@ class BilibiliIntl(lang: String) {
 | 
			
		||||
        else -> "Failed to get the credential to read the chapter."
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val informationTitle: String = when (lang) {
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE -> "信息"
 | 
			
		||||
        SPANISH -> "Información"
 | 
			
		||||
        else -> "Information"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val totalChapterCount: String = when (lang) {
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE -> "章节总数"
 | 
			
		||||
        SPANISH -> "Número total de capítulos"
 | 
			
		||||
        else -> "Total chapter count"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    val updatedEvery: String = when (lang) {
 | 
			
		||||
        CHINESE, SIMPLIFIED_CHINESE -> "每周更新时间"
 | 
			
		||||
        SPANISH -> "Actualizado en"
 | 
			
		||||
        else -> "Updated every"
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getWeekdays(dayIndexes: List<Int>): String {
 | 
			
		||||
        val weekdays = dateFormatSymbols.weekdays
 | 
			
		||||
            .filter(String::isNotBlank)
 | 
			
		||||
            .map { dayName -> dayName.replaceFirstChar { it.uppercase(locale) } }
 | 
			
		||||
 | 
			
		||||
        return dayIndexes.joinToString { weekdays[it] }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun localize(value: Int) = value.localized
 | 
			
		||||
 | 
			
		||||
    private val Int.localized: String
 | 
			
		||||
        get() = numberFormat.format(this)
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        const val CHINESE = "zh"
 | 
			
		||||
        const val ENGLISH = "en"
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user