@@ -5,11 +5,11 @@ import androidx.annotation.StringRes
55import com.fasterxml.jackson.annotation.JsonProperty
66import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey
77import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey
8- import com.lagradost.cloudstream3.app
98import com.lagradost.cloudstream3.R
109import com.lagradost.cloudstream3.Score
1110import com.lagradost.cloudstream3.ShowStatus
1211import com.lagradost.cloudstream3.TvType
12+ import com.lagradost.cloudstream3.app
1313import com.lagradost.cloudstream3.mvvm.logError
1414import com.lagradost.cloudstream3.syncproviders.AuthData
1515import com.lagradost.cloudstream3.syncproviders.AuthLoginRequirement
@@ -22,18 +22,16 @@ import com.lagradost.cloudstream3.ui.SyncWatchType
2222import com.lagradost.cloudstream3.ui.library.ListSorting
2323import com.lagradost.cloudstream3.utils.AppUtils.toJson
2424import com.lagradost.cloudstream3.utils.txt
25- import kotlinx.coroutines.flow.asFlow
26- import kotlinx.coroutines.flow.collect
27- import kotlinx.coroutines.flow.onEach
28- import kotlinx.coroutines.flow.withIndex
25+ import okhttp3.Interceptor
26+ import okhttp3.Request
2927import okhttp3.RequestBody.Companion.toRequestBody
28+ import okhttp3.Response
3029import java.text.SimpleDateFormat
3130import java.time.Instant
3231import java.time.LocalDate
3332import java.time.format.DateTimeFormatter
3433import java.util.Date
3534import java.util.Locale
36- import kotlin.collections.set
3735
3836const val KITSU_MAX_SEARCH_LIMIT = 20
3937
@@ -42,7 +40,9 @@ class KitsuApi: SyncAPI() {
4240 override val idPrefix = " kitsu"
4341
4442 private val apiUrl = " https://kitsu.io/api/edge"
43+ private val fallbackApiUrl = " https://kitsu.app/api/edge"
4544 private val oauthUrl = " https://kitsu.io/api/oauth"
45+ private val fallbackOauthUrl = " https://kitsu.app/api/oauth"
4646 override val hasInApp = true
4747 override val mainUrl = " https://kitsu.app"
4848 override val icon = R .drawable.kitsu_icon
@@ -63,6 +63,33 @@ class KitsuApi: SyncAPI() {
6363 email = true
6464 )
6565
66+ private class FallbackInterceptor (private val apiUrl : String , private val fallbackApiUrl : String ) : Interceptor {
67+ override fun intercept (chain : Interceptor .Chain ): Response {
68+ val request: Request = chain.request()
69+
70+ try {
71+
72+ val response = chain.proceed(request);
73+
74+ if (response.isSuccessful) return response
75+
76+ response.close()
77+
78+ } catch (_: Exception ) {
79+ }
80+
81+ val fallbackRequest: Request = request.newBuilder()
82+ .url(request.url.toString().replaceFirst(apiUrl, fallbackApiUrl))
83+ .build()
84+
85+ return chain.proceed(fallbackRequest)
86+
87+ }
88+ }
89+
90+ private val apiFallbackInterceptor = FallbackInterceptor (apiUrl, fallbackApiUrl)
91+ private val oauthFallbackInterceptor = FallbackInterceptor (oauthUrl, fallbackOauthUrl)
92+
6693 override suspend fun login (form : AuthLoginResponse ): AuthToken ? {
6794 val username = form.email ? : return null
6895 val password = form.password ? : return null
@@ -75,8 +102,10 @@ class KitsuApi: SyncAPI() {
75102 " grant_type" to grantType,
76103 " username" to username,
77104 " password" to password
78- )
105+ ),
106+ interceptor = oauthFallbackInterceptor
79107 ).parsed<ResponseToken >()
108+
80109 return AuthToken (
81110 accessTokenLifetime = unixTime + token.expiresIn.toLong(),
82111 refreshToken = token.refreshToken,
@@ -90,7 +119,8 @@ class KitsuApi: SyncAPI() {
90119 data = mapOf (
91120 " grant_type" to " refresh_token" ,
92121 " refresh_token" to token.refreshToken!!
93- )
122+ ),
123+ interceptor = oauthFallbackInterceptor
94124 ).parsed<ResponseToken >()
95125
96126 return AuthToken (
@@ -105,7 +135,8 @@ class KitsuApi: SyncAPI() {
105135 " $apiUrl /users?filter[self]=true" ,
106136 headers = mapOf (
107137 " Authorization" to " Bearer ${token?.accessToken ? : return null } "
108- ), cacheTime = 0
138+ ), cacheTime = 0 ,
139+ interceptor = apiFallbackInterceptor
109140 ).parsed<KitsuResponse >()
110141
111142 if (user.data.isEmpty()) {
@@ -123,11 +154,14 @@ class KitsuApi: SyncAPI() {
123154 val auth = auth?.token?.accessToken ? : return null
124155 val animeSelectedFields = arrayOf(" titles" ," canonicalTitle" ," posterImage" ," episodeCount" )
125156 val url = " $apiUrl /anime?filter[text]=$query &page[limit]=$KITSU_MAX_SEARCH_LIMIT &fields[anime]=${animeSelectedFields.joinToString(" ," )} "
157+
126158 val res = app.get(
127159 url, headers = mapOf (
128160 " Authorization" to " Bearer $auth " ,
129- ), cacheTime = 0
161+ ), cacheTime = 0 ,
162+ interceptor = apiFallbackInterceptor
130163 ).parsed<KitsuResponse >()
164+
131165 return res.data.map {
132166 val attributes = it.attributes
133167
@@ -160,7 +194,8 @@ class KitsuApi: SyncAPI() {
160194 val anime = app.get(
161195 url, headers = mapOf (
162196 " Authorization" to " Bearer $auth "
163- )
197+ ),
198+ interceptor = apiFallbackInterceptor
164199 ).parsed<KitsuResponse >().data.attributes
165200
166201 return SyncResult (
@@ -201,7 +236,8 @@ class KitsuApi: SyncAPI() {
201236 val anime = app.get(
202237 url, headers = mapOf (
203238 " Authorization" to " Bearer $accessToken "
204- )
239+ ),
240+ interceptor = apiFallbackInterceptor
205241 ).parsed<KitsuResponse >().data.firstOrNull()?.attributes
206242
207243 if (anime == null ) {
@@ -224,7 +260,8 @@ class KitsuApi: SyncAPI() {
224260
225261 val animeSelectedFields = arrayOf(" titles" ," canonicalTitle" )
226262 val url = " $apiUrl /anime?filter[text]=$title &page[limit]=$KITSU_MAX_SEARCH_LIMIT &fields[anime]=${animeSelectedFields.joinToString(" ," )} "
227- val res = app.get(url).parsed<KitsuResponse >()
263+
264+ val res = app.get(url, interceptor = apiFallbackInterceptor).parsed<KitsuResponse >()
228265
229266 return res.data.firstOrNull()?.id
230267
@@ -269,8 +306,10 @@ class KitsuApi: SyncAPI() {
269306 headers = mapOf (
270307 " Authorization" to " Bearer ${auth.token.accessToken} "
271308 ),
309+ interceptor = apiFallbackInterceptor
272310 )
273311
312+
274313 return res.isSuccessful
275314
276315 }
@@ -316,7 +355,8 @@ class KitsuApi: SyncAPI() {
316355 " content-type" to " application/vnd.api+json" ,
317356 " Authorization" to " Bearer ${auth.token.accessToken} "
318357 ),
319- requestBody = data.toJson().toRequestBody()
358+ requestBody = data.toJson().toRequestBody(),
359+ interceptor = apiFallbackInterceptor
320360 )
321361
322362 return res.isSuccessful
@@ -349,9 +389,11 @@ class KitsuApi: SyncAPI() {
349389 " content-type" to " application/vnd.api+json" ,
350390 " Authorization" to " Bearer ${auth.token.accessToken} "
351391 ),
352- requestBody = data.toJson().toRequestBody()
392+ requestBody = data.toJson().toRequestBody(),
393+ interceptor = apiFallbackInterceptor
353394 )
354395
396+
355397 return res.isSuccessful
356398
357399 }
@@ -365,6 +407,7 @@ class KitsuApi: SyncAPI() {
365407 headers = mapOf (
366408 " Authorization" to " Bearer ${auth.token.accessToken} "
367409 ),
410+ interceptor = apiFallbackInterceptor
368411 ).parsed<KitsuResponse >().data.firstOrNull() ? : return null
369412
370413 return res.id.toInt()
@@ -439,7 +482,8 @@ class KitsuApi: SyncAPI() {
439482 val res = app.get(
440483 url, headers = mapOf (
441484 " Authorization" to " Bearer ${token.accessToken} " ,
442- )
485+ ),
486+ interceptor = apiFallbackInterceptor
443487 ).parsed<KitsuResponse >()
444488 return res
445489 }
@@ -474,7 +518,7 @@ class KitsuApi: SyncAPI() {
474518
475519 val animeId = animeItem?.id
476520
477- val description : String? = animeItem?.attributes?.synopsis
521+ val synopsis : String? = animeItem?.attributes?.synopsis
478522
479523 return LibraryItem (
480524 canonicalTitle ? : titles?.enJp ? : titles?.jaJp.orEmpty(),
@@ -489,7 +533,7 @@ class KitsuApi: SyncAPI() {
489533 posterImage?.large ? : posterImage?.medium,
490534 null ,
491535 null ,
492- plot = description ,
536+ plot = synopsis ,
493537 releaseDate = if (startDate == null ) null else try {
494538 Date .from(
495539 Instant .from(
@@ -770,4 +814,4 @@ query {
770814 val canonical : String? = null
771815 )
772816 }
773- }
817+ }
0 commit comments