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 {
|
||||
extName = 'Torrentio Anime (Torrent / Debrid)'
|
||||
extClass = '.Torrentio'
|
||||
extVersionCode = 14
|
||||
extVersionCode = 15
|
||||
containsNsfw = false
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ fun anilistQuery() = """
|
|||
startDate_like: %year,
|
||||
seasonYear: %seasonYear,
|
||||
season: %season,
|
||||
format_in: %format
|
||||
format_in: %format,
|
||||
isAdult: false
|
||||
) {
|
||||
id
|
||||
title {
|
||||
|
@ -103,7 +104,7 @@ fun anilistLatestQuery() = """
|
|||
|
||||
fun getDetailsQuery() = """
|
||||
query media(%id: Int) {
|
||||
Media(id: %id) {
|
||||
Media(id: %id, isAdult: false) {
|
||||
id
|
||||
title {
|
||||
romaji
|
||||
|
@ -137,23 +138,3 @@ query media(%id: Int) {
|
|||
}
|
||||
}
|
||||
""".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.PreferenceScreen
|
||||
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.AnilistMetaLatest
|
||||
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.animesource.ConfigurableAnimeSource
|
||||
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||
|
@ -66,6 +66,7 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
.add("query", query)
|
||||
.add("variables", variables)
|
||||
.build()
|
||||
|
||||
return POST("https://graphql.anilist.co", body = requestBody)
|
||||
}
|
||||
|
||||
|
@ -148,7 +149,8 @@ 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 {
|
||||
|
@ -300,41 +302,55 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
|
||||
// ============================== Episodes ==============================
|
||||
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> {
|
||||
val responseString = response.body.string()
|
||||
val episodeList = json.decodeFromString<EpisodeList>(responseString)
|
||||
val aniZipResponse = json.decodeFromString<AniZipResponse>(responseString)
|
||||
|
||||
return when (episodeList.meta?.type) {
|
||||
"series" -> {
|
||||
episodeList.meta.videos
|
||||
?.let { videos ->
|
||||
if (preferences.getBoolean(UPCOMING_EP_KEY, UPCOMING_EP_DEFAULT)) { videos } else { videos.filter { video -> (video.released?.let { parseDate(it) } ?: 0L) <= System.currentTimeMillis() } }
|
||||
return when (aniZipResponse.mappings?.type) {
|
||||
"TV" -> {
|
||||
aniZipResponse.episodes
|
||||
?.let { episodes ->
|
||||
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 {
|
||||
episode_number = video.episode?.toFloat() ?: 0.0F
|
||||
url = "/stream/series/${video.videoId}.json"
|
||||
date_upload = video.released?.let { parseDate(it) } ?: 0L
|
||||
name = "Episode ${video.episode} : ${
|
||||
video.title?.removePrefix("Episode ")
|
||||
?.replaceFirst("\\d+\\s*".toRegex(), "")
|
||||
?.trim()
|
||||
}"
|
||||
scanlator = (video.released?.let { parseDate(it) } ?: 0L).takeIf { it > System.currentTimeMillis() }?.let { "Upcoming" } ?: ""
|
||||
episode_number = episodeNumber
|
||||
url = "/stream/series/kitsu:${aniZipResponse.mappings.kitsuId}:${String.format(Locale.ENGLISH, "%.0f", episodeNumber)}.json"
|
||||
date_upload = episode?.airDate?.let { parseDate(it) } ?: 0L
|
||||
name = if (title == null) "Episode ${episode?.episode}" else "Episode ${episode.episode}: $title"
|
||||
scanlator = (episode?.airDate?.let { parseDate(it) } ?: 0L).takeIf { it > System.currentTimeMillis() }?.let { "Upcoming" } ?: ""
|
||||
}
|
||||
}.orEmpty().reversed()
|
||||
}
|
||||
|
||||
"movie" -> {
|
||||
// Handle movie response
|
||||
"MOVIE" -> {
|
||||
val dateUpload = if (!aniZipResponse.episodes.isNullOrEmpty()) {
|
||||
aniZipResponse.episodes["1"]?.airDate?.let { parseDate(it) } ?: 0L
|
||||
} else {
|
||||
0L
|
||||
}
|
||||
|
||||
listOf(
|
||||
SEpisode.create().apply {
|
||||
episode_number = 1.0F
|
||||
url = "/stream/movie/${episodeList.meta.kitsuId}.json"
|
||||
url = "/stream/movie/kitsu:${aniZipResponse.mappings.kitsuId}.json"
|
||||
name = "Movie"
|
||||
date_upload = dateUpload
|
||||
},
|
||||
).reversed()
|
||||
}
|
||||
|
@ -342,6 +358,12 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseDateTime(dateStr: String): Long {
|
||||
return runCatching { DATE_TIME_FORMATTER.parse(dateStr)?.time }
|
||||
.getOrNull() ?: 0L
|
||||
}
|
||||
|
||||
private fun parseDate(dateStr: String): Long {
|
||||
return runCatching { DATE_FORMATTER.parse(dateStr)?.time }
|
||||
.getOrNull() ?: 0L
|
||||
|
@ -421,6 +443,7 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
udp://www.torrent.eu.org:451/announce,
|
||||
${fetchTrackers().split("\n").joinToString(",")}
|
||||
""".trimIndent()
|
||||
|
||||
return streamList.streams?.map { stream ->
|
||||
val urlOrHash =
|
||||
if (debridProvider == "none") {
|
||||
|
@ -875,8 +898,12 @@ class Torrentio : ConfigurableAnimeSource, AnimeHttpSource() {
|
|||
private const val IS_EFFICIENT_KEY = "efficient"
|
||||
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)
|
||||
}
|
||||
|
||||
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