Add iyf(爱壹帆) #616
9 changed files with 546 additions and 0 deletions
7
src/zh/iyf/build.gradle
Normal file
7
src/zh/iyf/build.gradle
Normal file
|
@ -0,0 +1,7 @@
|
|||
ext {
|
||||
extName = 'iyf'
|
||||
extClass = '.Iyf'
|
||||
extVersionCode = 1
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
BIN
src/zh/iyf/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/zh/iyf/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.7 KiB |
BIN
src/zh/iyf/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/zh/iyf/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
BIN
src/zh/iyf/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/zh/iyf/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
BIN
src/zh/iyf/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/zh/iyf/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
BIN
src/zh/iyf/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/zh/iyf/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -0,0 +1,197 @@
|
|||
package eu.kanade.tachiyomi.animeextension.zh.iyf
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
|
||||
open class PairSelectFilter(
|
||||
name: String,
|
||||
private val options: List<Pair<String, String>>,
|
||||
val key: String,
|
||||
) : AnimeFilter.Select<String>(name, options.map { it.first }.toTypedArray()) {
|
||||
val selected
|
||||
get() = options[state].second
|
||||
}
|
||||
|
||||
class TypeFilter(options: List<Pair<String, String>> = DEFAULT_TYPES) :
|
||||
PairSelectFilter("类型", options, "cid")
|
||||
|
||||
class RegionFilter(options: List<Pair<String, String>> = DEFAULT_REGIONS) :
|
||||
PairSelectFilter("地区", options, "region")
|
||||
|
||||
class LangFilter(options: List<Pair<String, String>> = DEFAULT_LANG) :
|
||||
PairSelectFilter("语言", options, "language")
|
||||
|
||||
class YearFilter(options: List<Pair<String, String>> = DEFAULT_YEAR) :
|
||||
PairSelectFilter("年份", options, "year")
|
||||
|
||||
class QualityFilter(options: List<Pair<String, String>> = DEFAULT_QUALITY) :
|
||||
PairSelectFilter("画质", options, "vipResource")
|
||||
|
||||
class StatusFilter(options: List<Pair<String, String>> = DEFAULT_STATUS) :
|
||||
PairSelectFilter("状态", options, "isserial")
|
||||
|
||||
class SortFilter(private val options: List<Pair<String, String>> = DEFAULT_SORT) :
|
||||
AnimeFilter.Sort("排序", options.map { it.first }.toTypedArray(), Selection(0, false)) {
|
||||
val desc
|
||||
get() = if (state?.ascending == true) {
|
||||
0
|
||||
} else {
|
||||
1
|
||||
}
|
||||
val orderBy
|
||||
get() = options[state?.index ?: 0].second
|
||||
}
|
||||
|
||||
//region default filter config
|
||||
private val DEFAULT_TYPES = listOf(
|
||||
"全部板块" to "0,1",
|
||||
"动漫" to "0,1,6",
|
||||
"电影" to "0,1,3",
|
||||
"电视剧" to "0,1,4",
|
||||
"综艺" to "0,1,5",
|
||||
"体育" to "0,1,95",
|
||||
"纪录片" to "0,1,7",
|
||||
"动漫-热血" to "0,1,6,46",
|
||||
"动漫-格斗" to "0,1,6,47",
|
||||
"动漫-机战" to "0,1,6,48",
|
||||
"动漫-少女" to "0,1,6,49",
|
||||
"动漫-竞技" to "0,1,6,51",
|
||||
"动漫-科幻" to "0,1,6,52",
|
||||
"动漫-魔幻" to "0,1,6,53",
|
||||
"动漫-爆笑" to "0,1,6,54",
|
||||
"动漫-推理" to "0,1,6,55",
|
||||
"动漫-冒险" to "0,1,6,121",
|
||||
"动漫-恋爱" to "0,1,6,120",
|
||||
"动漫-校园" to "0,1,6,119",
|
||||
"动漫-治愈" to "0,1,6,118",
|
||||
"动漫-泡面" to "0,1,6,117",
|
||||
"动漫-穿越" to "0,1,6,116",
|
||||
"动漫-灵异" to "0,1,6,56",
|
||||
"动漫-耽美" to "0,1,6,122",
|
||||
"动漫-剧场版" to "0,1,6,57",
|
||||
"动漫-其它" to "0,1,6,58",
|
||||
"电影-喜剧" to "0,1,3,19",
|
||||
"电影-爱情" to "0,1,3,20",
|
||||
"电影-动作" to "0,1,3,21",
|
||||
"电影-犯罪" to "0,1,3,22",
|
||||
"电影-科幻" to "0,1,3,23",
|
||||
"电影-奇幻" to "0,1,3,24",
|
||||
"电影-冒险" to "0,1,3,25",
|
||||
"电影-灾难" to "0,1,3,26",
|
||||
"电影-恐怖" to "0,1,3,123",
|
||||
"电影-惊悚" to "0,1,3,27",
|
||||
"电影-剧情" to "0,1,3,28",
|
||||
"电影-战争" to "0,1,3,29",
|
||||
"电影-歌舞" to "0,1,3,30",
|
||||
"电影-经典" to "0,1,3,31",
|
||||
"电影-悬疑" to "0,1,3,32",
|
||||
"电影-动画" to "0,1,3,113",
|
||||
"电影-同性" to "0,1,3,124",
|
||||
"电影-网络电影" to "0,1,3,125",
|
||||
"电视剧-偶像" to "0,1,4,129",
|
||||
"电视剧-爱情" to "0,1,4,146",
|
||||
"电视剧-言情" to "0,1,4,127",
|
||||
"电视剧-古装" to "0,1,4,126",
|
||||
"电视剧-历史" to "0,1,4,141",
|
||||
"电视剧-玄幻" to "0,1,4,142",
|
||||
"电视剧-谍战" to "0,1,4,136",
|
||||
"电视剧-历险" to "0,1,4,143",
|
||||
"电视剧-都市" to "0,1,4,132",
|
||||
"电视剧-科幻" to "0,1,4,144",
|
||||
"电视剧-军旅" to "0,1,4,135",
|
||||
"电视剧-喜剧" to "0,1,4,133",
|
||||
"电视剧-武侠" to "0,1,4,128",
|
||||
"电视剧-江湖" to "0,1,4,145",
|
||||
"电视剧-罪案" to "0,1,4,138",
|
||||
"电视剧-青春" to "0,1,4,131",
|
||||
"电视剧-家庭" to "0,1,4,130",
|
||||
"电视剧-战争" to "0,1,4,134",
|
||||
"电视剧-悬疑" to "0,1,4,137",
|
||||
"电视剧-穿越" to "0,1,4,139",
|
||||
"电视剧-宫廷" to "0,1,4,140",
|
||||
"电视剧-神话" to "0,1,4,147",
|
||||
"电视剧-商战" to "0,1,4,148",
|
||||
"电视剧-警匪" to "0,1,4,149",
|
||||
"电视剧-动作" to "0,1,4,150",
|
||||
"电视剧-惊悚" to "0,1,4,151",
|
||||
"电视剧-剧情" to "0,1,4,152",
|
||||
"电视剧-同性" to "0,1,4,153",
|
||||
"电视剧-奇幻" to "0,1,4,154",
|
||||
"综艺-真人秀" to "0,1,5,39",
|
||||
"综艺-选秀" to "0,1,5,38",
|
||||
"综艺-网综" to "0,1,5,94",
|
||||
"综艺-脱口秀" to "0,1,5,43",
|
||||
"综艺-搞笑" to "0,1,5,40",
|
||||
"综艺-竞技" to "0,1,5,91",
|
||||
"综艺-情感" to "0,1,5,33",
|
||||
"综艺-访谈" to "0,1,5,34",
|
||||
"综艺-演唱会" to "0,1,5,44",
|
||||
"综艺-晚会" to "0,1,5,92",
|
||||
"综艺-其它" to "0,1,5,45",
|
||||
"体育-奥运" to "0,1,95,99",
|
||||
"体育-综合" to "0,1,95,98",
|
||||
"体育-篮球" to "0,1,95,97",
|
||||
"体育-足球" to "0,1,95,96",
|
||||
"纪录片-文化" to "0,1,7,50",
|
||||
"纪录片-探索" to "0,1,7,59",
|
||||
"纪录片-军事" to "0,1,7,60",
|
||||
"纪录片-解密" to "0,1,7,61",
|
||||
"纪录片-科技" to "0,1,7,62",
|
||||
"纪录片-历史" to "0,1,7,63",
|
||||
"纪录片-人物" to "0,1,7,64",
|
||||
"纪录片-自然" to "0,1,7,66",
|
||||
"纪录片-其它" to "0,1,7,67",
|
||||
)
|
||||
private val DEFAULT_REGIONS = listOf(
|
||||
"全部地区" to "",
|
||||
"大陆" to "大陆",
|
||||
"香港" to "香港",
|
||||
"台湾" to "台湾",
|
||||
"日本" to "日本",
|
||||
"韩国" to "韩国",
|
||||
"欧美" to "欧美",
|
||||
"英国" to "英国",
|
||||
"泰国" to "泰国",
|
||||
"其它" to "其它",
|
||||
)
|
||||
private val DEFAULT_LANG = listOf(
|
||||
"全部语言" to "",
|
||||
"国语" to "国语",
|
||||
"粤语" to "粤语",
|
||||
"英语" to "英语",
|
||||
"韩语" to "韩语",
|
||||
"日语" to "日语",
|
||||
"西班牙语" to "西班牙语",
|
||||
"法语" to "法语",
|
||||
"德语" to "德语",
|
||||
"意大利语" to "意大利语",
|
||||
"泰国语" to "泰国语",
|
||||
"其它" to "其它",
|
||||
)
|
||||
private val DEFAULT_YEAR = listOf(
|
||||
"全部年份" to "",
|
||||
"今年" to "今年",
|
||||
"去年" to "去年",
|
||||
"更早" to "更早",
|
||||
"90年代" to "90年代",
|
||||
"80年代" to "80年代",
|
||||
"怀旧" to "怀旧",
|
||||
)
|
||||
private val DEFAULT_STATUS = listOf(
|
||||
"全部" to "-1",
|
||||
"全集" to "0",
|
||||
"连载中" to "1",
|
||||
)
|
||||
private val DEFAULT_QUALITY = listOf(
|
||||
"全部画质" to "",
|
||||
"4K" to "4K",
|
||||
"1080P" to "1080P",
|
||||
"900P" to "900P",
|
||||
"720P" to "720P",
|
||||
)
|
||||
private val DEFAULT_SORT = listOf(
|
||||
"添加时间" to "0",
|
||||
"更新时间" to "1",
|
||||
"人气高低" to "2",
|
||||
"评分高低" to "3",
|
||||
)
|
||||
//endregion
|
265
src/zh/iyf/src/eu/kanade/tachiyomi/animeextension/zh/iyf/Iyf.kt
Normal file
265
src/zh/iyf/src/eu/kanade/tachiyomi/animeextension/zh/iyf/Iyf.kt
Normal file
|
@ -0,0 +1,265 @@
|
|||
package eu.kanade.tachiyomi.animeextension.zh.iyf
|
||||
|
||||
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.network.POST
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import eu.kanade.tachiyomi.util.parseAs
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.security.MessageDigest
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class Iyf : AnimeHttpSource() {
|
||||
override val baseUrl: String
|
||||
get() = "https://www.iyf.tv"
|
||||
override val lang: String
|
||||
get() = "zh"
|
||||
override val name: String
|
||||
get() = "爱壹帆"
|
||||
override val supportsLatest: Boolean
|
||||
get() = true
|
||||
|
||||
override fun headersBuilder(): Headers.Builder {
|
||||
// Force the use of desktop user agent.
|
||||
return super.headersBuilder().set(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/132.0.0.0 Safari/537.36",
|
||||
)
|
||||
}
|
||||
|
||||
private val json by injectLazy<Json>()
|
||||
private val pConfig: PConfig by lazy {
|
||||
val doc = client.newCall(GET("$baseUrl/list", headers)).execute().asJsoup()
|
||||
val script = doc.selectFirst("script:containsData(injectJson)")!!.data()
|
||||
val pConfigStr =
|
||||
script.substringAfter("\"pConfig\":").let { it.substring(0, it.indexOf("}") + 1) }
|
||||
val pConfig = json.decodeFromString<JsonElement>(pConfigStr).jsonObject
|
||||
PConfig(
|
||||
publicKey = pConfig["publicKey"]!!.jsonPrimitive.content,
|
||||
privateKey = pConfig["privateKey"]!!.jsonArray[0].jsonPrimitive.content,
|
||||
)
|
||||
}
|
||||
private val popularAnimeFilterList = AnimeFilterList(
|
||||
TypeFilter(listOf("动漫" to "0,1,6")),
|
||||
SortFilter(listOf("人气高低" to "2")),
|
||||
)
|
||||
private val latestAnimeFilterList = AnimeFilterList(
|
||||
TypeFilter(listOf("动漫" to "0,1,6")),
|
||||
SortFilter(listOf("更新时间" to "1")),
|
||||
)
|
||||
private val episodeDateFormat by lazy {
|
||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault())
|
||||
}
|
||||
private val searchSortFilter by lazy {
|
||||
SortFilter(listOf("匹配度" to "4"))
|
||||
}
|
||||
|
||||
override fun animeDetailsRequest(anime: SAnime): Request {
|
||||
val vid = "$baseUrl${anime.url}".toHttpUrl().pathSegments.last()
|
||||
val detailUrl = "https://m10.iyf.tv/v3/video/detail".toHttpUrl().newBuilder()
|
||||
detailUrl.addQueryParameter("cinema", "1")
|
||||
.addQueryParameter("device", "1")
|
||||
.addQueryParameter("player", "CkPlayer")
|
||||
.addQueryParameter("tech", "HLS")
|
||||
.addQueryParameter("country", "HU")
|
||||
.addQueryParameter("lang", "cns")
|
||||
.addQueryParameter("v", "1")
|
||||
.addQueryParameter("id", vid)
|
||||
.addQueryParameter("region", "SG")
|
||||
.appendSignature()
|
||||
return GET(detailUrl.build(), headers)
|
||||
}
|
||||
|
||||
override fun animeDetailsParse(response: Response): SAnime {
|
||||
val resp = response.parseAs<CommonResponse<VideoDetail>>()
|
||||
val detail = resp.data.info[0]
|
||||
return SAnime.create().apply {
|
||||
title = detail.title
|
||||
thumbnail_url = detail.imgPath
|
||||
author = detail.directors.joinToString()
|
||||
artist = detail.stars.joinToString()
|
||||
genre = detail.keyWord.split(",").joinToString()
|
||||
status = if (detail.serialCount == 0) {
|
||||
SAnime.COMPLETED
|
||||
} else {
|
||||
SAnime.ONGOING
|
||||
}
|
||||
description = """
|
||||
添加:${detail.addDate}
|
||||
更新:${detail.updateWeekly}
|
||||
简介:${detail.context}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
override fun episodeListRequest(anime: SAnime): Request {
|
||||
val httpUrl = "$baseUrl${anime.url}".toHttpUrl()
|
||||
val vid = httpUrl.pathSegments.last()
|
||||
val cid = httpUrl.fragment
|
||||
val playlistUrl = "https://m10.iyf.tv/v3/video/languagesplaylist".toHttpUrl().newBuilder()
|
||||
playlistUrl.addQueryParameter("cinema", "1")
|
||||
.addQueryParameter("vid", vid)
|
||||
.addQueryParameter("lsk", "1")
|
||||
.addQueryParameter("taxis", "0")
|
||||
.addQueryParameter("cid", cid)
|
||||
.appendSignature()
|
||||
return GET(playlistUrl.build(), headers)
|
||||
}
|
||||
|
||||
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||
val resp = response.parseAs<CommonResponse<PlayList>>()
|
||||
val playList = resp.data.info[0].playList
|
||||
return playList.map {
|
||||
SEpisode.create().apply {
|
||||
url = "/${it.key}"
|
||||
name = it.name
|
||||
date_upload =
|
||||
runCatching { episodeDateFormat.parse(it.updateDate)?.time }.getOrNull() ?: 0L
|
||||
}
|
||||
}.asReversed()
|
||||
}
|
||||
|
||||
override fun videoListRequest(episode: SEpisode): Request {
|
||||
val vid = "$baseUrl${episode.url}".toHttpUrl().pathSegments.last()
|
||||
val playUrl = "https://m10.iyf.tv/v3/video/play".toHttpUrl().newBuilder()
|
||||
playUrl.addQueryParameter("cinema", "1")
|
||||
.addQueryParameter("id", vid)
|
||||
.addQueryParameter("a", "0")
|
||||
.addQueryParameter("lang", "none")
|
||||
.addQueryParameter("usersign", "1")
|
||||
.addQueryParameter("region", "SG")
|
||||
.addQueryParameter("device", "1")
|
||||
.addQueryParameter("isMasterSupport", "1")
|
||||
.appendSignature()
|
||||
return GET(playUrl.build(), headers)
|
||||
}
|
||||
|
||||
override fun videoListParse(response: Response): List<Video> {
|
||||
val resp = response.parseAs<CommonResponse<Play>>()
|
||||
val play = resp.data.info[0]
|
||||
return play.clarity.filter { it.path != null }.map {
|
||||
val url = it.path!!.rtmp.toHttpUrl().newBuilder().removeAllQueryParameters("us").build()
|
||||
.toString()
|
||||
Video(url, it.title, url)
|
||||
}
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response): AnimesPage = searchAnimeParse(response)
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request =
|
||||
searchAnimeRequest(page, "", latestAnimeFilterList)
|
||||
|
||||
override fun popularAnimeParse(response: Response): AnimesPage = searchAnimeParse(response)
|
||||
|
||||
override fun popularAnimeRequest(page: Int): Request =
|
||||
searchAnimeRequest(page, "", popularAnimeFilterList)
|
||||
|
||||
override fun searchAnimeParse(response: Response): AnimesPage {
|
||||
val resp = response.parseAs<CommonResponse<SearchResult>>()
|
||||
val result = resp.data.info[0].result
|
||||
return AnimesPage(
|
||||
result.map {
|
||||
SAnime.create().apply {
|
||||
url = "/play/${it.vid}#${it.videoClassID}"
|
||||
title = it.title
|
||||
thumbnail_url = it.image
|
||||
}
|
||||
},
|
||||
result.size >= PAGE_SIZE,
|
||||
)
|
||||
}
|
||||
|
||||
private fun keywordSearchRequest(page: Int, query: String): Request {
|
||||
val searchUrlBuilder = "https://rankv21.iyf.tv/v3/list/briefsearch".toHttpUrl().newBuilder()
|
||||
searchUrlBuilder.addQueryParameter("tags", query)
|
||||
val sortFilter = searchSortFilter
|
||||
searchUrlBuilder.addQueryParameter("orderby", sortFilter.orderBy)
|
||||
.addQueryParameter("page", "$page")
|
||||
.addQueryParameter("size", "$PAGE_SIZE")
|
||||
.addQueryParameter("desc", "${sortFilter.desc}")
|
||||
.addQueryParameter("isserial", "-1")
|
||||
val searchUrl = searchUrlBuilder.build()
|
||||
return POST(
|
||||
searchUrl.toString(),
|
||||
headers,
|
||||
FormBody.Builder().add("tags", query)
|
||||
.addEncoded("vv", signature(searchUrl.query ?: "", pConfig))
|
||||
.addEncoded("pub", pConfig.publicKey)
|
||||
.build(),
|
||||
)
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
if (query.isNotEmpty()) {
|
||||
return keywordSearchRequest(page, query)
|
||||
}
|
||||
val searchUrl = "https://m10.iyf.tv/api/list/Search".toHttpUrl().newBuilder()
|
||||
searchUrl.addQueryParameter("cinema", "1")
|
||||
.addQueryParameter("page", "$page")
|
||||
.addQueryParameter("size", "$PAGE_SIZE")
|
||||
filters.list.filterIsInstance<SortFilter>().firstOrNull()?.let {
|
||||
searchUrl.addQueryParameter("orderby", it.orderBy)
|
||||
.addQueryParameter("desc", "${it.desc}")
|
||||
}
|
||||
filters.list.filterIsInstance<PairSelectFilter>().forEach {
|
||||
if (it.selected.isNotEmpty()) {
|
||||
searchUrl.addQueryParameter(it.key, it.selected)
|
||||
}
|
||||
}
|
||||
searchUrl.addQueryParameter("isIndex", "-1")
|
||||
.addQueryParameter("isfree", "-1")
|
||||
// add signature
|
||||
searchUrl.appendSignature()
|
||||
return GET(searchUrl.build(), headers)
|
||||
}
|
||||
|
||||
private fun HttpUrl.Builder.appendSignature(): HttpUrl.Builder {
|
||||
addQueryParameter("vv", signature(build().query ?: "", pConfig))
|
||||
addQueryParameter("pub", pConfig.publicKey)
|
||||
return this
|
||||
}
|
||||
|
||||
private fun signature(query: String, pConfig: PConfig): String {
|
||||
val s = "${pConfig.publicKey}&${query.lowercase()}&${pConfig.privateKey}"
|
||||
return MessageDigest.getInstance("MD5").digest(s.toByteArray())
|
||||
.joinToString(separator = "") { "%02x".format(it) }
|
||||
}
|
||||
|
||||
override fun getFilterList(): AnimeFilterList {
|
||||
return AnimeFilterList(
|
||||
TypeFilter(),
|
||||
SortFilter(),
|
||||
RegionFilter(),
|
||||
LangFilter(),
|
||||
YearFilter(),
|
||||
QualityFilter(),
|
||||
StatusFilter(),
|
||||
)
|
||||
}
|
||||
|
||||
private class PConfig(
|
||||
val publicKey: String,
|
||||
val privateKey: String,
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val PAGE_SIZE = 32
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package eu.kanade.tachiyomi.animeextension.zh.iyf
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.JsonNames
|
||||
|
||||
@Serializable
|
||||
class CommonResponse<T>(
|
||||
val data: Data<T>,
|
||||
) {
|
||||
@Serializable
|
||||
class Data<T>(
|
||||
val info: List<T>,
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class SearchResult(
|
||||
val result: List<SearchResultItem>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SearchResultItem(
|
||||
@JsonNames("imgPath")
|
||||
val image: String,
|
||||
val key: String?,
|
||||
val title: String,
|
||||
val videoClassID: String,
|
||||
val contxt: String,
|
||||
) {
|
||||
val vid: String
|
||||
get() = key ?: contxt
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class VideoDetail(
|
||||
@SerialName("add_date")
|
||||
val addDate: String,
|
||||
@SerialName("contxt")
|
||||
val context: String,
|
||||
@SerialName("updateweekly")
|
||||
val updateWeekly: String,
|
||||
val imgPath: String,
|
||||
val title: String,
|
||||
val directors: List<String>,
|
||||
val stars: List<String>,
|
||||
val keyWord: String,
|
||||
val serialCount: Int,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PlayList(
|
||||
val playList: List<PlayListItem>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PlayListItem(
|
||||
val key: String,
|
||||
val name: String,
|
||||
val updateDate: String,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class Play(
|
||||
val clarity: List<PlayClarity>,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class PlayClarity(
|
||||
val title: String,
|
||||
val path: Path?,
|
||||
) {
|
||||
@Serializable
|
||||
class Path(
|
||||
val rtmp: String,
|
||||
)
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue