forked from Kohi-den/extensions-source
Merged with dark25 (#636)
* merge merged lib, lib-multisrc, all, ar, de, en, es, fr, hi, id, it, pt, tr src from dark25 * patch
This commit is contained in:
parent
9f385108fc
commit
1384df62f3
350 changed files with 12176 additions and 1064 deletions
|
@ -1,7 +1,7 @@
|
|||
ext {
|
||||
extName = 'Torrentio Anime (Torrent / Debrid)'
|
||||
extClass = '.Torrentio'
|
||||
extVersionCode = 11
|
||||
extVersionCode = 14
|
||||
containsNsfw = false
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
package eu.kanade.tachiyomi.animeextension.all.torrentioanime
|
||||
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
|
||||
object AniListFilters {
|
||||
open class QueryPartFilter(
|
||||
displayName: String,
|
||||
val vals: Array<Pair<String, String>>,
|
||||
) : AnimeFilter.Select<String>(
|
||||
displayName,
|
||||
vals.map { it.first }.toTypedArray(),
|
||||
) {
|
||||
fun toQueryPart() = vals[state].second
|
||||
}
|
||||
|
||||
open class CheckBoxFilterList(name: String, val pairs: Array<Pair<String, String>>) :
|
||||
AnimeFilter.Group<AnimeFilter.CheckBox>(name, pairs.map { CheckBoxVal(it.first, false) })
|
||||
|
||||
private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state)
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
|
||||
return (getFirst<R>() as QueryPartFilter).toQueryPart()
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.getFirst(): R {
|
||||
return first { it is R } as R
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.parseCheckboxList(
|
||||
options: Array<Pair<String, String>>,
|
||||
): List<String> {
|
||||
return (getFirst<R>() as CheckBoxFilterList).state
|
||||
.filter { it.state }
|
||||
.map { checkBox -> options.find { it.first == checkBox.name }!!.second }
|
||||
.filter(String::isNotBlank)
|
||||
}
|
||||
|
||||
private inline fun <reified R> AnimeFilterList.getSort(): String {
|
||||
val state = (getFirst<R>() as AnimeFilter.Sort).state ?: return ""
|
||||
val index = state.index
|
||||
val suffix = if (state.ascending) "" else "_DESC"
|
||||
return AniListFiltersData.SORT_LIST[index].second + suffix
|
||||
}
|
||||
|
||||
class GenreFilter : CheckBoxFilterList("Genres", AniListFiltersData.GENRE_LIST)
|
||||
class YearFilter : QueryPartFilter("Year", AniListFiltersData.YEAR_LIST)
|
||||
class SeasonFilter : QueryPartFilter("Season", AniListFiltersData.SEASON_LIST)
|
||||
class FormatFilter : CheckBoxFilterList("Format", AniListFiltersData.FORMAT_LIST)
|
||||
class StatusFilter : QueryPartFilter("Airing Status", AniListFiltersData.STATUS_LIST)
|
||||
|
||||
class SortFilter : AnimeFilter.Sort(
|
||||
"Sort",
|
||||
AniListFiltersData.SORT_LIST.map { it.first }.toTypedArray(),
|
||||
Selection(1, false),
|
||||
)
|
||||
|
||||
val FILTER_LIST get() = AnimeFilterList(
|
||||
SortFilter(),
|
||||
FormatFilter(),
|
||||
GenreFilter(),
|
||||
YearFilter(),
|
||||
SeasonFilter(),
|
||||
StatusFilter(),
|
||||
|
||||
)
|
||||
|
||||
class FilterSearchParams(
|
||||
val sort: String = "",
|
||||
val format: List<String> = emptyList(),
|
||||
val genres: List<String> = emptyList(),
|
||||
val year: String = "",
|
||||
val season: String = "",
|
||||
val status: String = "",
|
||||
|
||||
)
|
||||
|
||||
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
|
||||
if (filters.isEmpty()) return FilterSearchParams()
|
||||
|
||||
return FilterSearchParams(
|
||||
filters.getSort<SortFilter>(),
|
||||
filters.parseCheckboxList<FormatFilter>(AniListFiltersData.FORMAT_LIST),
|
||||
filters.parseCheckboxList<GenreFilter>(AniListFiltersData.GENRE_LIST),
|
||||
filters.asQueryPart<YearFilter>(),
|
||||
filters.asQueryPart<SeasonFilter>(),
|
||||
filters.asQueryPart<StatusFilter>(),
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
private object AniListFiltersData {
|
||||
val GENRE_LIST = arrayOf(
|
||||
Pair("Action", "Action"),
|
||||
Pair("Adventure", "Adventure"),
|
||||
Pair("Comedy", "Comedy"),
|
||||
Pair("Drama", "Drama"),
|
||||
Pair("Ecchi", "Ecchi"),
|
||||
Pair("Fantasy", "Fantasy"),
|
||||
Pair("Horror", "Horror"),
|
||||
Pair("Mahou Shoujo", "Mahou Shoujo"),
|
||||
Pair("Mecha", "Mecha"),
|
||||
Pair("Music", "Music"),
|
||||
Pair("Mystery", "Mystery"),
|
||||
Pair("Psychological", "Psychological"),
|
||||
Pair("Romance", "Romance"),
|
||||
Pair("Sci-Fi", "Sci-Fi"),
|
||||
Pair("Slice of Life", "Slice of Life"),
|
||||
Pair("Sports", "Sports"),
|
||||
Pair("Supernatural", "Supernatural"),
|
||||
Pair("Thriller", "Thriller"),
|
||||
)
|
||||
|
||||
val YEAR_LIST: Array<Pair<String, String>> = arrayOf(
|
||||
Pair("Any", ""),
|
||||
) + (1940..2025).reversed().map { Pair(it.toString(), it.toString()) }.toTypedArray()
|
||||
|
||||
val SEASON_LIST = arrayOf(
|
||||
Pair("Any", ""),
|
||||
Pair("Winter", "WINTER"),
|
||||
Pair("Spring", "SPRING"),
|
||||
Pair("Summer", "SUMMER"),
|
||||
Pair("Fall", "FALL"),
|
||||
)
|
||||
|
||||
val FORMAT_LIST = arrayOf(
|
||||
Pair("Any", ""),
|
||||
Pair("TV Show", "TV"),
|
||||
Pair("Movie", "MOVIE"),
|
||||
Pair("TV Short", "TV_SHORT"),
|
||||
Pair("Special", "SPECIAL"),
|
||||
Pair("OVA", "OVA"),
|
||||
Pair("ONA", "ONA"),
|
||||
Pair("Music", "MUSIC"),
|
||||
)
|
||||
|
||||
val STATUS_LIST = arrayOf(
|
||||
Pair("Any", ""),
|
||||
Pair("Airing", "RELEASING"),
|
||||
Pair("Finished", "FINISHED"),
|
||||
Pair("Not Yet Aired", "NOT_YET_RELEASED"),
|
||||
Pair("Cancelled", "CANCELLED"),
|
||||
)
|
||||
|
||||
val SORT_LIST = arrayOf(
|
||||
Pair("Title", "TITLE_ENGLISH"),
|
||||
Pair("Popularity", "POPULARITY"),
|
||||
Pair("Average Score", "SCORE"),
|
||||
Pair("Trending", "TRENDING"),
|
||||
Pair("Favorites", "FAVOURITES"),
|
||||
Pair("Date Added", "ID"),
|
||||
Pair("Release Date", "START_DATE"),
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,159 @@
|
|||
package eu.kanade.tachiyomi.animeextension.all.torrentioanime
|
||||
|
||||
private fun String.toQuery() = this.trimIndent().replace("%", "$")
|
||||
|
||||
fun anilistQuery() = """
|
||||
query (
|
||||
%page: Int,
|
||||
%perPage: Int,
|
||||
%sort: [MediaSort],
|
||||
%search: String,
|
||||
%genres: [String],
|
||||
%year: String,
|
||||
%seasonYear: Int,
|
||||
%season: MediaSeason,
|
||||
%format: [MediaFormat],
|
||||
%status: [MediaStatus],
|
||||
) {
|
||||
Page(page: %page, perPage: %perPage) {
|
||||
pageInfo {
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
media(
|
||||
type: ANIME,
|
||||
sort: %sort,
|
||||
search: %search,
|
||||
status_in: %status,
|
||||
genre_in: %genres,
|
||||
startDate_like: %year,
|
||||
seasonYear: %seasonYear,
|
||||
season: %season,
|
||||
format_in: %format
|
||||
) {
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
}
|
||||
coverImage {
|
||||
extraLarge
|
||||
large
|
||||
}
|
||||
description
|
||||
status
|
||||
tags {
|
||||
name
|
||||
}
|
||||
genres
|
||||
studios {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
countryOfOrigin
|
||||
isAdult
|
||||
}
|
||||
}
|
||||
}
|
||||
""".toQuery()
|
||||
|
||||
fun anilistLatestQuery() = """
|
||||
query (%page: Int, %perPage: Int, %sort: [AiringSort]) {
|
||||
Page(page: %page, perPage: %perPage) {
|
||||
pageInfo {
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
airingSchedules(
|
||||
airingAt_greater: 0,
|
||||
airingAt_lesser: ${System.currentTimeMillis() / 1000 - 10000},
|
||||
sort: %sort
|
||||
) {
|
||||
media {
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
}
|
||||
coverImage {
|
||||
extraLarge
|
||||
large
|
||||
}
|
||||
description
|
||||
status
|
||||
tags {
|
||||
name
|
||||
}
|
||||
genres
|
||||
studios {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
countryOfOrigin
|
||||
isAdult
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".toQuery()
|
||||
|
||||
fun getDetailsQuery() = """
|
||||
query media(%id: Int) {
|
||||
Media(id: %id) {
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
}
|
||||
coverImage {
|
||||
extraLarge
|
||||
large
|
||||
medium
|
||||
}
|
||||
description
|
||||
season
|
||||
seasonYear
|
||||
format
|
||||
status
|
||||
genres
|
||||
episodes
|
||||
format
|
||||
countryOfOrigin
|
||||
isAdult
|
||||
tags{
|
||||
name
|
||||
}
|
||||
studios {
|
||||
nodes {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".toQuery()
|
||||
|
||||
fun getEpisodeQuery() = """
|
||||
query media(%id: Int, %type: MediaType) {
|
||||
Media(id: %id, type: %type) {
|
||||
episodes
|
||||
nextAiringEpisode {
|
||||
episode
|
||||
}
|
||||
}
|
||||
}
|
||||
""".toQuery()
|
||||
|
||||
fun getMalIdQuery() = """
|
||||
query media(%id: Int, %type: MediaType) {
|
||||
Media(id: %id, type: %type) {
|
||||
idMal
|
||||
id
|
||||
}
|
||||
}
|
||||
""".toQuery()
|
|
@ -25,15 +25,19 @@ import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
|||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.awaitSuccess
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.add
|
||||
import kotlinx.serialization.json.buildJsonObject
|
||||
import kotlinx.serialization.json.put
|
||||
import kotlinx.serialization.json.putJsonArray
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.Jsoup
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.net.URL
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
|
@ -62,93 +66,9 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
.add("query", query)
|
||||
.add("variables", variables)
|
||||
.build()
|
||||
|
||||
return POST("https://graphql.anilist.co", body = requestBody)
|
||||
}
|
||||
|
||||
// ============================== Anilist Meta List ======================
|
||||
private fun anilistQuery(): String {
|
||||
return """
|
||||
query (${"$"}page: Int, ${"$"}perPage: Int, ${"$"}sort: [MediaSort], ${"$"}search: String) {
|
||||
Page(page: ${"$"}page, perPage: ${"$"}perPage) {
|
||||
pageInfo{
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
media(type: ANIME, sort: ${"$"}sort, search: ${"$"}search, status_in:[RELEASING,FINISHED,NOT_YET_RELEASED]) {
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
}
|
||||
coverImage {
|
||||
extraLarge
|
||||
large
|
||||
}
|
||||
description
|
||||
status
|
||||
tags{
|
||||
name
|
||||
}
|
||||
genres
|
||||
studios {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
countryOfOrigin
|
||||
isAdult
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
private fun anilistLatestQuery(): String {
|
||||
return """
|
||||
query (${"$"}page: Int, ${"$"}perPage: Int, ${"$"}sort: [AiringSort]) {
|
||||
Page(page: ${"$"}page, perPage: ${"$"}perPage) {
|
||||
pageInfo {
|
||||
currentPage
|
||||
hasNextPage
|
||||
}
|
||||
airingSchedules(
|
||||
airingAt_greater: 0
|
||||
airingAt_lesser: ${System.currentTimeMillis() / 1000 - 10000}
|
||||
sort: ${"$"}sort
|
||||
) {
|
||||
media{
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
}
|
||||
coverImage {
|
||||
extraLarge
|
||||
large
|
||||
}
|
||||
description
|
||||
status
|
||||
tags{
|
||||
name
|
||||
}
|
||||
genres
|
||||
studios {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
countryOfOrigin
|
||||
isAdult
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
private fun parseSearchJson(jsonLine: String?, isLatestQuery: Boolean = false): AnimesPage {
|
||||
val jsonData = jsonLine ?: return AnimesPage(emptyList(), false)
|
||||
val metaData: Any = if (!isLatestQuery) {
|
||||
|
@ -218,7 +138,8 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
{
|
||||
"page": $page,
|
||||
"perPage": 30,
|
||||
"sort": "TRENDING_DESC"
|
||||
"sort": "TRENDING_DESC",
|
||||
"status": ["FINISHED", "RELEASING"]
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
|
@ -227,8 +148,7 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
|
||||
override fun popularAnimeParse(response: Response): AnimesPage {
|
||||
val jsonData = response.body.string()
|
||||
return parseSearchJson(jsonData)
|
||||
}
|
||||
return parseSearchJson(jsonData) }
|
||||
|
||||
// =============================== Latest ===============================
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
|
@ -261,67 +181,73 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
}
|
||||
|
||||
private fun searchAnimeByIdParse(response: Response): AnimesPage {
|
||||
val details = animeDetailsParse(response).apply {
|
||||
setUrlWithoutDomain(response.request.url.toString())
|
||||
initialized = true
|
||||
}
|
||||
|
||||
val details = animeDetailsParse(response)
|
||||
return AnimesPage(listOf(details), false)
|
||||
}
|
||||
|
||||
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request {
|
||||
val variables = """
|
||||
{
|
||||
"page": $page,
|
||||
"perPage": 30,
|
||||
"sort": "POPULARITY_DESC",
|
||||
"search": "$query"
|
||||
val params = AniListFilters.getSearchParameters(filters)
|
||||
val variablesObject = buildJsonObject {
|
||||
put("page", page)
|
||||
put("perPage", 30)
|
||||
put("sort", params.sort)
|
||||
if (query.isNotBlank()) put("search", query)
|
||||
|
||||
if (params.genres.isNotEmpty()) {
|
||||
putJsonArray("genres") {
|
||||
params.genres.forEach { add(it) }
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
if (params.format.isNotEmpty()) {
|
||||
putJsonArray("format") {
|
||||
params.format.forEach { add(it) }
|
||||
}
|
||||
}
|
||||
|
||||
if (params.season.isBlank() && params.year.isNotBlank()) {
|
||||
put("year", "${params.year}%")
|
||||
}
|
||||
|
||||
if (params.season.isNotBlank() && params.year.isBlank()) {
|
||||
throw Exception("Year cannot be blank if season is set")
|
||||
}
|
||||
|
||||
if (params.season.isNotBlank() && params.year.isNotBlank()) {
|
||||
put("season", params.season)
|
||||
put("seasonYear", params.year)
|
||||
}
|
||||
|
||||
if (params.status.isNotBlank()) {
|
||||
putJsonArray("status") {
|
||||
params.status.forEach { add(it.toString()) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val variables = json.encodeToString(variablesObject)
|
||||
|
||||
println(anilistQuery())
|
||||
println(variables)
|
||||
|
||||
return makeGraphQLRequest(anilistQuery(), variables)
|
||||
}
|
||||
|
||||
override fun searchAnimeParse(response: Response) = popularAnimeParse(response)
|
||||
|
||||
// ============================== Filters ===============================
|
||||
|
||||
override fun getFilterList(): AnimeFilterList = AniListFilters.FILTER_LIST
|
||||
|
||||
// =========================== Anime Details ============================
|
||||
|
||||
override fun animeDetailsParse(response: Response): SAnime = throw UnsupportedOperationException()
|
||||
|
||||
override suspend fun getAnimeDetails(anime: SAnime): SAnime {
|
||||
val query = """
|
||||
query(${"$"}id: Int){
|
||||
Media(id: ${"$"}id){
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
english
|
||||
native
|
||||
}
|
||||
coverImage {
|
||||
extraLarge
|
||||
large
|
||||
}
|
||||
description
|
||||
status
|
||||
tags{
|
||||
name
|
||||
}
|
||||
genres
|
||||
studios {
|
||||
nodes {
|
||||
name
|
||||
}
|
||||
}
|
||||
countryOfOrigin
|
||||
isAdult
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
|
||||
val variables = """{"id": ${anime.url}}"""
|
||||
|
||||
val metaData = runCatching {
|
||||
json.decodeFromString<DetailsById>(client.newCall(makeGraphQLRequest(query, variables)).execute().body.string())
|
||||
json.decodeFromString<DetailsById>(client.newCall(makeGraphQLRequest(getDetailsQuery(), variables)).execute().body.string())
|
||||
}.getOrNull()?.data?.media
|
||||
|
||||
anime.title = metaData?.title?.let { title ->
|
||||
|
@ -334,10 +260,24 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
} ?: ""
|
||||
|
||||
anime.thumbnail_url = metaData?.coverImage?.extraLarge
|
||||
anime.description = metaData?.description
|
||||
?.replace(Regex("<br><br>"), "\n")
|
||||
?.replace(Regex("<.*?>"), "")
|
||||
?: "No Description"
|
||||
|
||||
anime.description = buildString {
|
||||
append(
|
||||
metaData?.description?.let {
|
||||
Jsoup.parseBodyFragment(
|
||||
it.replace("<br>\n", "br2n")
|
||||
.replace("<br>", "br2n")
|
||||
.replace("\n", "br2n"),
|
||||
).text().replace("br2n", "\n")
|
||||
},
|
||||
)
|
||||
append("\n\n")
|
||||
if (!(metaData?.season == null && metaData?.seasonYear == null)) {
|
||||
append("Release: ${ metaData.season ?: ""} ${ metaData.seasonYear ?: ""}")
|
||||
}
|
||||
metaData?.format?.let { append("\nType: ${metaData.format}") }
|
||||
metaData?.episodes?.let { append("\nTotal Episode Count: ${metaData.episodes}") }
|
||||
}.trim()
|
||||
|
||||
anime.status = when (metaData?.status) {
|
||||
"RELEASING" -> SAnime.ONGOING
|
||||
|
@ -360,9 +300,7 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
|
||||
// ============================== Episodes ==============================
|
||||
override fun episodeListRequest(anime: SAnime): Request {
|
||||
val res = URL("https://api.ani.zip/mappings?anilist_id=${anime.url}").readText()
|
||||
val kitsuId = JSONObject(res).getJSONObject("mappings").getInt("kitsu_id").toString()
|
||||
return GET("https://anime-kitsu.strem.fun/meta/series/kitsu%3A$kitsuId.json")
|
||||
return GET("https://anime-kitsu.strem.fun/meta/series/anilist%3A${anime.url}.json")
|
||||
}
|
||||
|
||||
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||
|
@ -375,7 +313,6 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
?.let { videos ->
|
||||
if (preferences.getBoolean(UPCOMING_EP_KEY, UPCOMING_EP_DEFAULT)) { videos } else { videos.filter { video -> (video.released?.let { parseDate(it) } ?: 0L) <= System.currentTimeMillis() } }
|
||||
}
|
||||
?.filter { it.thumbnail != null }
|
||||
?.map { video ->
|
||||
SEpisode.create().apply {
|
||||
episode_number = video.episode?.toFloat() ?: 0.0F
|
||||
|
@ -481,9 +418,9 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
udp://tracker.tiny-vps.com:6969/announce,
|
||||
udp://tracker.torrent.eu.org:451/announce,
|
||||
udp://valakas.rollo.dnsabr.com:2710/announce,
|
||||
udp://www.torrent.eu.org:451/announce
|
||||
udp://www.torrent.eu.org:451/announce,
|
||||
${fetchTrackers().split("\n").joinToString(",")}
|
||||
""".trimIndent()
|
||||
|
||||
return streamList.streams?.map { stream ->
|
||||
val urlOrHash =
|
||||
if (debridProvider == "none") {
|
||||
|
@ -509,6 +446,17 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
)
|
||||
}
|
||||
|
||||
private fun fetchTrackers(): String {
|
||||
val request = Request.Builder()
|
||||
.url("https://raw.githubusercontent.com/ngosang/trackerslist/master/trackers_best.txt")
|
||||
.build()
|
||||
|
||||
client.newCall(request).execute().use { response ->
|
||||
if (!response.isSuccessful) throw Exception("Unexpected code $response")
|
||||
return response.body.string().trim()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
// Debrid provider
|
||||
ListPreference(screen.context).apply {
|
||||
|
@ -714,7 +662,10 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
"🇫🇷 Torrent9",
|
||||
"🇪🇸 MejorTorrent",
|
||||
"🇲🇽 Cinecalidad",
|
||||
"🇮🇹 ilCorsaroNero",
|
||||
"🇪🇸 Wolfmax4k",
|
||||
)
|
||||
|
||||
private val PREF_PROVIDERS_VALUE = arrayOf(
|
||||
"yts",
|
||||
"eztv",
|
||||
|
@ -735,6 +686,8 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
"torrent9",
|
||||
"mejortorrent",
|
||||
"cinecalidad",
|
||||
"ilcorsaronero",
|
||||
"wolfmax4k",
|
||||
)
|
||||
|
||||
private val PREF_DEFAULT_PROVIDERS_VALUE = arrayOf(
|
||||
|
@ -759,6 +712,9 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
"BluRay REMUX",
|
||||
"HDR/HDR10+/Dolby Vision",
|
||||
"Dolby Vision",
|
||||
"Dolby Vision + HDR",
|
||||
"3D",
|
||||
"Non 3D (DO NOT SELECT IF NOT SURE)",
|
||||
"4k",
|
||||
"1080p",
|
||||
"720p",
|
||||
|
@ -768,10 +724,14 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
"Cam",
|
||||
"Unknown",
|
||||
)
|
||||
|
||||
private val PREF_QUALITY_VALUE = arrayOf(
|
||||
"brremux",
|
||||
"hdrall",
|
||||
"dolbyvision",
|
||||
"dolbyvisionwithhdr",
|
||||
"threed",
|
||||
"nonthreed",
|
||||
"4k",
|
||||
"1080p",
|
||||
"720p",
|
||||
|
|
|
@ -73,7 +73,11 @@ data class AnilistMedia(
|
|||
val status: String? = null,
|
||||
val tags: List<AnilistTag>? = null,
|
||||
val genres: List<String>? = null,
|
||||
val episodes: Int? = null,
|
||||
val format: String? = null,
|
||||
val studios: AnilistStudios? = null,
|
||||
val season: String? = null,
|
||||
val seasonYear: Int? = null,
|
||||
val countryOfOrigin: String? = null,
|
||||
val isAdult: Boolean = false,
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue