forked from AlmightyHak/extensions-source
Add Xiaoxintv(小宝影院) (#341)
This commit is contained in:
parent
e780630225
commit
21bc5b8bfb
8 changed files with 506 additions and 0 deletions
7
src/zh/xiaoxintv/build.gradle
Normal file
7
src/zh/xiaoxintv/build.gradle
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
ext {
|
||||||
|
extName = 'Xiaoxintv'
|
||||||
|
extClass = '.Xiaoxintv'
|
||||||
|
extVersionCode = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
BIN
src/zh/xiaoxintv/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/zh/xiaoxintv/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
BIN
src/zh/xiaoxintv/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/zh/xiaoxintv/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2 KiB |
BIN
src/zh/xiaoxintv/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/zh/xiaoxintv/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
BIN
src/zh/xiaoxintv/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/zh/xiaoxintv/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.9 KiB |
BIN
src/zh/xiaoxintv/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/zh/xiaoxintv/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
|
@ -0,0 +1,221 @@
|
||||||
|
@file:Suppress("LocalVariableName", "PropertyName")
|
||||||
|
|
||||||
|
package eu.kanade.tachiyomi.animeextension.zh.xiaoxintv
|
||||||
|
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
|
||||||
|
private const val PREF_KEY_FILTER_CONFIG_PREFIX = "STORED_SEARCH_CONFIG"
|
||||||
|
|
||||||
|
open class PathFilter(name: String, private val beans: Array<out SearchBean>) :
|
||||||
|
AnimeFilter.Select<String>(name, beans.map { it.name }.toTypedArray()) {
|
||||||
|
val selected
|
||||||
|
get() = beans[state]
|
||||||
|
}
|
||||||
|
|
||||||
|
class GroupFilter(name: String, filters: List<PathFilter>) :
|
||||||
|
AnimeFilter.Group<PathFilter>(name, filters)
|
||||||
|
|
||||||
|
internal enum class FilterType(val title: String) {
|
||||||
|
TYPE("类型"),
|
||||||
|
CLASS("分类"),
|
||||||
|
YEAR("年份"),
|
||||||
|
LANG("语言"),
|
||||||
|
SORT("排序"),
|
||||||
|
REGION("地区"),
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchBean {
|
||||||
|
val name: String
|
||||||
|
val ignore: Boolean
|
||||||
|
fun toPath(): String
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchType(
|
||||||
|
override val name: String,
|
||||||
|
val id: String,
|
||||||
|
override val ignore: Boolean = false,
|
||||||
|
) : SearchBean {
|
||||||
|
constructor(name: String, id: Int) : this(name, "$id")
|
||||||
|
|
||||||
|
override fun toPath() = "/id/$id"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun SearchType.toFilter(): PathFilter {
|
||||||
|
return PathFilter(name, arrayOf(this))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchSort(
|
||||||
|
override val name: String,
|
||||||
|
val by: String,
|
||||||
|
override val ignore: Boolean = false,
|
||||||
|
) : SearchBean {
|
||||||
|
override fun toPath() = "/by/$by"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchYear(override val name: String, override val ignore: Boolean = false) :
|
||||||
|
SearchBean {
|
||||||
|
override fun toPath() = "/year/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchLang(override val name: String, override val ignore: Boolean = false) :
|
||||||
|
SearchBean {
|
||||||
|
override fun toPath() = "/lang/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchClass(override val name: String, override val ignore: Boolean = false) :
|
||||||
|
SearchBean {
|
||||||
|
override fun toPath() = "/class/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchRegion(override val name: String, override val ignore: Boolean = false) :
|
||||||
|
SearchBean {
|
||||||
|
override fun toPath() = "/area/$name"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchFilterConfig(
|
||||||
|
val type: List<SearchType>,
|
||||||
|
val category: List<SearchClass> = emptyList(),
|
||||||
|
val year: List<SearchYear> = emptyList(),
|
||||||
|
val lang: List<SearchLang> = emptyList(),
|
||||||
|
val region: List<SearchRegion> = emptyList(),
|
||||||
|
) {
|
||||||
|
fun isEmpty() =
|
||||||
|
type.isEmpty() && category.isEmpty() && year.isEmpty() && lang.isEmpty() && region.isEmpty()
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun <reified T> c(): Class<T> {
|
||||||
|
return T::class.java
|
||||||
|
}
|
||||||
|
|
||||||
|
private val searchPriority = arrayOf(
|
||||||
|
c<SearchRegion>(),
|
||||||
|
c<SearchSort>(),
|
||||||
|
c<SearchClass>(),
|
||||||
|
c<SearchType>(),
|
||||||
|
c<SearchLang>(),
|
||||||
|
c<SearchYear>(),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun Iterable<SearchBean>.toPath(): String {
|
||||||
|
return this.asSequence().filterNot { it.ignore }
|
||||||
|
.groupBy { it::class.java }.flatMap { it.value.subList(it.value.size - 1, it.value.size) }
|
||||||
|
.sortedBy {
|
||||||
|
searchPriority.indexOf(it::class.java)
|
||||||
|
}
|
||||||
|
.joinToString(separator = "") { it.toPath() }.removePrefix("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
private val defaultLangList =
|
||||||
|
listOf(
|
||||||
|
SearchLang("全部", ignore = true),
|
||||||
|
SearchLang("国语"),
|
||||||
|
SearchLang("粤语"),
|
||||||
|
SearchLang("英语"),
|
||||||
|
SearchLang("其他"),
|
||||||
|
)
|
||||||
|
|
||||||
|
private val typeAll = SearchType("全部", "-1", ignore = true)
|
||||||
|
private val categoryAll = SearchClass("全部", ignore = true)
|
||||||
|
private val yearAll = SearchYear("全部", ignore = true)
|
||||||
|
private val regionAll = SearchRegion("全部", ignore = true)
|
||||||
|
|
||||||
|
private val defaultSearchFilterConfig = mapOf(
|
||||||
|
// anime
|
||||||
|
"5" to SearchFilterConfig(
|
||||||
|
type = listOf(typeAll, SearchType("国产动漫", 51), SearchType("日本动漫", 52)),
|
||||||
|
category = listOf(
|
||||||
|
categoryAll,
|
||||||
|
SearchClass("热血"),
|
||||||
|
SearchClass("格斗"),
|
||||||
|
SearchClass("其他"),
|
||||||
|
),
|
||||||
|
year = listOf(yearAll),
|
||||||
|
lang = defaultLangList,
|
||||||
|
),
|
||||||
|
// movie
|
||||||
|
"7" to SearchFilterConfig(
|
||||||
|
type = listOf(typeAll),
|
||||||
|
region = listOf(regionAll),
|
||||||
|
year = listOf(yearAll),
|
||||||
|
lang = defaultLangList,
|
||||||
|
),
|
||||||
|
// tv
|
||||||
|
"6" to SearchFilterConfig(
|
||||||
|
type = listOf(typeAll),
|
||||||
|
category = listOf(categoryAll),
|
||||||
|
year = listOf(yearAll),
|
||||||
|
lang = defaultLangList,
|
||||||
|
),
|
||||||
|
// variety show
|
||||||
|
"3" to SearchFilterConfig(
|
||||||
|
type = listOf(typeAll),
|
||||||
|
category = listOf(categoryAll),
|
||||||
|
year = listOf(yearAll),
|
||||||
|
lang = defaultLangList,
|
||||||
|
),
|
||||||
|
// documentary
|
||||||
|
"21" to SearchFilterConfig(
|
||||||
|
type = emptyList(),
|
||||||
|
region = listOf(regionAll),
|
||||||
|
year = listOf(yearAll),
|
||||||
|
lang = defaultLangList,
|
||||||
|
),
|
||||||
|
// short show
|
||||||
|
"64" to SearchFilterConfig(
|
||||||
|
type = listOf(typeAll),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun findDefaultSearchFilterConfig(majorTypeId: String): SearchFilterConfig {
|
||||||
|
return defaultSearchFilterConfig.getOrElse(majorTypeId) {
|
||||||
|
SearchFilterConfig(
|
||||||
|
listOf(typeAll),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun genFilterConfigKey(majorTypeId: String): String {
|
||||||
|
return PREF_KEY_FILTER_CONFIG_PREFIX + "_$majorTypeId"
|
||||||
|
}
|
||||||
|
|
||||||
|
internal val defaultMajorSearchTypeSet = arrayOf(
|
||||||
|
SearchType("动漫", 5),
|
||||||
|
SearchType("电影", 7),
|
||||||
|
SearchType("电视剧", 6),
|
||||||
|
SearchType("综艺", 3),
|
||||||
|
SearchType("纪录片", 21),
|
||||||
|
SearchType("短剧", 64),
|
||||||
|
)
|
||||||
|
|
||||||
|
internal val defaultSortTypeSet =
|
||||||
|
arrayOf(
|
||||||
|
SearchSort("时间", "time", ignore = true),
|
||||||
|
SearchSort("人气", "hits"),
|
||||||
|
SearchSort("评分", "score"),
|
||||||
|
)
|
||||||
|
|
||||||
|
fun SharedPreferences.findSearchFilterConfig(majorTypeId: String, json: Json): SearchFilterConfig {
|
||||||
|
// check shared preferences
|
||||||
|
return getString(genFilterConfigKey(majorTypeId), null)?.let { json.decodeFromString(it) }
|
||||||
|
?: findDefaultSearchFilterConfig(majorTypeId)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun SharedPreferences.saveSearchFilterConfig(
|
||||||
|
majorTypeId: String,
|
||||||
|
searchFilterConfig: SearchFilterConfig,
|
||||||
|
json: Json,
|
||||||
|
) {
|
||||||
|
edit().putString(genFilterConfigKey(majorTypeId), json.encodeToString(searchFilterConfig))
|
||||||
|
.apply()
|
||||||
|
}
|
|
@ -0,0 +1,278 @@
|
||||||
|
package eu.kanade.tachiyomi.animeextension.zh.xiaoxintv
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import kotlinx.serialization.json.jsonObject
|
||||||
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.Response
|
||||||
|
import org.jsoup.nodes.Document
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
|
private object HotSortFilter :
|
||||||
|
PathFilter(FilterType.SORT.title, arrayOf(SearchSort("人气", "hits")))
|
||||||
|
|
||||||
|
class Xiaoxintv : AnimeHttpSource() {
|
||||||
|
override val baseUrl: String
|
||||||
|
get() = "https://xiaoxintv.cc"
|
||||||
|
override val lang: String
|
||||||
|
get() = "zh"
|
||||||
|
override val name: String
|
||||||
|
get() = "小宝影院"
|
||||||
|
override val supportsLatest: Boolean
|
||||||
|
get() = true
|
||||||
|
|
||||||
|
private val majorSearchTypeSet: Array<SearchType>
|
||||||
|
get() = defaultMajorSearchTypeSet
|
||||||
|
private val searchSortTypeSet: Array<SearchSort>
|
||||||
|
get() = defaultSortTypeSet
|
||||||
|
private val filterUpdateRecord by lazy {
|
||||||
|
majorSearchTypeSet.associateWith {
|
||||||
|
false
|
||||||
|
}.toMutableMap()
|
||||||
|
}
|
||||||
|
private val json by injectLazy<Json>()
|
||||||
|
private val preferences: SharedPreferences by lazy {
|
||||||
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun animeDetailsParse(response: Response): SAnime {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
return SAnime.create().apply {
|
||||||
|
thumbnail_url =
|
||||||
|
document.select(".myui-vodlist__thumb.picture img").attr("data-original")
|
||||||
|
url = document.select(".myui-vodlist__thumb.picture").attr("href")
|
||||||
|
title = document.select(".myui-content__detail .title").text()
|
||||||
|
author = document.selectFirst("p.data:contains(主演:)")?.text()
|
||||||
|
artist = document.selectFirst("p.data:contains(导演:)")?.text()
|
||||||
|
description = document.selectFirst("p.data:contains(简介:)")?.ownText()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
return document.select("#playlist1 ul li").mapIndexed { index, element ->
|
||||||
|
SEpisode.create().apply {
|
||||||
|
url = element.select("a").attr("href")
|
||||||
|
name = element.attr("title")
|
||||||
|
episode_number = index.toFloat()
|
||||||
|
}
|
||||||
|
}.reversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findVideoUrl(document: Document): String {
|
||||||
|
val script = document.select("script:containsData(player_aaaa)").first()!!.data()
|
||||||
|
val info = script.substringAfter("player_aaaa=").let { json.parseToJsonElement(it) }
|
||||||
|
return info.jsonObject["url"]!!.jsonPrimitive.content
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun videoListParse(response: Response): List<Video> {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val videoUrl = findVideoUrl(document)
|
||||||
|
return listOf(Video(videoUrl, "小宝影院", videoUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesParse(response: Response): AnimesPage {
|
||||||
|
return searchFilterParse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int) = searchAnimeRequest(
|
||||||
|
page,
|
||||||
|
"",
|
||||||
|
AnimeFilterList(
|
||||||
|
majorSearchTypeSet[0].toFilter(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun popularAnimeParse(response: Response): AnimesPage {
|
||||||
|
return searchFilterParse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularAnimeRequest(page: Int) = searchAnimeRequest(
|
||||||
|
page,
|
||||||
|
"",
|
||||||
|
AnimeFilterList(
|
||||||
|
majorSearchTypeSet[0].toFilter(),
|
||||||
|
HotSortFilter,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun searchAnimeParse(response: Response): AnimesPage {
|
||||||
|
val requestUrl = response.request.url.toString()
|
||||||
|
if (requestUrl.contains("/vod/search")) {
|
||||||
|
return searchKeywordParse(response)
|
||||||
|
}
|
||||||
|
return searchFilterParse(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun searchFilterParse(response: Response): AnimesPage {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
tryUpdateFilters(response.request, document)
|
||||||
|
val items = document.select(".myui-vodlist__box").map {
|
||||||
|
SAnime.create().apply {
|
||||||
|
val thumbNode = it.select(".myui-vodlist__thumb")
|
||||||
|
url = thumbNode.attr("href")
|
||||||
|
thumbnail_url = thumbNode.attr("data-original")
|
||||||
|
title = thumbNode.attr("title")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val nextPageUrl = document.select(".myui-page a:contains(下一页)").attr("href")
|
||||||
|
return AnimesPage(items, !response.request.url.toString().endsWith(nextPageUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun tryUpdateFilters(request: Request, document: Document) {
|
||||||
|
val requestUrl = request.url.toString()
|
||||||
|
val match = filterUpdateRecord.firstNotNullOfOrNull {
|
||||||
|
if (requestUrl.endsWith(it.key.toPath())) {
|
||||||
|
it.key
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (match == null || filterUpdateRecord[match] == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
filterUpdateRecord[match] = true
|
||||||
|
var typeList: List<SearchType> = emptyList()
|
||||||
|
var langList: List<SearchLang> = emptyList()
|
||||||
|
var yearList: List<SearchYear> = emptyList()
|
||||||
|
var regionList: List<SearchRegion> = emptyList()
|
||||||
|
var classList: List<SearchClass> = emptyList()
|
||||||
|
document.select(".myui-panel_bd .myui-screen__list").forEach {
|
||||||
|
val li = it.select("li a")
|
||||||
|
val key = li[0].text()
|
||||||
|
val options = li.drop(1)
|
||||||
|
when (key) {
|
||||||
|
FilterType.TYPE.title -> {
|
||||||
|
typeList = options.mapIndexed { index, element ->
|
||||||
|
SearchType(
|
||||||
|
element.text(),
|
||||||
|
element.attr("href").substringAfter("id/")
|
||||||
|
.substringBefore("/").removeSuffix(".html"),
|
||||||
|
ignore = index == 0,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterType.LANG.title -> {
|
||||||
|
langList = options.mapIndexed { index, element ->
|
||||||
|
SearchLang(element.text(), ignore = index == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterType.YEAR.title -> {
|
||||||
|
yearList = options.mapIndexed { index, element ->
|
||||||
|
SearchYear(element.text(), ignore = index == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterType.REGION.title -> {
|
||||||
|
regionList = options.mapIndexed { index, element ->
|
||||||
|
SearchRegion(element.text(), ignore = index == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterType.CLASS.title -> {
|
||||||
|
classList = options.mapIndexed { index, element ->
|
||||||
|
SearchClass(element.text(), ignore = index == 0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val config = SearchFilterConfig(typeList, classList, yearList, langList, regionList)
|
||||||
|
if (config.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
preferences.saveSearchFilterConfig(match.id, config, json)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun searchKeywordParse(response: Response): AnimesPage {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
val items = document.select("#searchList li").map {
|
||||||
|
SAnime.create().apply {
|
||||||
|
val thumbNode = it.select("a.myui-vodlist__thumb")
|
||||||
|
url = thumbNode.attr("href")
|
||||||
|
thumbnail_url = thumbNode.attr("data-original")
|
||||||
|
title = thumbNode.attr("title")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val nextPageUrl = document.select(".myui-page a:contains(下一页)").attr("href")
|
||||||
|
return AnimesPage(items, !response.request.url.toString().endsWith(nextPageUrl))
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun keywordQuery(page: Int, query: String): Request {
|
||||||
|
val searchUrl = baseUrl.toHttpUrl().newBuilder()
|
||||||
|
.addPathSegments("index.php/vod/search")
|
||||||
|
if (page > 1) {
|
||||||
|
searchUrl.addPathSegments("page/$page/wd/$query")
|
||||||
|
} else {
|
||||||
|
searchUrl.addQueryParameter("wd", query)
|
||||||
|
}
|
||||||
|
return GET(searchUrl.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||||
|
if (query.isNotBlank()) {
|
||||||
|
return keywordQuery(page, query)
|
||||||
|
}
|
||||||
|
val searchUrl = baseUrl.toHttpUrl().newBuilder().addPathSegments("index.php/vod/show")
|
||||||
|
val filterPath = filters.flatMap {
|
||||||
|
if (it is GroupFilter) {
|
||||||
|
it.state
|
||||||
|
} else {
|
||||||
|
listOf(it)
|
||||||
|
}
|
||||||
|
}.filterIsInstance<PathFilter>().map { it.selected }.toPath()
|
||||||
|
if (filterPath.isEmpty()) {
|
||||||
|
searchUrl.addPathSegments(majorSearchTypeSet[0].toPath().removePrefix("/"))
|
||||||
|
} else {
|
||||||
|
searchUrl.addPathSegments(filterPath)
|
||||||
|
}
|
||||||
|
if (page > 1) {
|
||||||
|
searchUrl.addPathSegments("page/$page")
|
||||||
|
}
|
||||||
|
return GET(searchUrl.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun List<SearchBean>.toFilter(name: String): PathFilter? {
|
||||||
|
if (isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return PathFilter(name, toTypedArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFilterList(): AnimeFilterList {
|
||||||
|
val groupFilters = majorSearchTypeSet.map { majorType ->
|
||||||
|
val config = preferences.findSearchFilterConfig(majorType.id, json)
|
||||||
|
val filters = listOfNotNull(
|
||||||
|
config.type.toFilter(FilterType.TYPE.title),
|
||||||
|
config.region.toFilter(FilterType.REGION.title),
|
||||||
|
config.category.toFilter(FilterType.CLASS.title),
|
||||||
|
config.year.toFilter(FilterType.YEAR.title),
|
||||||
|
config.lang.toFilter(FilterType.LANG.title),
|
||||||
|
)
|
||||||
|
GroupFilter(majorType.name, filters)
|
||||||
|
}.toTypedArray()
|
||||||
|
return AnimeFilterList(
|
||||||
|
PathFilter("主分类", majorSearchTypeSet),
|
||||||
|
PathFilter(FilterType.SORT.title, searchSortTypeSet),
|
||||||
|
AnimeFilter.Header("展开下方与主分类对应分组可进行更多设置"),
|
||||||
|
*groupFilters,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue