mirror of
https://github.com/recloudstream/cloudstream.git
synced 2026-06-19 20:05:41 +00:00
Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b75ca6ace |
8 changed files with 288 additions and 3 deletions
|
|
@ -35,6 +35,7 @@ import com.lagradost.cloudstream3.syncproviders.providers.OpenSubtitlesApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.SimklApi
|
import com.lagradost.cloudstream3.syncproviders.providers.SimklApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.SubDlApi
|
import com.lagradost.cloudstream3.syncproviders.providers.SubDlApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.providers.SubSourceApi
|
import com.lagradost.cloudstream3.syncproviders.providers.SubSourceApi
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.providers.TraktApi
|
||||||
import com.lagradost.cloudstream3.ui.SyncWatchType
|
import com.lagradost.cloudstream3.ui.SyncWatchType
|
||||||
import com.lagradost.cloudstream3.ui.library.ListSorting
|
import com.lagradost.cloudstream3.ui.library.ListSorting
|
||||||
import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery
|
import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery
|
||||||
|
|
@ -276,7 +277,7 @@ abstract class SyncAPI : AuthAPI() {
|
||||||
open var requireLibraryRefresh: Boolean = true
|
open var requireLibraryRefresh: Boolean = true
|
||||||
open val mainUrl: String = "NONE"
|
open val mainUrl: String = "NONE"
|
||||||
|
|
||||||
/** Currently unused, but will be used to correctly render the UI.
|
/** Currently unused, but will be used to correctly render the UI.
|
||||||
* This should specify what sync watch types can be used with this service. */
|
* This should specify what sync watch types can be used with this service. */
|
||||||
open val supportedWatchTypes: Set<SyncWatchType> = SyncWatchType.entries.toSet()
|
open val supportedWatchTypes: Set<SyncWatchType> = SyncWatchType.entries.toSet()
|
||||||
/**
|
/**
|
||||||
|
|
@ -732,6 +733,7 @@ abstract class AccountManager {
|
||||||
val malApi = MALApi()
|
val malApi = MALApi()
|
||||||
val aniListApi = AniListApi()
|
val aniListApi = AniListApi()
|
||||||
val simklApi = SimklApi()
|
val simklApi = SimklApi()
|
||||||
|
val traktApi = TraktApi()
|
||||||
val localListApi = LocalList()
|
val localListApi = LocalList()
|
||||||
|
|
||||||
val openSubtitlesApi = OpenSubtitlesApi()
|
val openSubtitlesApi = OpenSubtitlesApi()
|
||||||
|
|
@ -773,6 +775,7 @@ abstract class AccountManager {
|
||||||
SyncRepo(malApi),
|
SyncRepo(malApi),
|
||||||
SyncRepo(aniListApi),
|
SyncRepo(aniListApi),
|
||||||
SyncRepo(simklApi),
|
SyncRepo(simklApi),
|
||||||
|
SyncRepo(traktApi),
|
||||||
SyncRepo(localListApi),
|
SyncRepo(localListApi),
|
||||||
|
|
||||||
SubtitleRepo(openSubtitlesApi),
|
SubtitleRepo(openSubtitlesApi),
|
||||||
|
|
@ -822,6 +825,7 @@ abstract class AccountManager {
|
||||||
LoadResponse.malIdPrefix = malApi.idPrefix
|
LoadResponse.malIdPrefix = malApi.idPrefix
|
||||||
LoadResponse.aniListIdPrefix = aniListApi.idPrefix
|
LoadResponse.aniListIdPrefix = aniListApi.idPrefix
|
||||||
LoadResponse.simklIdPrefix = simklApi.idPrefix
|
LoadResponse.simklIdPrefix = simklApi.idPrefix
|
||||||
|
LoadResponse.traktIdPrefix = traktApi.idPrefix
|
||||||
}
|
}
|
||||||
|
|
||||||
val subtitleProviders = arrayOf(
|
val subtitleProviders = arrayOf(
|
||||||
|
|
@ -834,6 +838,7 @@ abstract class AccountManager {
|
||||||
SyncRepo(malApi),
|
SyncRepo(malApi),
|
||||||
SyncRepo(aniListApi),
|
SyncRepo(aniListApi),
|
||||||
SyncRepo(simklApi),
|
SyncRepo(simklApi),
|
||||||
|
SyncRepo(traktApi),
|
||||||
SyncRepo(localListApi)
|
SyncRepo(localListApi)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,249 @@
|
||||||
|
package com.lagradost.cloudstream3.syncproviders.providers
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
|
import com.lagradost.cloudstream3.Score
|
||||||
|
import com.lagradost.cloudstream3.app
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.AuthLoginPage
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.AuthToken
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.AuthUser
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.SyncAPI
|
||||||
|
import com.lagradost.cloudstream3.ui.SyncWatchType
|
||||||
|
|
||||||
|
/* https://trakt.docs.apiary.io */
|
||||||
|
class TraktApi : SyncAPI() {
|
||||||
|
override val name = "Trakt"
|
||||||
|
override val idPrefix = "trakt"
|
||||||
|
|
||||||
|
override val mainUrl = "https://trakt.tv"
|
||||||
|
val api = "https://api.trakt.tv"
|
||||||
|
|
||||||
|
override val supportedWatchTypes: Set<SyncWatchType> = emptySet()
|
||||||
|
|
||||||
|
override val icon = R.drawable.trakt
|
||||||
|
override val hasOAuth2 = true
|
||||||
|
override val redirectUrlIdentifier = "NONE"
|
||||||
|
val redirectUri = "cloudstreamapp://$redirectUrlIdentifier"
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val id: String get() = throw NotImplementedError()
|
||||||
|
val secret: String get() = throw NotImplementedError()
|
||||||
|
|
||||||
|
fun getHeaders(token: AuthToken) = mapOf(
|
||||||
|
"Authorization" to "Bearer ${token.accessToken}",
|
||||||
|
"Content-Type" to "application/json",
|
||||||
|
"trakt-api-version" to "2",
|
||||||
|
"trakt-api-key" to id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class TokenRoot(
|
||||||
|
@JsonProperty("access_token")
|
||||||
|
val accessToken: String,
|
||||||
|
@JsonProperty("token_type")
|
||||||
|
val tokenType: String,
|
||||||
|
@JsonProperty("expires_in")
|
||||||
|
val expiresIn: Long,
|
||||||
|
@JsonProperty("refresh_token")
|
||||||
|
val refreshToken: String,
|
||||||
|
@JsonProperty("scope")
|
||||||
|
val scope: String,
|
||||||
|
@JsonProperty("created_at")
|
||||||
|
val createdAt: Long,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class UserRoot(
|
||||||
|
@JsonProperty("username")
|
||||||
|
val username: String,
|
||||||
|
@JsonProperty("private")
|
||||||
|
val private: Boolean?,
|
||||||
|
@JsonProperty("name")
|
||||||
|
val name: String,
|
||||||
|
@JsonProperty("vip")
|
||||||
|
val vip: Boolean?,
|
||||||
|
@JsonProperty("vip_ep")
|
||||||
|
val vipEp: Boolean?,
|
||||||
|
@JsonProperty("ids")
|
||||||
|
val ids: Ids?,
|
||||||
|
@JsonProperty("joined_at")
|
||||||
|
val joinedAt: String?,
|
||||||
|
@JsonProperty("location")
|
||||||
|
val location: String?,
|
||||||
|
@JsonProperty("about")
|
||||||
|
val about: String?,
|
||||||
|
@JsonProperty("gender")
|
||||||
|
val gender: String?,
|
||||||
|
@JsonProperty("age")
|
||||||
|
val age: Long?,
|
||||||
|
@JsonProperty("images")
|
||||||
|
val images: Images?,
|
||||||
|
) {
|
||||||
|
data class Ids(
|
||||||
|
@JsonProperty("slug")
|
||||||
|
val slug: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Images(
|
||||||
|
@JsonProperty("avatar")
|
||||||
|
val avatar: Avatar,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Avatar(
|
||||||
|
@JsonProperty("full")
|
||||||
|
val full: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override suspend fun user(token: AuthToken?): AuthUser? {
|
||||||
|
if (token == null) return null
|
||||||
|
// https://trakt.docs.apiary.io/#reference/users/profile/get-user-profile
|
||||||
|
|
||||||
|
val userData = app.get(
|
||||||
|
"$api/users/me?extended=full", headers = getHeaders(token)
|
||||||
|
).parsed<UserRoot>()
|
||||||
|
|
||||||
|
return AuthUser(
|
||||||
|
name = userData.name,
|
||||||
|
id = userData.username.hashCode(),
|
||||||
|
profilePicture = userData.images?.avatar?.full
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun login(redirectUrl: String, payload: String?): AuthToken? {
|
||||||
|
val sanitizer =
|
||||||
|
splitRedirectUrl(redirectUrl)
|
||||||
|
|
||||||
|
if (sanitizer["state"] != payload) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://trakt.docs.apiary.io/#reference/authentication-oauth/get-token/exchange-code-for-access_token
|
||||||
|
val tokenData = app.post(
|
||||||
|
"$api/oauth/token",
|
||||||
|
json = mapOf(
|
||||||
|
"code" to (sanitizer["code"] ?: throw ErrorLoadingException("No code")),
|
||||||
|
"client_id" to id,
|
||||||
|
"client_secret" to secret,
|
||||||
|
"redirect_uri" to redirectUri,
|
||||||
|
"grant_type" to "authorization_code"
|
||||||
|
)
|
||||||
|
).parsed<TokenRoot>()
|
||||||
|
|
||||||
|
return AuthToken(
|
||||||
|
accessToken = tokenData.accessToken,
|
||||||
|
refreshToken = tokenData.refreshToken,
|
||||||
|
accessTokenLifetime = unixTime + tokenData.expiresIn
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun refreshToken(token: AuthToken): AuthToken? {
|
||||||
|
// https://trakt.docs.apiary.io/#reference/authentication-oauth/get-token/exchange-refresh_token-for-access_token
|
||||||
|
val tokenData = app.post(
|
||||||
|
"$api/oauth/token",
|
||||||
|
json = mapOf(
|
||||||
|
"refresh_token" to (token.refreshToken
|
||||||
|
?: throw ErrorLoadingException("No refreshtoken")),
|
||||||
|
"client_id" to id,
|
||||||
|
"client_secret" to secret,
|
||||||
|
"redirect_uri" to redirectUri,
|
||||||
|
"grant_type" to "refresh_token",
|
||||||
|
)
|
||||||
|
).parsed<TokenRoot>()
|
||||||
|
|
||||||
|
return AuthToken(
|
||||||
|
accessToken = tokenData.accessToken,
|
||||||
|
refreshToken = tokenData.refreshToken,
|
||||||
|
accessTokenLifetime = unixTime + tokenData.expiresIn
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun loginRequest(): AuthLoginPage? {
|
||||||
|
// https://trakt.docs.apiary.io/#reference/authentication-oauth/authorize/authorize-application
|
||||||
|
val codeChallenge = generateCodeVerifier()
|
||||||
|
return AuthLoginPage(
|
||||||
|
"$mainUrl/oauth/authorize?client_id=$id&response_type=code&redirect_uri=$redirectUri&state=$codeChallenge",
|
||||||
|
payload = codeChallenge
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class RatingRoot(
|
||||||
|
@JsonProperty("rated_at")
|
||||||
|
val ratedAt: String?,
|
||||||
|
@JsonProperty("rating")
|
||||||
|
val rating: Int?,
|
||||||
|
@JsonProperty("type")
|
||||||
|
val type: String,
|
||||||
|
@JsonProperty("season")
|
||||||
|
val season: Season?,
|
||||||
|
@JsonProperty("show")
|
||||||
|
val show: Show?,
|
||||||
|
@JsonProperty("movie")
|
||||||
|
val movie: Movie?,
|
||||||
|
) {
|
||||||
|
data class Season(
|
||||||
|
@JsonProperty("number")
|
||||||
|
val number: Long?,
|
||||||
|
@JsonProperty("ids")
|
||||||
|
val ids: Ids?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Show(
|
||||||
|
@JsonProperty("title")
|
||||||
|
val title: String?,
|
||||||
|
@JsonProperty("year")
|
||||||
|
val year: Long?,
|
||||||
|
@JsonProperty("ids")
|
||||||
|
val ids: Ids?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Movie(
|
||||||
|
@JsonProperty("title")
|
||||||
|
val title: String?,
|
||||||
|
@JsonProperty("year")
|
||||||
|
val year: Long?,
|
||||||
|
@JsonProperty("ids")
|
||||||
|
val ids: Ids?,
|
||||||
|
)
|
||||||
|
|
||||||
|
data class Ids(
|
||||||
|
@JsonProperty("trakt")
|
||||||
|
val trakt: String?,
|
||||||
|
@JsonProperty("slug")
|
||||||
|
val slug: String?,
|
||||||
|
@JsonProperty("tvdb")
|
||||||
|
val tvdb: String?,
|
||||||
|
@JsonProperty("imdb")
|
||||||
|
val imdb: String?,
|
||||||
|
@JsonProperty("tmdb")
|
||||||
|
val tmdb: String?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
data class TraktSyncStatus(
|
||||||
|
override var status: SyncWatchType = SyncWatchType.NONE,
|
||||||
|
override var score: Score?,
|
||||||
|
override var watchedEpisodes: Int? = null,
|
||||||
|
override var isFavorite: Boolean? = null,
|
||||||
|
override var maxEpisodes: Int? = null,
|
||||||
|
val type: String,
|
||||||
|
) : AbstractSyncStatus()
|
||||||
|
|
||||||
|
override suspend fun status(token: AuthToken?, id: String): AbstractSyncStatus? {
|
||||||
|
if (token == null) return null
|
||||||
|
|
||||||
|
val response = app.get("$api/sync/ratings/all", headers = getHeaders(token))
|
||||||
|
.parsed<Array<RatingRoot>>()
|
||||||
|
|
||||||
|
// This is criminally wrong, but there is no api to get the rating directly
|
||||||
|
for (x in response) {
|
||||||
|
if (x.show?.ids?.trakt == id || x.movie?.ids?.trakt == id || x.season?.ids?.trakt == id) {
|
||||||
|
return TraktSyncStatus(score = Score.from10(x.rating), type = x.type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return SyncStatus(SyncWatchType.NONE, null, null, null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -33,6 +33,7 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.malApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.openSubtitlesApi
|
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.openSubtitlesApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklApi
|
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.simklApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.subDlApi
|
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.subDlApi
|
||||||
|
import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.traktApi
|
||||||
import com.lagradost.cloudstream3.syncproviders.AuthLoginResponse
|
import com.lagradost.cloudstream3.syncproviders.AuthLoginResponse
|
||||||
import com.lagradost.cloudstream3.syncproviders.AuthRepo
|
import com.lagradost.cloudstream3.syncproviders.AuthRepo
|
||||||
import com.lagradost.cloudstream3.syncproviders.AuthUser
|
import com.lagradost.cloudstream3.syncproviders.AuthUser
|
||||||
|
|
@ -461,6 +462,7 @@ class SettingsAccount : PreferenceFragmentCompat(), BiometricCallback {
|
||||||
R.string.mal_key to SyncRepo(malApi),
|
R.string.mal_key to SyncRepo(malApi),
|
||||||
R.string.anilist_key to SyncRepo(aniListApi),
|
R.string.anilist_key to SyncRepo(aniListApi),
|
||||||
R.string.simkl_key to SyncRepo(simklApi),
|
R.string.simkl_key to SyncRepo(simklApi),
|
||||||
|
R.string.trakt_key to SyncRepo(traktApi),
|
||||||
R.string.opensubtitles_key to SubtitleRepo(openSubtitlesApi),
|
R.string.opensubtitles_key to SubtitleRepo(openSubtitlesApi),
|
||||||
R.string.subdl_key to SubtitleRepo(subDlApi),
|
R.string.subdl_key to SubtitleRepo(subDlApi),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
19
app/src/main/res/drawable/trakt.xml
Normal file
19
app/src/main/res/drawable/trakt.xml
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<vector
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:name="vector"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:tint="?attr/white"
|
||||||
|
android:viewportWidth="48"
|
||||||
|
android:viewportHeight="48">
|
||||||
|
<!--<path
|
||||||
|
android:name="path"
|
||||||
|
android:pathData="M 48 11.26 L 48 36.73 C 48 42.95 42.95 48 36.73 48 L 11.26 48 C 5.04 48 0 42.95 0 36.73 L 0 11.26 C 0 5.04 5.04 0 11.26 0 L 36.73 0 C 40.05 0 43.03 1.43 45.1 3.72 C 45.57 4.24 45.99 4.8 46.35 5.4 C 46.53 5.69 46.69 5.99 46.85 6.29 C 47.18 6.97 47.45 7.68 47.64 8.43 C 47.74 8.8 47.82 9.19 47.87 9.58 C 47.96 10.12 48 10.69 48 11.26 Z"
|
||||||
|
android:fillColor="#000000"
|
||||||
|
android:strokeWidth="1"/>-->
|
||||||
|
<path
|
||||||
|
android:name="path_1"
|
||||||
|
android:pathData="M 13.62 17.97 L 21.54 25.89 L 23.01 24.42 L 15.09 16.5 L 13.62 17.97 Z M 28.01 32.37 L 29.48 30.91 L 27.32 28.75 L 47.64 8.43 C 47.45 7.68 47.18 6.97 46.85 6.29 L 24.39 28.75 L 28.01 32.37 Z M 12.92 18.67 L 11.46 20.13 L 25.86 34.53 L 27.32 33.06 L 23 28.75 L 46.35 5.4 C 45.99 4.8 45.57 4.24 45.1 3.72 L 21.54 27.28 L 12.92 18.67 Z M 47.87 9.58 L 28.7 28.75 L 30.17 30.21 L 48 12.38 L 48 11.26 C 48 10.69 47.96 10.12 47.87 9.58 Z M 25.16 22.27 L 17.24 14.35 L 15.77 15.82 L 23.69 23.74 L 25.16 22.27 Z M 41.32 35.12 C 41.32 38.54 38.54 41.32 35.12 41.32 L 12.88 41.32 C 9.46 41.32 6.68 38.54 6.68 35.12 L 6.68 12.88 C 6.68 9.46 9.46 6.67 12.88 6.67 L 33.66 6.67 L 33.66 4.6 L 12.88 4.6 C 8.32 4.6 4.6 8.31 4.6 12.88 L 4.6 35.12 C 4.6 39.68 8.31 43.4 12.88 43.4 L 35.12 43.4 C 39.68 43.4 43.4 39.69 43.4 35.12 L 43.4 31.61 L 41.33 31.61 L 41.33 35.12 Z"
|
||||||
|
android:fillColor="#ffffff"
|
||||||
|
android:strokeWidth="1"/>
|
||||||
|
</vector>
|
||||||
|
|
@ -513,6 +513,7 @@
|
||||||
<string name="mal_key" translatable="false">mal_key</string>
|
<string name="mal_key" translatable="false">mal_key</string>
|
||||||
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
|
<string name="opensubtitles_key" translatable="false">opensubtitles_key</string>
|
||||||
<string name="subdl_key" translatable="false">subdl_key</string>
|
<string name="subdl_key" translatable="false">subdl_key</string>
|
||||||
|
<string name="trakt_key" translatable="false">trakt_key</string>
|
||||||
<string name="nginx_key" translatable="false">nginx_key</string>
|
<string name="nginx_key" translatable="false">nginx_key</string>
|
||||||
<string name="example_password">password123</string>
|
<string name="example_password">password123</string>
|
||||||
<string name="example_username">Username</string>
|
<string name="example_username">Username</string>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
android:icon="@drawable/simkl_logo"
|
android:icon="@drawable/simkl_logo"
|
||||||
android:key="@string/simkl_key" />
|
android:key="@string/simkl_key" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
android:icon="@drawable/trakt"
|
||||||
|
android:key="@string/trakt_key" />
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:icon="@drawable/open_subtitles_icon"
|
android:icon="@drawable/open_subtitles_icon"
|
||||||
android:key="@string/opensubtitles_key" />
|
android:key="@string/opensubtitles_key" />
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature
|
import com.fasterxml.jackson.databind.DeserializationFeature
|
||||||
import com.fasterxml.jackson.databind.json.JsonMapper
|
import com.fasterxml.jackson.databind.json.JsonMapper
|
||||||
import com.fasterxml.jackson.module.kotlin.kotlinModule
|
import com.fasterxml.jackson.module.kotlin.kotlinModule
|
||||||
|
import com.lagradost.cloudstream3.metaproviders.TraktProvider
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
import com.lagradost.cloudstream3.mvvm.safe
|
import com.lagradost.cloudstream3.mvvm.safe
|
||||||
import com.lagradost.cloudstream3.syncproviders.SyncIdName
|
import com.lagradost.cloudstream3.syncproviders.SyncIdName
|
||||||
|
|
@ -58,7 +59,7 @@ object APIHolder {
|
||||||
get() = System.currentTimeMillis()
|
get() = System.currentTimeMillis()
|
||||||
|
|
||||||
// ConcurrentModificationException is possible!!!
|
// ConcurrentModificationException is possible!!!
|
||||||
val allProviders = threadSafeListOf<MainAPI>()
|
val allProviders = threadSafeListOf<MainAPI>(TraktProvider())
|
||||||
|
|
||||||
fun initAll() {
|
fun initAll() {
|
||||||
synchronized(allProviders) {
|
synchronized(allProviders) {
|
||||||
|
|
@ -1695,6 +1696,7 @@ interface LoadResponse {
|
||||||
var malIdPrefix = "" //malApi.idPrefix
|
var malIdPrefix = "" //malApi.idPrefix
|
||||||
var aniListIdPrefix = "" //aniListApi.idPrefix
|
var aniListIdPrefix = "" //aniListApi.idPrefix
|
||||||
var simklIdPrefix = "" //simklApi.idPrefix
|
var simklIdPrefix = "" //simklApi.idPrefix
|
||||||
|
var traktIdPrefix = "" //simklApi.idPrefix
|
||||||
var isTrailersEnabled = true
|
var isTrailersEnabled = true
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1890,7 +1892,7 @@ interface LoadResponse {
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
fun LoadResponse.addTraktId(id: String?) {
|
fun LoadResponse.addTraktId(id: String?) {
|
||||||
// TODO add Trakt sync
|
this.syncData[traktIdPrefix] = (id ?: return).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("UNUSED_PARAMETER")
|
@Suppress("UNUSED_PARAMETER")
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addRating
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addRating
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTraktId
|
||||||
import com.lagradost.cloudstream3.MainAPI
|
import com.lagradost.cloudstream3.MainAPI
|
||||||
import com.lagradost.cloudstream3.MainPageRequest
|
import com.lagradost.cloudstream3.MainPageRequest
|
||||||
import com.lagradost.cloudstream3.NextAiring
|
import com.lagradost.cloudstream3.NextAiring
|
||||||
|
|
@ -192,6 +193,7 @@ open class TraktProvider : MainAPI() {
|
||||||
addTrailer(mediaDetails.trailer)
|
addTrailer(mediaDetails.trailer)
|
||||||
addImdbId(mediaDetails.ids?.imdb)
|
addImdbId(mediaDetails.ids?.imdb)
|
||||||
addTMDbId(mediaDetails.ids?.tmdb.toString())
|
addTMDbId(mediaDetails.ids?.tmdb.toString())
|
||||||
|
addTraktId(mediaDetails.ids?.trakt?.toString())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
|
@ -281,6 +283,7 @@ open class TraktProvider : MainAPI() {
|
||||||
addTrailer(mediaDetails.trailer)
|
addTrailer(mediaDetails.trailer)
|
||||||
addImdbId(mediaDetails.ids?.imdb)
|
addImdbId(mediaDetails.ids?.imdb)
|
||||||
addTMDbId(mediaDetails.ids?.tmdb.toString())
|
addTMDbId(mediaDetails.ids?.tmdb.toString())
|
||||||
|
addTraktId(mediaDetails.ids?.trakt?.toString())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue