mirror of
https://github.com/aniyomiorg/aniyomi.git
synced 2024-11-27 16:26:29 +03:00
feat(simkl): add support for next episode airing
This commit is contained in:
parent
0c0bf51663
commit
ad0e308b7b
2 changed files with 74 additions and 23 deletions
|
@ -920,8 +920,9 @@ class AnimeInfoScreenModel(
|
|||
}
|
||||
|
||||
private suspend fun updateAiringTime(anime: Anime, trackItems: List<AnimeTrackItem>, manualFetch: Boolean) {
|
||||
val airingEpisode = AniChartApi().loadAiringTime(anime, trackItems, manualFetch)
|
||||
updateSuccessState { it.copy(nextAiringEpisode = airingEpisode) }
|
||||
val airingEpisodeData = AniChartApi().loadAiringTime(anime, trackItems, manualFetch)
|
||||
setAnimeViewerFlags.awaitSetNextEpisodeAiring(anime.id, airingEpisodeData)
|
||||
updateSuccessState { it.copy(nextAiringEpisode = airingEpisodeData) }
|
||||
}
|
||||
|
||||
// Track sheet - end
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package eu.kanade.tachiyomi.util
|
||||
import eu.kanade.domain.entries.anime.interactor.SetAnimeViewerFlags
|
||||
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||
import eu.kanade.tachiyomi.data.track.anilist.Anilist
|
||||
import eu.kanade.tachiyomi.data.track.myanimelist.MyAnimeList
|
||||
import eu.kanade.tachiyomi.data.track.simkl.Simkl
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.jsonMime
|
||||
import eu.kanade.tachiyomi.ui.entries.anime.track.AnimeTrackItem
|
||||
|
@ -12,32 +13,34 @@ import okhttp3.OkHttpClient
|
|||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import tachiyomi.core.util.lang.withIOContext
|
||||
import tachiyomi.domain.entries.anime.model.Anime
|
||||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import java.time.OffsetDateTime
|
||||
import java.util.Calendar
|
||||
|
||||
class AniChartApi {
|
||||
private val client = OkHttpClient()
|
||||
private val setAnimeViewerFlags: SetAnimeViewerFlags = Injekt.get()
|
||||
|
||||
internal suspend fun loadAiringTime(anime: Anime, trackItems: List<AnimeTrackItem>, manualFetch: Boolean): Pair<Int, Long> {
|
||||
if (anime.status == SAnime.COMPLETED.toLong() && !manualFetch) return Pair(anime.nextEpisodeToAir, anime.nextEpisodeAiringAt)
|
||||
var airingEpisodeData = Pair(anime.nextEpisodeToAir, anime.nextEpisodeAiringAt)
|
||||
if (anime.status == SAnime.COMPLETED.toLong() && !manualFetch) return airingEpisodeData
|
||||
|
||||
return withIOContext {
|
||||
var alId = 0L
|
||||
var airingTime = Pair(0, 0L)
|
||||
trackItems.forEach {
|
||||
if (it.track != null) {
|
||||
alId = when (it.service) {
|
||||
is Anilist -> it.track.remoteId
|
||||
is MyAnimeList -> getAlIdFromMal(it.track.remoteId)
|
||||
else -> 0L
|
||||
val matchingTrackItem = trackItems.firstOrNull {
|
||||
(it.service is Anilist && it.track != null) ||
|
||||
(it.service is MyAnimeList && it.track != null) ||
|
||||
(it.service is Simkl && it.track != null)
|
||||
} ?: return@withIOContext Pair(1, 0L)
|
||||
|
||||
matchingTrackItem.let { item ->
|
||||
item.track!!.let {
|
||||
airingEpisodeData = when (item.service) {
|
||||
is Anilist -> getAnilistAiringEpisodeData(it.remoteId)
|
||||
is MyAnimeList -> getAnilistAiringEpisodeData(getAlIdFromMal(it.remoteId))
|
||||
is Simkl -> getSimklAiringEpisodeData(it.remoteId)
|
||||
else -> Pair(1, 0L)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (alId != 0L) {
|
||||
airingTime = getAiringAt(alId)
|
||||
setAnimeViewerFlags.awaitSetNextEpisodeAiring(anime.id, airingTime)
|
||||
}
|
||||
return@withIOContext airingTime
|
||||
return@withIOContext airingEpisodeData
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -68,7 +71,7 @@ class AniChartApi {
|
|||
}
|
||||
}
|
||||
|
||||
private suspend fun getAiringAt(id: Long): Pair<Int, Long> {
|
||||
private suspend fun getAnilistAiringEpisodeData(id: Long): Pair<Int, Long> {
|
||||
return withIOContext {
|
||||
val query = """
|
||||
query {
|
||||
|
@ -89,13 +92,60 @@ class AniChartApi {
|
|||
),
|
||||
).execute()
|
||||
} catch (e: Exception) {
|
||||
return@withIOContext Pair(0, 0L)
|
||||
return@withIOContext Pair(1, 0L)
|
||||
}
|
||||
val data = response.body.string()
|
||||
val episodeNumber = data.substringAfter("episode\":").substringBefore(",").toIntOrNull() ?: 0
|
||||
val episodeNumber = data.substringAfter("episode\":").substringBefore(",").toIntOrNull() ?: 1
|
||||
val airingAt = data.substringAfter("airingAt\":").substringBefore("}").toLongOrNull() ?: 0L
|
||||
|
||||
return@withIOContext Pair(episodeNumber, airingAt)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun getSimklAiringEpisodeData(id: Long): Pair<Int, Long> {
|
||||
var episodeNumber = 1
|
||||
var airingAt = 0L
|
||||
return withIOContext {
|
||||
val calendarTypes = listOf("anime", "tv", "movie_release")
|
||||
calendarTypes.forEach {
|
||||
val response = try {
|
||||
client.newCall(GET("https://data.simkl.in/calendar/$it.json")).execute()
|
||||
} catch (e: Exception) {
|
||||
return@withIOContext Pair(1, 0L)
|
||||
}
|
||||
|
||||
val body = response.body.string()
|
||||
|
||||
val data = removeAiredSimkl(body)
|
||||
|
||||
val malId = data.substringAfter("\"simkl_id\":$id,", "").substringAfter("\"mal\":\"").substringBefore("\"").toLongOrNull() ?: 0L
|
||||
if (malId != 0L) return@withIOContext getAnilistAiringEpisodeData(getAlIdFromMal(malId))
|
||||
|
||||
val epNum = data.substringAfter("\"simkl_id\":$id,", "").substringBefore("\"}}").substringAfterLast("\"episode\":")
|
||||
episodeNumber = epNum.substringBefore(",").toIntOrNull() ?: episodeNumber
|
||||
|
||||
val date = data.substringBefore("\"simkl_id\":$id,", "").substringAfterLast("\"date\":\"").substringBefore("\"")
|
||||
airingAt = if (date.isNotBlank()) toUnixTimestamp(date) else airingAt
|
||||
|
||||
if (airingAt != 0L) return@withIOContext Pair(episodeNumber, airingAt)
|
||||
}
|
||||
return@withIOContext Pair(episodeNumber, airingAt)
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeAiredSimkl(body: String): String {
|
||||
val currentTimeInMillis = Calendar.getInstance().timeInMillis
|
||||
val index = body.split("\"date\":\"").drop(1).indexOfFirst {
|
||||
val date = it.substringBefore("\"")
|
||||
val time = if (date.isNotBlank()) toUnixTimestamp(date) else 0L
|
||||
time.times(1000) > currentTimeInMillis
|
||||
}
|
||||
return if (index >= 0) body.substring(index) else ""
|
||||
}
|
||||
|
||||
private fun toUnixTimestamp(dateFormat: String): Long {
|
||||
val offsetDateTime = OffsetDateTime.parse(dateFormat)
|
||||
val instant = offsetDateTime.toInstant()
|
||||
return instant.epochSecond
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue