forked from AlmightyHak/extensions-source
fix(all/torrentioanime): use api.ani.zip for episode lists and fix nsfw (#676)
* feat(all/torrentio): use api.ani.zip again for episode list * feat(all/torrentio): align queries with nsfw tag * feat(all/torrentio): fix latest query
This commit is contained in:
parent
4933411035
commit
954c401f8f
4 changed files with 121 additions and 46 deletions
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'Torrentio Anime (Torrent / Debrid)'
|
extName = 'Torrentio Anime (Torrent / Debrid)'
|
||||||
extClass = '.Torrentio'
|
extClass = '.Torrentio'
|
||||||
extVersionCode = 14
|
extVersionCode = 15
|
||||||
containsNsfw = false
|
containsNsfw = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,8 @@ fun anilistQuery() = """
|
||||||
startDate_like: %year,
|
startDate_like: %year,
|
||||||
seasonYear: %seasonYear,
|
seasonYear: %seasonYear,
|
||||||
season: %season,
|
season: %season,
|
||||||
format_in: %format
|
format_in: %format,
|
||||||
|
isAdult: false
|
||||||
) {
|
) {
|
||||||
id
|
id
|
||||||
title {
|
title {
|
||||||
|
@ -103,7 +104,7 @@ fun anilistLatestQuery() = """
|
||||||
|
|
||||||
fun getDetailsQuery() = """
|
fun getDetailsQuery() = """
|
||||||
query media(%id: Int) {
|
query media(%id: Int) {
|
||||||
Media(id: %id) {
|
Media(id: %id, isAdult: false) {
|
||||||
id
|
id
|
||||||
title {
|
title {
|
||||||
romaji
|
romaji
|
||||||
|
@ -137,23 +138,3 @@ query media(%id: Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".toQuery()
|
""".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()
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ import androidx.preference.ListPreference
|
||||||
import androidx.preference.MultiSelectListPreference
|
import androidx.preference.MultiSelectListPreference
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import androidx.preference.SwitchPreferenceCompat
|
import androidx.preference.SwitchPreferenceCompat
|
||||||
|
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.AniZipResponse
|
||||||
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.AnilistMeta
|
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.AnilistMeta
|
||||||
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.AnilistMetaLatest
|
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.AnilistMetaLatest
|
||||||
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.DetailsById
|
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.DetailsById
|
||||||
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.EpisodeList
|
|
||||||
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.StreamDataTorrent
|
import eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto.StreamDataTorrent
|
||||||
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
@ -66,6 +66,7 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
.add("query", query)
|
.add("query", query)
|
||||||
.add("variables", variables)
|
.add("variables", variables)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return POST("https://graphql.anilist.co", body = requestBody)
|
return POST("https://graphql.anilist.co", body = requestBody)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -148,7 +149,8 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
|
|
||||||
override fun popularAnimeParse(response: Response): AnimesPage {
|
override fun popularAnimeParse(response: Response): AnimesPage {
|
||||||
val jsonData = response.body.string()
|
val jsonData = response.body.string()
|
||||||
return parseSearchJson(jsonData) }
|
return parseSearchJson(jsonData)
|
||||||
|
}
|
||||||
|
|
||||||
// =============================== Latest ===============================
|
// =============================== Latest ===============================
|
||||||
override fun latestUpdatesRequest(page: Int): Request {
|
override fun latestUpdatesRequest(page: Int): Request {
|
||||||
|
@ -300,41 +302,55 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
|
|
||||||
// ============================== Episodes ==============================
|
// ============================== Episodes ==============================
|
||||||
override fun episodeListRequest(anime: SAnime): Request {
|
override fun episodeListRequest(anime: SAnime): Request {
|
||||||
return GET("https://anime-kitsu.strem.fun/meta/series/anilist%3A${anime.url}.json")
|
return GET("https://api.ani.zip/mappings?anilist_id=${anime.url}")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun episodeListParse(response: Response): List<SEpisode> {
|
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||||
val responseString = response.body.string()
|
val responseString = response.body.string()
|
||||||
val episodeList = json.decodeFromString<EpisodeList>(responseString)
|
val aniZipResponse = json.decodeFromString<AniZipResponse>(responseString)
|
||||||
|
|
||||||
return when (episodeList.meta?.type) {
|
return when (aniZipResponse.mappings?.type) {
|
||||||
"series" -> {
|
"TV" -> {
|
||||||
episodeList.meta.videos
|
aniZipResponse.episodes
|
||||||
?.let { videos ->
|
?.let { episodes ->
|
||||||
if (preferences.getBoolean(UPCOMING_EP_KEY, UPCOMING_EP_DEFAULT)) { videos } else { videos.filter { video -> (video.released?.let { parseDate(it) } ?: 0L) <= System.currentTimeMillis() } }
|
if (preferences.getBoolean(UPCOMING_EP_KEY, UPCOMING_EP_DEFAULT)) {
|
||||||
|
episodes
|
||||||
|
} else {
|
||||||
|
episodes.filter { (_, episode) -> (episode?.airDate?.let { parseDate(it) } ?: 0L) <= System.currentTimeMillis() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?.map { video ->
|
?.mapNotNull { (_, episode) ->
|
||||||
|
val episodeNumber = runCatching { episode?.episode?.toFloat() }.getOrNull()
|
||||||
|
|
||||||
|
if (episodeNumber == null) {
|
||||||
|
return@mapNotNull null
|
||||||
|
}
|
||||||
|
|
||||||
|
val title = episode?.title?.get("en")
|
||||||
|
|
||||||
SEpisode.create().apply {
|
SEpisode.create().apply {
|
||||||
episode_number = video.episode?.toFloat() ?: 0.0F
|
episode_number = episodeNumber
|
||||||
url = "/stream/series/${video.videoId}.json"
|
url = "/stream/series/kitsu:${aniZipResponse.mappings.kitsuId}:${String.format(Locale.ENGLISH, "%.0f", episodeNumber)}.json"
|
||||||
date_upload = video.released?.let { parseDate(it) } ?: 0L
|
date_upload = episode?.airDate?.let { parseDate(it) } ?: 0L
|
||||||
name = "Episode ${video.episode} : ${
|
name = if (title == null) "Episode ${episode?.episode}" else "Episode ${episode.episode}: $title"
|
||||||
video.title?.removePrefix("Episode ")
|
scanlator = (episode?.airDate?.let { parseDate(it) } ?: 0L).takeIf { it > System.currentTimeMillis() }?.let { "Upcoming" } ?: ""
|
||||||
?.replaceFirst("\\d+\\s*".toRegex(), "")
|
|
||||||
?.trim()
|
|
||||||
}"
|
|
||||||
scanlator = (video.released?.let { parseDate(it) } ?: 0L).takeIf { it > System.currentTimeMillis() }?.let { "Upcoming" } ?: ""
|
|
||||||
}
|
}
|
||||||
}.orEmpty().reversed()
|
}.orEmpty().reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
"movie" -> {
|
"MOVIE" -> {
|
||||||
// Handle movie response
|
val dateUpload = if (!aniZipResponse.episodes.isNullOrEmpty()) {
|
||||||
|
aniZipResponse.episodes["1"]?.airDate?.let { parseDate(it) } ?: 0L
|
||||||
|
} else {
|
||||||
|
0L
|
||||||
|
}
|
||||||
|
|
||||||
listOf(
|
listOf(
|
||||||
SEpisode.create().apply {
|
SEpisode.create().apply {
|
||||||
episode_number = 1.0F
|
episode_number = 1.0F
|
||||||
url = "/stream/movie/${episodeList.meta.kitsuId}.json"
|
url = "/stream/movie/kitsu:${aniZipResponse.mappings.kitsuId}.json"
|
||||||
name = "Movie"
|
name = "Movie"
|
||||||
|
date_upload = dateUpload
|
||||||
},
|
},
|
||||||
).reversed()
|
).reversed()
|
||||||
}
|
}
|
||||||
|
@ -342,6 +358,12 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
else -> emptyList()
|
else -> emptyList()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun parseDateTime(dateStr: String): Long {
|
||||||
|
return runCatching { DATE_TIME_FORMATTER.parse(dateStr)?.time }
|
||||||
|
.getOrNull() ?: 0L
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseDate(dateStr: String): Long {
|
private fun parseDate(dateStr: String): Long {
|
||||||
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
|
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
|
||||||
.getOrNull() ?: 0L
|
.getOrNull() ?: 0L
|
||||||
|
@ -421,6 +443,7 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
udp://www.torrent.eu.org:451/announce,
|
udp://www.torrent.eu.org:451/announce,
|
||||||
${fetchTrackers().split("\n").joinToString(",")}
|
${fetchTrackers().split("\n").joinToString(",")}
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
|
|
||||||
return streamList.streams?.map { stream ->
|
return streamList.streams?.map { stream ->
|
||||||
val urlOrHash =
|
val urlOrHash =
|
||||||
if (debridProvider == "none") {
|
if (debridProvider == "none") {
|
||||||
|
@ -875,8 +898,12 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
private const val IS_EFFICIENT_KEY = "efficient"
|
private const val IS_EFFICIENT_KEY = "efficient"
|
||||||
private const val IS_EFFICIENT_DEFAULT = false
|
private const val IS_EFFICIENT_DEFAULT = false
|
||||||
|
|
||||||
private val DATE_FORMATTER by lazy {
|
private val DATE_TIME_FORMATTER by lazy {
|
||||||
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
|
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val DATE_FORMATTER by lazy {
|
||||||
|
SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package eu.kanade.tachiyomi.animeextension.all.torrentioanime.dto
|
||||||
|
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AniZipResponse(
|
||||||
|
val titles: Map<String, String?>? = null,
|
||||||
|
val episodes: Map<String, AniZipEpisode?>? = null,
|
||||||
|
val episodeCount: Int? = null,
|
||||||
|
val specialCount: Int? = null,
|
||||||
|
val images: List<AniZipImage?>? = null,
|
||||||
|
val mappings: AniZipMappings? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AniZipEpisode(
|
||||||
|
val episode: String? = null,
|
||||||
|
val episodeNumber: Int? = null,
|
||||||
|
val absoluteEpisodeNumber: Int? = null,
|
||||||
|
val seasonNumber: Int? = null,
|
||||||
|
val title: Map<String, String?>? = null,
|
||||||
|
val length: Int? = null,
|
||||||
|
val runtime: Int? = null,
|
||||||
|
@SerialName("airdate")
|
||||||
|
val airDate: String? = null,
|
||||||
|
val rating: String? = null,
|
||||||
|
@SerialName("anidbEid")
|
||||||
|
val aniDbEpisodeId: Long? = null,
|
||||||
|
val tvdbShowId: Long? = null,
|
||||||
|
val tvdbId: Long? = null,
|
||||||
|
val overview: String? = null,
|
||||||
|
val image: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AniZipImage(
|
||||||
|
val coverType: String? = null,
|
||||||
|
val url: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AniZipMappings(
|
||||||
|
@SerialName("animeplanet_id")
|
||||||
|
val animePlanetId: String? = null,
|
||||||
|
@SerialName("kitsu_id")
|
||||||
|
val kitsuId: Long? = null,
|
||||||
|
@SerialName("mal_id")
|
||||||
|
val myAnimeListId: Long? = null,
|
||||||
|
val type: String? = null,
|
||||||
|
@SerialName("anilist_id")
|
||||||
|
val aniListId: Long? = null,
|
||||||
|
@SerialName("anisearch_id")
|
||||||
|
val aniSearchId: Long? = null,
|
||||||
|
@SerialName("anidb_id")
|
||||||
|
val aniDbId: Long? = null,
|
||||||
|
@SerialName("notifymoe_id")
|
||||||
|
val notifyMoeId: String? = null,
|
||||||
|
@SerialName("livechart_id")
|
||||||
|
val liveChartId: Long? = null,
|
||||||
|
@SerialName("thetvdb_id")
|
||||||
|
val theTvDbId: Long? = null,
|
||||||
|
@SerialName("imdb_id")
|
||||||
|
val imdbId: String? = null,
|
||||||
|
@SerialName("themoviedb_id")
|
||||||
|
val theMovieDbId: String? = null,
|
||||||
|
)
|
Loading…
Add table
Add a link
Reference in a new issue