From 9ba0661dde427c112f1ade768b938f4d9b9e009c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 17:46:20 -0600 Subject: [PATCH 001/192] Test kotlinx-serialization support --- .../lagradost/cloudstream3/MainActivity.kt | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt index 09d18feede6..97eb0fbdfc5 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt @@ -9,29 +9,54 @@ import com.lagradost.nicehttp.Requests import com.lagradost.nicehttp.ResponseParser import io.ktor.client.engine.okhttp.OkHttpEngine import okhttp3.OkHttpClient +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlin.reflect.KClass import kotlin.reflect.KClass // Short name for requests client to make it nicer to use +@OptIn(ExperimentalSerializationApi::class) private val jacksonResponseParser = object : ResponseParser { val mapper: ObjectMapper = jacksonObjectMapper().configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false ) + val kotlinxJson = Json { ignoreUnknownKeys = true } override fun parse(text: String, kClass: KClass): T { - return mapper.readValue(text, kClass.java) + val serializer = kotlinxJson.serializersModule.getContextual(kClass) + return if (serializer != null) { + try { + kotlinxJson.decodeFromString(serializer, text) + } catch (e: Exception) { + mapper.readValue(text, kClass.java) + } + } else { + mapper.readValue(text, kClass.java) + } } override fun parseSafe(text: String, kClass: KClass): T? { return try { - mapper.readValue(text, kClass.java) + parse(text, kClass) } catch (e: Exception) { null } } override fun writeValueAsString(obj: Any): String { - return mapper.writeValueAsString(obj) + val serializer = kotlinxJson.serializersModule.getContextual(obj::class) + return if (serializer != null) { + try { + // If it has a serializer, encode it safely via Kotlinx + kotlinxJson.encodeToString(kotlinxJson.serializersModule.serializer(obj::class.java), obj) + } catch (e: Exception) { + mapper.writeValueAsString(obj) + } + } else { + mapper.writeValueAsString(obj) + } } } From d7db2e0fa0271959803f0877fd03511fbe98353e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 17:46:43 -0600 Subject: [PATCH 002/192] - --- .../commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt index 97eb0fbdfc5..1d9fc4275ff 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt @@ -13,7 +13,6 @@ import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlin.reflect.KClass -import kotlin.reflect.KClass // Short name for requests client to make it nicer to use @OptIn(ExperimentalSerializationApi::class) From 94a6bc9ccd866c125c57aa203b153540d4b18e3c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 17:51:33 -0600 Subject: [PATCH 003/192] Add --- .../commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt index 1d9fc4275ff..fbecd87c40d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt @@ -12,6 +12,7 @@ import okhttp3.OkHttpClient import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.serializer import kotlin.reflect.KClass // Short name for requests client to make it nicer to use From 450e767dcb67e80797bda64a64ec4cec74236451 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 18:33:27 -0600 Subject: [PATCH 004/192] Update --- .../kotlin/com/lagradost/cloudstream3/MainActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt index fbecd87c40d..40202c5756e 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt @@ -50,7 +50,7 @@ private val jacksonResponseParser = object : ResponseParser { return if (serializer != null) { try { // If it has a serializer, encode it safely via Kotlinx - kotlinxJson.encodeToString(kotlinxJson.serializersModule.serializer(obj::class.java), obj) + kotlinxJson.encodeToString(JsonElement.serializer(), kotlinxJson.parseToJsonElement(obj.toString())) } catch (e: Exception) { mapper.writeValueAsString(obj) } From bcad70a5343cfb10a153ecffeb8c8e28fd84d9d9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:18:49 -0600 Subject: [PATCH 005/192] Try --- .../actions/temp/CloudStreamPackage.kt | 24 +- .../cloudstream3/plugins/PluginManager.kt | 14 +- .../cloudstream3/plugins/RepositoryManager.kt | 43 +- .../cloudstream3/syncproviders/AuthAPI.kt | 37 +- .../syncproviders/providers/AniListApi.kt | 396 +++++++++--------- .../syncproviders/providers/KitsuApi.kt | 112 ++--- .../syncproviders/providers/MALApi.kt | 276 ++++++------ .../providers/OpenSubtitlesApi.kt | 76 ++-- .../syncproviders/providers/SimklApi.kt | 244 ++++++----- .../syncproviders/providers/SubSource.kt | 63 +-- .../syncproviders/providers/Subdl.kt | 93 ++-- .../cloudstream3/ui/player/Torrent.kt | 94 +++-- .../ui/search/SearchHistoryAdaptor.kt | 12 +- .../ui/search/SearchSuggestionApi.kt | 17 +- .../ui/settings/SettingsGeneral.kt | 12 +- .../extensions/ExtensionsViewModel.kt | 10 +- .../subtitles/ChromecastSubtitlesFragment.kt | 20 +- .../ui/subtitles/SubtitlesFragment.kt | 38 +- .../cloudstream3/utils/BackupUtils.kt | 21 +- .../cloudstream3/utils/DataStoreHelper.kt | 90 ++-- .../cloudstream3/utils/FillerEpisodeCheck.kt | 57 +-- .../cloudstream3/utils/InAppUpdater.kt | 46 +- .../lagradost/cloudstream3/utils/SyncUtil.kt | 103 ++--- .../utils/downloader/DownloadObjects.kt | 134 +++--- .../cloudstream3/utils/videoskip/AniSkip.kt | 23 +- .../cloudstream3/utils/videoskip/AnimeSkip.kt | 77 ++-- .../utils/videoskip/IntroDbSkip.kt | 19 +- .../utils/videoskip/TheIntroDBSkip.kt | 21 +- .../com/lagradost/cloudstream3/MainAPI.kt | 53 ++- .../cloudstream3/extractors/Blogger.kt | 8 +- .../cloudstream3/extractors/ByseSX.kt | 33 +- .../cloudstream3/extractors/GUpload.kt | 20 +- .../cloudstream3/extractors/Gdriveplayer.kt | 10 +- .../cloudstream3/extractors/Gofile.kt | 24 +- .../extractors/HDMomPlayerExtractor.kt | 14 +- .../extractors/HDPlayerSystemExtractor.kt | 12 +- .../cloudstream3/extractors/Jeniusplay.kt | 10 +- .../cloudstream3/extractors/Linkbox.kt | 19 +- .../extractors/MailRuExtractor.kt | 13 +- .../extractors/OdnoklassnikiExtractor.kt | 8 +- .../extractors/PeaceMakerstExtractor.kt | 30 +- .../cloudstream3/extractors/PlayLtXyz.kt | 6 +- .../cloudstream3/extractors/Rabbitstream.kt | 29 +- .../extractors/SobreatsesuypExtractor.kt | 8 +- .../cloudstream3/extractors/StreamEmbed.kt | 20 +- .../cloudstream3/extractors/StreamSB.kt | 30 +- .../cloudstream3/extractors/Streamlare.kt | 21 +- .../cloudstream3/extractors/Streamplay.kt | 8 +- .../cloudstream3/extractors/Streamup.kt | 11 +- .../cloudstream3/extractors/TRsTXExtractor.kt | 8 +- .../cloudstream3/extractors/Tantifilm.kt | 19 +- .../extractors/TauVideoExtractor.kt | 11 +- .../cloudstream3/extractors/Uservideo.kt | 10 +- .../cloudstream3/extractors/Vicloud.kt | 11 +- .../extractors/VideoSeyredExtractor.kt | 30 +- .../cloudstream3/extractors/Vidoza.kt | 12 +- .../cloudstream3/extractors/Vinovo.kt | 8 +- .../cloudstream3/extractors/XStreamCdn.kt | 29 +- .../cloudstream3/extractors/YourUpload.kt | 6 +- .../extractors/helper/AesHelper.kt | 10 +- .../extractors/helper/GogoHelper.kt | 20 +- .../extractors/helper/JWPlayerHelper.kt | 17 +- .../extractors/helper/WcoHelper.kt | 15 +- .../metaproviders/CrossTmdbProvider.kt | 8 +- .../cloudstream3/metaproviders/MyDramaList.kt | 215 +++++----- .../metaproviders/TmdbProvider.kt | 14 +- .../metaproviders/TraktProvider.kt | 225 +++++----- .../cloudstream3/plugins/BasePlugin.kt | 12 +- .../cloudstream3/utils/ExtractorApi.kt | 4 +- 69 files changed, 1790 insertions(+), 1453 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt index d414b611783..9489c7381ad 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt @@ -4,7 +4,8 @@ import android.app.Activity import android.content.Context import android.content.Intent import android.net.Uri -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.actions.OpenInAppAction import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.ui.player.ExtractorUri @@ -49,18 +50,19 @@ class CloudStreamPackage : OpenInAppAction( const val DURATION_EXTRA: String = "dur" // Duration time in MS (Long) } + @Serializable data class MinimalVideoLink( - @JsonProperty("uri") + @SerialName("uri") val uri: Uri?, - @JsonProperty("url") + @SerialName("url") val url: String?, - @JsonProperty("mimeType") + @SerialName("mimeType") val mimeType: String = "video/mp4", - @JsonProperty("name") + @SerialName("name") val name: String?, - @JsonProperty("headers") + @SerialName("headers") var headers: Map = mapOf(), - @JsonProperty("quality") + @SerialName("quality") val quality: Int?, ) { companion object { @@ -99,13 +101,13 @@ class CloudStreamPackage : OpenInAppAction( data class MinimalSubtitleLink( - @JsonProperty("url") + @SerialName("url") val url: String, - @JsonProperty("mimeType") + @SerialName("mimeType") val mimeType: String = "text/vtt", - @JsonProperty("name") + @SerialName("name") val name: String?, - @JsonProperty("headers") + @SerialName("headers") var headers: Map = mapOf(), ) { companion object { diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt index eae14a6c0c3..a8d3ee103d6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt @@ -18,7 +18,8 @@ import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.fragment.app.FragmentActivity -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.removePluginMapping import com.lagradost.cloudstream3.AllLanguagesName @@ -73,12 +74,13 @@ const val EXTENSIONS_CHANNEL_NAME = "Extensions" const val EXTENSIONS_CHANNEL_DESCRIPT = "Extension notification channel" // Data class for internal storage +@Serializable data class PluginData( - @JsonProperty("internalName") val internalName: String, - @JsonProperty("url") val url: String?, - @JsonProperty("isOnline") val isOnline: Boolean, - @JsonProperty("filePath") val filePath: String, - @JsonProperty("version") val version: Int, + @SerialName("internalName") val internalName: String, + @SerialName("url") val url: String?, + @SerialName("isOnline") val isOnline: Boolean, + @SerialName("filePath") val filePath: String, + @SerialName("version") val version: Int, ) { @WorkerThread fun toSitePlugin(): SitePlugin { diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt index 65eda36ea2c..ba149f79a5f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt @@ -2,7 +2,8 @@ package com.lagradost.cloudstream3.plugins import android.content.Context import androidx.annotation.WorkerThread -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey @@ -30,12 +31,13 @@ import java.util.concurrent.atomic.AtomicInteger * Comes with the app, always available in the app, non removable. * */ +@Serializable data class Repository( - @JsonProperty("iconUrl") val iconUrl: String?, - @JsonProperty("name") val name: String, - @JsonProperty("description") val description: String?, - @JsonProperty("manifestVersion") val manifestVersion: Int, - @JsonProperty("pluginLists") val pluginLists: List + @SerialName("iconUrl") val iconUrl: String?, + @SerialName("name") val name: String, + @SerialName("description") val description: String?, + @SerialName("manifestVersion") val manifestVersion: Int, + @SerialName("pluginLists") val pluginLists: List ) /** @@ -45,32 +47,33 @@ data class Repository( * 2: Slow * 3: Beta only * */ + @Serializable data class SitePlugin( // Url to the .cs3 file - @JsonProperty("url") val url: String, + @SerialName("url") val url: String, // Status to remotely disable the provider - @JsonProperty("status") val status: Int, + @SerialName("status") val status: Int, // Integer over 0, any change of this will trigger an auto update - @JsonProperty("version") val version: Int, + @SerialName("version") val version: Int, // Unused currently, used to make the api backwards compatible? // Set to 1 - @JsonProperty("apiVersion") val apiVersion: Int, + @SerialName("apiVersion") val apiVersion: Int, // Name to be shown in app - @JsonProperty("name") val name: String, + @SerialName("name") val name: String, // Name to be referenced internally. Separate to make name and url changes possible - @JsonProperty("internalName") val internalName: String, - @JsonProperty("authors") val authors: List, - @JsonProperty("description") val description: String?, + @SerialName("internalName") val internalName: String, + @SerialName("authors") val authors: List, + @SerialName("description") val description: String?, // Might be used to go directly to the plugin repo in the future - @JsonProperty("repositoryUrl") val repositoryUrl: String?, + @SerialName("repositoryUrl") val repositoryUrl: String?, // These types are yet to be mapped and used, ignore for now - @JsonProperty("tvTypes") val tvTypes: List?, + @SerialName("tvTypes") val tvTypes: List?, // Most often a language tag like "en" or "zh-TW" - @JsonProperty("language") val language: String?, - @JsonProperty("iconUrl") val iconUrl: String?, + @SerialName("language") val language: String?, + @SerialName("iconUrl") val iconUrl: String?, // Automatically generated by the gradle plugin - @JsonProperty("fileSize") val fileSize: Long?, - @JsonProperty("fileHash") val fileHash: String?, + @SerialName("fileSize") val fileSize: Long?, + @SerialName("fileHash") val fileHash: String?, ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 83a7a09847c..b6625ca2119 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -2,7 +2,8 @@ package com.lagradost.cloudstream3.syncproviders import android.util.Base64 import androidx.annotation.WorkerThread -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder.unixTime import com.lagradost.cloudstream3.ActorData import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -56,28 +57,29 @@ data class AuthLoginPage( val payload: String? = null, ) +@Serializable data class AuthToken( /** * This is the general access tokens/api token representing a logged in user. * * `Access tokens are the thing that applications use to make API requests on behalf of a user.` * */ - @JsonProperty("accessToken") + @SerialName("accessToken") val accessToken: String? = null, /** * For OAuth a special refresh token is issues to refresh the access token. * */ - @JsonProperty("refreshToken") + @SerialName("refreshToken") val refreshToken: String? = null, /** In UnixTime (sec) when it expires */ - @JsonProperty("accessTokenLifetime") + @SerialName("accessTokenLifetime") val accessTokenLifetime: Long? = null, /** In UnixTime (sec) when it expires */ - @JsonProperty("refreshTokenLifetime") + @SerialName("refreshTokenLifetime") val refreshTokenLifetime: Long? = null, /** Sometimes AuthToken needs to be customized to store e.g. username/password, * this acts as a catch all to store text or JSON data. */ - @JsonProperty("payload") + @SerialName("payload") val payload: String? = null, ) { fun isAccessTokenExpired(marginSec: Long = 10L) = @@ -87,19 +89,20 @@ data class AuthToken( refreshTokenLifetime != null && (System.currentTimeMillis() / 1000) + marginSec >= refreshTokenLifetime } +@Serializable data class AuthUser( /** Account display-name, can also be email if name does not exist */ - @JsonProperty("name") + @SerialName("name") val name: String?, /** Unique account identifier, * if a subsequent login is done then it will be refused if another account with the same id exists*/ - @JsonProperty("id") + @SerialName("id") val id: Int, /** Profile picture URL */ - @JsonProperty("profilePicture") + @SerialName("profilePicture") val profilePicture: String? = null, /** Profile picture Headers of the URL */ - @JsonProperty("profilePictureHeader") + @SerialName("profilePictureHeader") val profilePictureHeaders: Map? = null ) @@ -111,10 +114,11 @@ data class AuthUser( * Any local set/get key should use user.id.toString(), * as token.accessToken (even hashed) is unsecure, and will rotate. * */ +@Serializable data class AuthData( - @JsonProperty("user") + @SerialName("user") val user: AuthUser, - @JsonProperty("token") + @SerialName("token") val token: AuthToken, ) @@ -138,14 +142,15 @@ data class AuthLoginRequirement( ) /** What the user responds to the AuthLoginRequirement */ +@Serializable data class AuthLoginResponse( - @JsonProperty("password") + @SerialName("password") val password: String?, - @JsonProperty("username") + @SerialName("username") val username: String?, - @JsonProperty("email") + @SerialName("email") val email: String?, - @JsonProperty("server") + @SerialName("server") val server: String?, ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 788e95912eb..2d87fa7709a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.ActorData import com.lagradost.cloudstream3.ActorRole @@ -525,65 +526,73 @@ class AniListApi : SyncAPI() { } + @Serializable data class MediaRecommendation( - @JsonProperty("id") val id: Int, - @JsonProperty("title") val title: Title?, - @JsonProperty("idMal") val idMal: Int?, - @JsonProperty("coverImage") val coverImage: CoverImage?, - @JsonProperty("averageScore") val averageScore: Int? + @SerialName("id") val id: Int, + @SerialName("title") val title: Title?, + @SerialName("idMal") val idMal: Int?, + @SerialName("coverImage") val coverImage: CoverImage?, + @SerialName("averageScore") val averageScore: Int? ) + @Serializable data class FullAnilistList( - @JsonProperty("data") val data: Data? + @SerialName("data") val data: Data? ) + @Serializable data class CompletedAt( - @JsonProperty("year") val year: Int, - @JsonProperty("month") val month: Int, - @JsonProperty("day") val day: Int + @SerialName("year") val year: Int, + @SerialName("month") val month: Int, + @SerialName("day") val day: Int ) + @Serializable data class StartedAt( - @JsonProperty("year") val year: String?, - @JsonProperty("month") val month: String?, - @JsonProperty("day") val day: String? + @SerialName("year") val year: String?, + @SerialName("month") val month: String?, + @SerialName("day") val day: String? ) + @Serializable data class Title( - @JsonProperty("english") val english: String?, - @JsonProperty("romaji") val romaji: String? + @SerialName("english") val english: String?, + @SerialName("romaji") val romaji: String? ) + @Serializable data class CoverImage( - @JsonProperty("medium") val medium: String?, - @JsonProperty("large") val large: String?, - @JsonProperty("extraLarge") val extraLarge: String? + @SerialName("medium") val medium: String?, + @SerialName("large") val large: String?, + @SerialName("extraLarge") val extraLarge: String? ) + @Serializable data class Media( - @JsonProperty("id") val id: Int, - @JsonProperty("idMal") val idMal: Int?, - @JsonProperty("season") val season: String?, - @JsonProperty("seasonYear") val seasonYear: Int, - @JsonProperty("format") val format: String?, - //@JsonProperty("source") val source: String, - @JsonProperty("episodes") val episodes: Int, - @JsonProperty("title") val title: Title, - @JsonProperty("description") val description: String?, - @JsonProperty("coverImage") val coverImage: CoverImage, - @JsonProperty("synonyms") val synonyms: List, - @JsonProperty("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @SerialName("id") val id: Int, + @SerialName("idMal") val idMal: Int?, + @SerialName("season") val season: String?, + @SerialName("seasonYear") val seasonYear: Int, + @SerialName("format") val format: String?, + //@SerialName("source") val source: String, + @SerialName("episodes") val episodes: Int, + @SerialName("title") val title: Title, + @SerialName("description") val description: String?, + @SerialName("coverImage") val coverImage: CoverImage, + @SerialName("synonyms") val synonyms: List, + @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, ) + @Serializable data class Entries( - @JsonProperty("status") val status: String?, - @JsonProperty("completedAt") val completedAt: CompletedAt, - @JsonProperty("startedAt") val startedAt: StartedAt, - @JsonProperty("updatedAt") val updatedAt: Int, - @JsonProperty("progress") val progress: Int, - @JsonProperty("score") val score: Int, - @JsonProperty("private") val private: Boolean, - @JsonProperty("media") val media: Media + @SerialName("status") val status: String?, + @SerialName("completedAt") val completedAt: CompletedAt, + @SerialName("startedAt") val startedAt: StartedAt, + @SerialName("updatedAt") val updatedAt: Int, + @SerialName("progress") val progress: Int, + @SerialName("score") val score: Int, + @SerialName("private") val private: Boolean, + @SerialName("media") val media: Media ) { fun toLibraryItem(): SyncAPI.LibraryItem { return SyncAPI.LibraryItem( @@ -610,17 +619,20 @@ class AniListApi : SyncAPI() { } } + @Serializable data class Lists( - @JsonProperty("status") val status: String?, - @JsonProperty("entries") val entries: List + @SerialName("status") val status: String?, + @SerialName("entries") val entries: List ) + @Serializable data class MediaListCollection( - @JsonProperty("lists") val lists: List + @SerialName("lists") val lists: List ) + @Serializable data class Data( - @JsonProperty("MediaListCollection") val mediaListCollection: MediaListCollection + @SerialName("MediaListCollection") val mediaListCollection: MediaListCollection ) private suspend fun getAniListAnimeListSmart(auth: AuthData): Array? { @@ -732,9 +744,9 @@ class AniListApi : SyncAPI() { } /** Used to query a saved MediaItem on the list to get the id for removal */ - data class MediaListItemRoot(@JsonProperty("data") val data: MediaListItem? = null) - data class MediaListItem(@JsonProperty("MediaList") val mediaList: MediaListId? = null) - data class MediaListId(@JsonProperty("id") val id: Long? = null) + data class MediaListItemRoot(@SerialName("data") val data: MediaListItem? = null) + data class MediaListItem(@SerialName("MediaList") val mediaList: MediaListId? = null) + data class MediaListId(@SerialName("id") val id: Long? = null) private suspend fun postDataAboutId( auth : AuthData, @@ -837,73 +849,73 @@ class AniListApi : SyncAPI() { } data class SeasonResponse( - @JsonProperty("data") val data: SeasonData, + @SerialName("data") val data: SeasonData, ) data class SeasonData( - @JsonProperty("Media") val media: SeasonMedia, + @SerialName("Media") val media: SeasonMedia, ) data class SeasonMedia( - @JsonProperty("id") val id: Int?, - @JsonProperty("title") val title: MediaTitle?, - @JsonProperty("idMal") val idMal: Int?, - @JsonProperty("format") val format: String?, - @JsonProperty("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, - @JsonProperty("relations") val relations: SeasonEdges?, - @JsonProperty("coverImage") val coverImage: MediaCoverImage?, - @JsonProperty("duration") val duration: Int?, - @JsonProperty("episodes") val episodes: Int?, - @JsonProperty("genres") val genres: List?, - @JsonProperty("synonyms") val synonyms: List?, - @JsonProperty("averageScore") val averageScore: Int?, - @JsonProperty("isAdult") val isAdult: Boolean?, - @JsonProperty("trailer") val trailer: MediaTrailer?, - @JsonProperty("description") val description: String?, - @JsonProperty("characters") val characters: CharacterConnection?, - @JsonProperty("recommendations") val recommendations: RecommendationConnection?, + @SerialName("id") val id: Int?, + @SerialName("title") val title: MediaTitle?, + @SerialName("idMal") val idMal: Int?, + @SerialName("format") val format: String?, + @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @SerialName("relations") val relations: SeasonEdges?, + @SerialName("coverImage") val coverImage: MediaCoverImage?, + @SerialName("duration") val duration: Int?, + @SerialName("episodes") val episodes: Int?, + @SerialName("genres") val genres: List?, + @SerialName("synonyms") val synonyms: List?, + @SerialName("averageScore") val averageScore: Int?, + @SerialName("isAdult") val isAdult: Boolean?, + @SerialName("trailer") val trailer: MediaTrailer?, + @SerialName("description") val description: String?, + @SerialName("characters") val characters: CharacterConnection?, + @SerialName("recommendations") val recommendations: RecommendationConnection?, ) data class RecommendationConnection( - @JsonProperty("edges") val edges: List = emptyList(), - @JsonProperty("nodes") val nodes: List = emptyList(), - //@JsonProperty("pageInfo") val pageInfo: PageInfo, + @SerialName("edges") val edges: List = emptyList(), + @SerialName("nodes") val nodes: List = emptyList(), + //@SerialName("pageInfo") val pageInfo: PageInfo, ) data class RecommendationEdge( - //@JsonProperty("rating") val rating: Int, - @JsonProperty("node") val node: Recommendation, + //@SerialName("rating") val rating: Int, + @SerialName("node") val node: Recommendation, ) data class Recommendation( val id: Long, - @JsonProperty("mediaRecommendation") val mediaRecommendation: SeasonMedia?, + @SerialName("mediaRecommendation") val mediaRecommendation: SeasonMedia?, ) data class CharacterName( - @JsonProperty("name") val first: String?, - @JsonProperty("middle") val middle: String?, - @JsonProperty("last") val last: String?, - @JsonProperty("full") val full: String?, - @JsonProperty("native") val native: String?, - @JsonProperty("alternative") val alternative: List?, - @JsonProperty("alternativeSpoiler") val alternativeSpoiler: List?, - @JsonProperty("userPreferred") val userPreferred: String?, + @SerialName("name") val first: String?, + @SerialName("middle") val middle: String?, + @SerialName("last") val last: String?, + @SerialName("full") val full: String?, + @SerialName("native") val native: String?, + @SerialName("alternative") val alternative: List?, + @SerialName("alternativeSpoiler") val alternativeSpoiler: List?, + @SerialName("userPreferred") val userPreferred: String?, ) data class CharacterImage( - @JsonProperty("large") val large: String?, - @JsonProperty("medium") val medium: String?, + @SerialName("large") val large: String?, + @SerialName("medium") val medium: String?, ) data class Character( - @JsonProperty("name") val name: CharacterName?, - @JsonProperty("age") val age: String?, - @JsonProperty("image") val image: CharacterImage?, + @SerialName("name") val name: CharacterName?, + @SerialName("age") val age: String?, + @SerialName("image") val image: CharacterImage?, ) data class CharacterEdge( - @JsonProperty("id") val id: Int?, + @SerialName("id") val id: Int?, /** MAIN A primary character role in the media @@ -914,227 +926,227 @@ class AniListApi : SyncAPI() { BACKGROUND A background character in the media */ - @JsonProperty("role") val role: String?, - @JsonProperty("name") val name: String?, - @JsonProperty("voiceActors") val voiceActors: List?, - @JsonProperty("favouriteOrder") val favouriteOrder: Int?, - @JsonProperty("media") val media: List?, - @JsonProperty("node") val node: Character?, + @SerialName("role") val role: String?, + @SerialName("name") val name: String?, + @SerialName("voiceActors") val voiceActors: List?, + @SerialName("favouriteOrder") val favouriteOrder: Int?, + @SerialName("media") val media: List?, + @SerialName("node") val node: Character?, ) data class StaffImage( - @JsonProperty("large") val large: String?, - @JsonProperty("medium") val medium: String?, + @SerialName("large") val large: String?, + @SerialName("medium") val medium: String?, ) data class StaffName( - @JsonProperty("name") val first: String?, - @JsonProperty("middle") val middle: String?, - @JsonProperty("last") val last: String?, - @JsonProperty("full") val full: String?, - @JsonProperty("native") val native: String?, - @JsonProperty("alternative") val alternative: List?, - @JsonProperty("userPreferred") val userPreferred: String?, + @SerialName("name") val first: String?, + @SerialName("middle") val middle: String?, + @SerialName("last") val last: String?, + @SerialName("full") val full: String?, + @SerialName("native") val native: String?, + @SerialName("alternative") val alternative: List?, + @SerialName("userPreferred") val userPreferred: String?, ) data class Staff( - @JsonProperty("image") val image: StaffImage?, - @JsonProperty("name") val name: StaffName?, - @JsonProperty("age") val age: Int?, + @SerialName("image") val image: StaffImage?, + @SerialName("name") val name: StaffName?, + @SerialName("age") val age: Int?, ) data class CharacterConnection( - @JsonProperty("edges") val edges: List?, - @JsonProperty("nodes") val nodes: List?, - //@JsonProperty("pageInfo") pageInfo: PageInfo + @SerialName("edges") val edges: List?, + @SerialName("nodes") val nodes: List?, + //@SerialName("pageInfo") pageInfo: PageInfo ) data class MediaTrailer( - @JsonProperty("id") val id: String?, - @JsonProperty("site") val site: String?, - @JsonProperty("thumbnail") val thumbnail: String?, + @SerialName("id") val id: String?, + @SerialName("site") val site: String?, + @SerialName("thumbnail") val thumbnail: String?, ) data class MediaCoverImage( - @JsonProperty("extraLarge") val extraLarge: String?, - @JsonProperty("large") val large: String?, - @JsonProperty("medium") val medium: String?, - @JsonProperty("color") val color: String?, + @SerialName("extraLarge") val extraLarge: String?, + @SerialName("large") val large: String?, + @SerialName("medium") val medium: String?, + @SerialName("color") val color: String?, ) data class SeasonNextAiringEpisode( - @JsonProperty("episode") val episode: Int?, - @JsonProperty("timeUntilAiring") val timeUntilAiring: Int?, + @SerialName("episode") val episode: Int?, + @SerialName("timeUntilAiring") val timeUntilAiring: Int?, ) data class SeasonEdges( - @JsonProperty("edges") val edges: List?, + @SerialName("edges") val edges: List?, ) data class SeasonEdge( - @JsonProperty("id") val id: Int?, - @JsonProperty("relationType") val relationType: String?, - @JsonProperty("node") val node: SeasonNode?, + @SerialName("id") val id: Int?, + @SerialName("relationType") val relationType: String?, + @SerialName("node") val node: SeasonNode?, ) data class AniListFavoritesMediaConnection( - @JsonProperty("nodes") val nodes: List, + @SerialName("nodes") val nodes: List, ) data class AniListFavourites( - @JsonProperty("anime") val anime: AniListFavoritesMediaConnection, + @SerialName("anime") val anime: AniListFavoritesMediaConnection, ) data class MediaTitle( - @JsonProperty("romaji") val romaji: String?, - @JsonProperty("english") val english: String?, - @JsonProperty("native") val native: String?, - @JsonProperty("userPreferred") val userPreferred: String?, + @SerialName("romaji") val romaji: String?, + @SerialName("english") val english: String?, + @SerialName("native") val native: String?, + @SerialName("userPreferred") val userPreferred: String?, ) data class SeasonNode( - @JsonProperty("id") val id: Int, - @JsonProperty("format") val format: String?, - @JsonProperty("title") val title: Title?, - @JsonProperty("idMal") val idMal: Int?, - @JsonProperty("coverImage") val coverImage: CoverImage?, - @JsonProperty("averageScore") val averageScore: Int? -// @JsonProperty("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @SerialName("id") val id: Int, + @SerialName("format") val format: String?, + @SerialName("title") val title: Title?, + @SerialName("idMal") val idMal: Int?, + @SerialName("coverImage") val coverImage: CoverImage?, + @SerialName("averageScore") val averageScore: Int? +// @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, ) data class AniListAvatar( - @JsonProperty("large") val large: String?, + @SerialName("large") val large: String?, ) data class AniListViewer( - @JsonProperty("id") val id: Int, - @JsonProperty("name") val name: String, - @JsonProperty("avatar") val avatar: AniListAvatar?, - @JsonProperty("favourites") val favourites: AniListFavourites?, + @SerialName("id") val id: Int, + @SerialName("name") val name: String, + @SerialName("avatar") val avatar: AniListAvatar?, + @SerialName("favourites") val favourites: AniListFavourites?, ) data class AniListData( - @JsonProperty("Viewer") val viewer: AniListViewer?, + @SerialName("Viewer") val viewer: AniListViewer?, ) data class AniListRoot( - @JsonProperty("data") val data: AniListData?, + @SerialName("data") val data: AniListData?, ) data class AniListUser( - @JsonProperty("id") val id: Int, - @JsonProperty("name") val name: String, - @JsonProperty("picture") val picture: String?, + @SerialName("id") val id: Int, + @SerialName("name") val name: String, + @SerialName("picture") val picture: String?, ) data class LikeNode( - @JsonProperty("id") val id: Int?, - //@JsonProperty("idMal") public int idMal; + @SerialName("id") val id: Int?, + //@SerialName("idMal") public int idMal; ) data class LikePageInfo( - @JsonProperty("total") val total: Int?, - @JsonProperty("currentPage") val currentPage: Int?, - @JsonProperty("lastPage") val lastPage: Int?, - @JsonProperty("perPage") val perPage: Int?, - @JsonProperty("hasNextPage") val hasNextPage: Boolean?, + @SerialName("total") val total: Int?, + @SerialName("currentPage") val currentPage: Int?, + @SerialName("lastPage") val lastPage: Int?, + @SerialName("perPage") val perPage: Int?, + @SerialName("hasNextPage") val hasNextPage: Boolean?, ) data class LikeAnime( - @JsonProperty("nodes") val nodes: List?, - @JsonProperty("pageInfo") val pageInfo: LikePageInfo?, + @SerialName("nodes") val nodes: List?, + @SerialName("pageInfo") val pageInfo: LikePageInfo?, ) data class LikeFavourites( - @JsonProperty("anime") val anime: LikeAnime?, + @SerialName("anime") val anime: LikeAnime?, ) data class LikeViewer( - @JsonProperty("favourites") val favourites: LikeFavourites?, + @SerialName("favourites") val favourites: LikeFavourites?, ) data class LikeData( - @JsonProperty("Viewer") val viewer: LikeViewer?, + @SerialName("Viewer") val viewer: LikeViewer?, ) data class LikeRoot( - @JsonProperty("data") val data: LikeData?, + @SerialName("data") val data: LikeData?, ) data class AniListTitleHolder( - @JsonProperty("title") val title: Title?, - @JsonProperty("isFavourite") val isFavourite: Boolean?, - @JsonProperty("id") val id: Int?, - @JsonProperty("progress") val progress: Int?, - @JsonProperty("episodes") val episodes: Int?, - @JsonProperty("score") val score: Int?, - @JsonProperty("type") val type: AniListStatusType?, + @SerialName("title") val title: Title?, + @SerialName("isFavourite") val isFavourite: Boolean?, + @SerialName("id") val id: Int?, + @SerialName("progress") val progress: Int?, + @SerialName("episodes") val episodes: Int?, + @SerialName("score") val score: Int?, + @SerialName("type") val type: AniListStatusType?, ) data class GetDataMediaListEntry( - @JsonProperty("progress") val progress: Int?, - @JsonProperty("status") val status: String?, - @JsonProperty("score") val score: Int?, + @SerialName("progress") val progress: Int?, + @SerialName("status") val status: String?, + @SerialName("score") val score: Int?, ) data class Nodes( - @JsonProperty("id") val id: Int?, - @JsonProperty("mediaRecommendation") val mediaRecommendation: MediaRecommendation? + @SerialName("id") val id: Int?, + @SerialName("mediaRecommendation") val mediaRecommendation: MediaRecommendation? ) data class GetDataMedia( - @JsonProperty("isFavourite") val isFavourite: Boolean?, - @JsonProperty("episodes") val episodes: Int?, - @JsonProperty("title") val title: Title?, - @JsonProperty("mediaListEntry") val mediaListEntry: GetDataMediaListEntry? + @SerialName("isFavourite") val isFavourite: Boolean?, + @SerialName("episodes") val episodes: Int?, + @SerialName("title") val title: Title?, + @SerialName("mediaListEntry") val mediaListEntry: GetDataMediaListEntry? ) data class Recommendations( - @JsonProperty("nodes") val nodes: List? + @SerialName("nodes") val nodes: List? ) data class GetDataData( - @JsonProperty("Media") val media: GetDataMedia?, + @SerialName("Media") val media: GetDataMedia?, ) data class GetDataRoot( - @JsonProperty("data") val data: GetDataData?, + @SerialName("data") val data: GetDataData?, ) data class GetSearchTitle( - @JsonProperty("romaji") val romaji: String?, + @SerialName("romaji") val romaji: String?, ) data class TrailerObject( - @JsonProperty("id") val id: String?, - @JsonProperty("thumbnail") val thumbnail: String?, - @JsonProperty("site") val site: String?, + @SerialName("id") val id: String?, + @SerialName("thumbnail") val thumbnail: String?, + @SerialName("site") val site: String?, ) data class GetSearchMedia( - @JsonProperty("id") val id: Int, - @JsonProperty("idMal") val idMal: Int?, - @JsonProperty("seasonYear") val seasonYear: Int, - @JsonProperty("title") val title: GetSearchTitle, - @JsonProperty("startDate") val startDate: StartedAt, - @JsonProperty("averageScore") val averageScore: Int?, - @JsonProperty("meanScore") val meanScore: Int?, - @JsonProperty("bannerImage") val bannerImage: String?, - @JsonProperty("trailer") val trailer: TrailerObject?, - @JsonProperty("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, - @JsonProperty("recommendations") val recommendations: Recommendations?, - @JsonProperty("relations") val relations: SeasonEdges? + @SerialName("id") val id: Int, + @SerialName("idMal") val idMal: Int?, + @SerialName("seasonYear") val seasonYear: Int, + @SerialName("title") val title: GetSearchTitle, + @SerialName("startDate") val startDate: StartedAt, + @SerialName("averageScore") val averageScore: Int?, + @SerialName("meanScore") val meanScore: Int?, + @SerialName("bannerImage") val bannerImage: String?, + @SerialName("trailer") val trailer: TrailerObject?, + @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @SerialName("recommendations") val recommendations: Recommendations?, + @SerialName("relations") val relations: SeasonEdges? ) data class GetSearchPage( - @JsonProperty("Page") val page: GetSearchData?, + @SerialName("Page") val page: GetSearchData?, ) data class GetSearchData( - @JsonProperty("media") val media: List?, + @SerialName("media") val media: List?, ) data class GetSearchRoot( - @JsonProperty("data") val data: GetSearchPage?, + @SerialName("data") val data: GetSearchPage?, ) } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt index 29c3c0c1793..90009b7f7ac 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt @@ -2,7 +2,8 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R @@ -489,18 +490,20 @@ class KitsuApi: SyncAPI() { } + @Serializable data class ResponseToken( - @JsonProperty("token_type") val tokenType: String, - @JsonProperty("expires_in") val expiresIn: Int, - @JsonProperty("access_token") val accessToken: String, - @JsonProperty("refresh_token") val refreshToken: String, + @SerialName("token_type") val tokenType: String, + @SerialName("expires_in") val expiresIn: Int, + @SerialName("access_token") val accessToken: String, + @SerialName("refresh_token") val refreshToken: String, ) + @Serializable data class KitsuNode( - @JsonProperty("id") val id: String, - @JsonProperty("attributes") val attributes: KitsuNodeAttributes, + @SerialName("id") val id: String, + @SerialName("attributes") val attributes: KitsuNodeAttributes, /* User list anime node */ - @JsonProperty("relationships") val relationships: KitsuRelationships?, + @SerialName("relationships") val relationships: KitsuRelationships?, var anime: KitsuAnimeData? ) { fun toLibraryItem(): LibraryItem { @@ -549,81 +552,91 @@ class KitsuApi: SyncAPI() { } + @Serializable data class KitsuAnimeAttributes( - @JsonProperty("titles") val titles: KitsuTitles?, - @JsonProperty("canonicalTitle") val canonicalTitle: String?, - @JsonProperty("posterImage") val posterImage: KitsuPosterImage?, - @JsonProperty("synopsis") val synopsis: String?, - @JsonProperty("startDate") val startDate: String?, - @JsonProperty("endDate") val endDate: String?, - @JsonProperty("episodeCount") val episodeCount: Int?, - @JsonProperty("episodeLength") val episodeLength: Int?, + @SerialName("titles") val titles: KitsuTitles?, + @SerialName("canonicalTitle") val canonicalTitle: String?, + @SerialName("posterImage") val posterImage: KitsuPosterImage?, + @SerialName("synopsis") val synopsis: String?, + @SerialName("startDate") val startDate: String?, + @SerialName("endDate") val endDate: String?, + @SerialName("episodeCount") val episodeCount: Int?, + @SerialName("episodeLength") val episodeLength: Int?, ) + @Serializable data class KitsuAnimeData( - @JsonProperty("id") val id: String, - @JsonProperty("attributes") val attributes: KitsuAnimeAttributes, + @SerialName("id") val id: String, + @SerialName("attributes") val attributes: KitsuAnimeAttributes, ) + @Serializable data class KitsuNodeAttributes( /* General attributes */ - @JsonProperty("titles") val titles: KitsuTitles?, - @JsonProperty("canonicalTitle") val canonicalTitle: String?, - @JsonProperty("posterImage") val posterImage: KitsuPosterImage?, - @JsonProperty("synopsis") val synopsis: String?, - @JsonProperty("startDate") val startDate: String?, - @JsonProperty("endDate") val endDate: String?, - @JsonProperty("episodeCount") val episodeCount: Int?, - @JsonProperty("episodeLength") val episodeLength: Int?, + @SerialName("titles") val titles: KitsuTitles?, + @SerialName("canonicalTitle") val canonicalTitle: String?, + @SerialName("posterImage") val posterImage: KitsuPosterImage?, + @SerialName("synopsis") val synopsis: String?, + @SerialName("startDate") val startDate: String?, + @SerialName("endDate") val endDate: String?, + @SerialName("episodeCount") val episodeCount: Int?, + @SerialName("episodeLength") val episodeLength: Int?, /* User attributes */ - @JsonProperty("name") val name: String?, - @JsonProperty("location") val location: String?, - @JsonProperty("createdAt") val createdAt: String?, - @JsonProperty("avatar") val avatar: KitsuUserAvatar?, + @SerialName("name") val name: String?, + @SerialName("location") val location: String?, + @SerialName("createdAt") val createdAt: String?, + @SerialName("avatar") val avatar: KitsuUserAvatar?, /* User list anime attributes */ - @JsonProperty("progress") val progress: Int?, - @JsonProperty("ratingTwenty") val ratingTwenty: Float?, - @JsonProperty("updatedAt") val updatedAt: String?, - @JsonProperty("status") val status: String?, + @SerialName("progress") val progress: Int?, + @SerialName("ratingTwenty") val ratingTwenty: Float?, + @SerialName("updatedAt") val updatedAt: String?, + @SerialName("status") val status: String?, ) + @Serializable data class KitsuRelationships( - @JsonProperty("anime") val anime: KitsuRelationshipsAnime? + @SerialName("anime") val anime: KitsuRelationshipsAnime? ) + @Serializable data class KitsuRelationshipsAnime( - @JsonProperty("links") val links: KitsuLinks? + @SerialName("links") val links: KitsuLinks? ) + @Serializable data class KitsuPosterImage( - @JsonProperty("large") val large: String?, - @JsonProperty("medium") val medium: String?, + @SerialName("large") val large: String?, + @SerialName("medium") val medium: String?, ) + @Serializable data class KitsuTitles( - @JsonProperty("en_jp") val enJp: String?, - @JsonProperty("ja_jp") val jaJp: String? + @SerialName("en_jp") val enJp: String?, + @SerialName("ja_jp") val jaJp: String? ) + @Serializable data class KitsuUserAvatar( - @JsonProperty("original") val original: String? + @SerialName("original") val original: String? ) + @Serializable data class KitsuLinks( /* Pagination */ - @JsonProperty("first") val first: String?, - @JsonProperty("next") val next: String?, - @JsonProperty("last") val last: String?, + @SerialName("first") val first: String?, + @SerialName("next") val next: String?, + @SerialName("last") val last: String?, /* Relationships */ - @JsonProperty("related") val related: String? + @SerialName("related") val related: String? ) + @Serializable data class KitsuResponse( - @JsonProperty("links") val links: KitsuLinks?, - @JsonProperty("data") val data: List, + @SerialName("links") val links: KitsuLinks?, + @SerialName("data") val data: List, /* When requesting related info (User library entry -> anime) */ - @JsonProperty("included") val included: List?, + @SerialName("included") val included: List?, ) @@ -790,8 +803,9 @@ query { val nodes: List? = null ) + @Serializable data class Node( - @JsonProperty("number") + @SerialName("number") val num: Int? = null, val titles: Titles? = null, val description: Description? = null, diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index 5686b8169ae..222ed4331d3 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey import com.lagradost.cloudstream3.R @@ -135,76 +136,83 @@ class MALApi : SyncAPI() { ) } + @Serializable data class MalAnime( - @JsonProperty("id") val id: Int?, - @JsonProperty("title") val title: String?, - @JsonProperty("main_picture") val mainPicture: MainPicture?, - @JsonProperty("alternative_titles") val alternativeTitles: AlternativeTitles?, - @JsonProperty("start_date") val startDate: String?, - @JsonProperty("end_date") val endDate: String?, - @JsonProperty("synopsis") val synopsis: String?, - @JsonProperty("mean") val mean: Double?, - @JsonProperty("rank") val rank: Int?, - @JsonProperty("popularity") val popularity: Int?, - @JsonProperty("num_list_users") val numListUsers: Int?, - @JsonProperty("num_scoring_users") val numScoringUsers: Int?, - @JsonProperty("nsfw") val nsfw: String?, - @JsonProperty("created_at") val createdAt: String?, - @JsonProperty("updated_at") val updatedAt: String?, - @JsonProperty("media_type") val mediaType: String?, - @JsonProperty("status") val status: String?, - @JsonProperty("genres") val genres: ArrayList?, - @JsonProperty("my_list_status") val myListStatus: MyListStatus?, - @JsonProperty("num_episodes") val numEpisodes: Int?, - @JsonProperty("start_season") val startSeason: StartSeason?, - @JsonProperty("broadcast") val broadcast: Broadcast?, - @JsonProperty("source") val source: String?, - @JsonProperty("average_episode_duration") val averageEpisodeDuration: Int?, - @JsonProperty("rating") val rating: String?, - @JsonProperty("pictures") val pictures: ArrayList?, - @JsonProperty("background") val background: String?, - @JsonProperty("related_anime") val relatedAnime: ArrayList?, - @JsonProperty("related_manga") val relatedManga: ArrayList?, - @JsonProperty("recommendations") val recommendations: ArrayList?, - @JsonProperty("studios") val studios: ArrayList?, - @JsonProperty("statistics") val statistics: Statistics?, + @SerialName("id") val id: Int?, + @SerialName("title") val title: String?, + @SerialName("main_picture") val mainPicture: MainPicture?, + @SerialName("alternative_titles") val alternativeTitles: AlternativeTitles?, + @SerialName("start_date") val startDate: String?, + @SerialName("end_date") val endDate: String?, + @SerialName("synopsis") val synopsis: String?, + @SerialName("mean") val mean: Double?, + @SerialName("rank") val rank: Int?, + @SerialName("popularity") val popularity: Int?, + @SerialName("num_list_users") val numListUsers: Int?, + @SerialName("num_scoring_users") val numScoringUsers: Int?, + @SerialName("nsfw") val nsfw: String?, + @SerialName("created_at") val createdAt: String?, + @SerialName("updated_at") val updatedAt: String?, + @SerialName("media_type") val mediaType: String?, + @SerialName("status") val status: String?, + @SerialName("genres") val genres: ArrayList?, + @SerialName("my_list_status") val myListStatus: MyListStatus?, + @SerialName("num_episodes") val numEpisodes: Int?, + @SerialName("start_season") val startSeason: StartSeason?, + @SerialName("broadcast") val broadcast: Broadcast?, + @SerialName("source") val source: String?, + @SerialName("average_episode_duration") val averageEpisodeDuration: Int?, + @SerialName("rating") val rating: String?, + @SerialName("pictures") val pictures: ArrayList?, + @SerialName("background") val background: String?, + @SerialName("related_anime") val relatedAnime: ArrayList?, + @SerialName("related_manga") val relatedManga: ArrayList?, + @SerialName("recommendations") val recommendations: ArrayList?, + @SerialName("studios") val studios: ArrayList?, + @SerialName("statistics") val statistics: Statistics?, ) + @Serializable data class Recommendations( - @JsonProperty("node") val node: Node? = null, - @JsonProperty("num_recommendations") val numRecommendations: Int? = null + @SerialName("node") val node: Node? = null, + @SerialName("num_recommendations") val numRecommendations: Int? = null ) + @Serializable data class Studios( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("name") val name: String? = null + @SerialName("id") val id: Int? = null, + @SerialName("name") val name: String? = null ) + @Serializable data class MyListStatus( - @JsonProperty("status") val status: String? = null, - @JsonProperty("score") val score: Int? = null, - @JsonProperty("num_episodes_watched") val numEpisodesWatched: Int? = null, - @JsonProperty("is_rewatching") val isRewatching: Boolean? = null, - @JsonProperty("updated_at") val updatedAt: String? = null + @SerialName("status") val status: String? = null, + @SerialName("score") val score: Int? = null, + @SerialName("num_episodes_watched") val numEpisodesWatched: Int? = null, + @SerialName("is_rewatching") val isRewatching: Boolean? = null, + @SerialName("updated_at") val updatedAt: String? = null ) + @Serializable data class RelatedAnime( - @JsonProperty("node") val node: Node? = null, - @JsonProperty("relation_type") val relationType: String? = null, - @JsonProperty("relation_type_formatted") val relationTypeFormatted: String? = null + @SerialName("node") val node: Node? = null, + @SerialName("relation_type") val relationType: String? = null, + @SerialName("relation_type_formatted") val relationTypeFormatted: String? = null ) + @Serializable data class Status( - @JsonProperty("watching") val watching: String? = null, - @JsonProperty("completed") val completed: String? = null, - @JsonProperty("on_hold") val onHold: String? = null, - @JsonProperty("dropped") val dropped: String? = null, - @JsonProperty("plan_to_watch") val planToWatch: String? = null + @SerialName("watching") val watching: String? = null, + @SerialName("completed") val completed: String? = null, + @SerialName("on_hold") val onHold: String? = null, + @SerialName("dropped") val dropped: String? = null, + @SerialName("plan_to_watch") val planToWatch: String? = null ) + @Serializable data class Statistics( - @JsonProperty("status") val status: Status? = null, - @JsonProperty("num_list_users") val numListUsers: Int? = null + @SerialName("status") val status: Status? = null, + @SerialName("num_list_users") val numListUsers: Int? = null ) private fun parseDate(string: String?): Long? { @@ -375,53 +383,58 @@ class MALApi : SyncAPI() { private val allTitles = hashMapOf() + @Serializable data class MalList( - @JsonProperty("data") val data: List, - @JsonProperty("paging") val paging: Paging + @SerialName("data") val data: List, + @SerialName("paging") val paging: Paging ) + @Serializable data class MainPicture( - @JsonProperty("medium") val medium: String, - @JsonProperty("large") val large: String + @SerialName("medium") val medium: String, + @SerialName("large") val large: String ) + @Serializable data class Node( - @JsonProperty("id") val id: Int, - @JsonProperty("title") val title: String, - @JsonProperty("main_picture") val mainPicture: MainPicture?, - @JsonProperty("alternative_titles") val alternativeTitles: AlternativeTitles?, - @JsonProperty("media_type") val mediaType: String?, - @JsonProperty("num_episodes") val numEpisodes: Int?, - @JsonProperty("status") val status: String?, - @JsonProperty("start_date") val startDate: String?, - @JsonProperty("end_date") val endDate: String?, - @JsonProperty("average_episode_duration") val averageEpisodeDuration: Int?, - @JsonProperty("synopsis") val synopsis: String?, - @JsonProperty("mean") val mean: Double?, - @JsonProperty("genres") val genres: List?, - @JsonProperty("rank") val rank: Int?, - @JsonProperty("popularity") val popularity: Int?, - @JsonProperty("num_list_users") val numListUsers: Int?, - @JsonProperty("num_favorites") val numFavorites: Int?, - @JsonProperty("num_scoring_users") val numScoringUsers: Int?, - @JsonProperty("start_season") val startSeason: StartSeason?, - @JsonProperty("broadcast") val broadcast: Broadcast?, - @JsonProperty("nsfw") val nsfw: String?, - @JsonProperty("created_at") val createdAt: String?, - @JsonProperty("updated_at") val updatedAt: String? + @SerialName("id") val id: Int, + @SerialName("title") val title: String, + @SerialName("main_picture") val mainPicture: MainPicture?, + @SerialName("alternative_titles") val alternativeTitles: AlternativeTitles?, + @SerialName("media_type") val mediaType: String?, + @SerialName("num_episodes") val numEpisodes: Int?, + @SerialName("status") val status: String?, + @SerialName("start_date") val startDate: String?, + @SerialName("end_date") val endDate: String?, + @SerialName("average_episode_duration") val averageEpisodeDuration: Int?, + @SerialName("synopsis") val synopsis: String?, + @SerialName("mean") val mean: Double?, + @SerialName("genres") val genres: List?, + @SerialName("rank") val rank: Int?, + @SerialName("popularity") val popularity: Int?, + @SerialName("num_list_users") val numListUsers: Int?, + @SerialName("num_favorites") val numFavorites: Int?, + @SerialName("num_scoring_users") val numScoringUsers: Int?, + @SerialName("start_season") val startSeason: StartSeason?, + @SerialName("broadcast") val broadcast: Broadcast?, + @SerialName("nsfw") val nsfw: String?, + @SerialName("created_at") val createdAt: String?, + @SerialName("updated_at") val updatedAt: String? ) + @Serializable data class ListStatus( - @JsonProperty("status") val status: String?, - @JsonProperty("score") val score: Int, - @JsonProperty("num_episodes_watched") val numEpisodesWatched: Int, - @JsonProperty("is_rewatching") val isRewatching: Boolean, - @JsonProperty("updated_at") val updatedAt: String, + @SerialName("status") val status: String?, + @SerialName("score") val score: Int, + @SerialName("num_episodes_watched") val numEpisodesWatched: Int, + @SerialName("is_rewatching") val isRewatching: Boolean, + @SerialName("updated_at") val updatedAt: String, ) + @Serializable data class Data( - @JsonProperty("node") val node: Node, - @JsonProperty("list_status") val listStatus: ListStatus?, + @SerialName("node") val node: Node, + @SerialName("list_status") val listStatus: ListStatus?, ) { fun toLibraryItem(): SyncAPI.LibraryItem { return SyncAPI.LibraryItem( @@ -452,29 +465,34 @@ class MALApi : SyncAPI() { } } + @Serializable data class Paging( - @JsonProperty("next") val next: String? + @SerialName("next") val next: String? ) + @Serializable data class AlternativeTitles( - @JsonProperty("synonyms") val synonyms: List, - @JsonProperty("en") val en: String, - @JsonProperty("ja") val ja: String + @SerialName("synonyms") val synonyms: List, + @SerialName("en") val en: String, + @SerialName("ja") val ja: String ) + @Serializable data class Genres( - @JsonProperty("id") val id: Int, - @JsonProperty("name") val name: String + @SerialName("id") val id: Int, + @SerialName("name") val name: String ) + @Serializable data class StartSeason( - @JsonProperty("year") val year: Int, - @JsonProperty("season") val season: String + @SerialName("year") val year: Int, + @SerialName("season") val season: String ) + @Serializable data class Broadcast( - @JsonProperty("day_of_the_week") val dayOfTheWeek: String?, - @JsonProperty("start_time") val startTime: String? + @SerialName("day_of_the_week") val dayOfTheWeek: String?, + @SerialName("start_time") val startTime: String? ) override suspend fun library(auth : AuthData?): LibraryMetadata? { @@ -596,25 +614,29 @@ class MALApi : SyncAPI() { } + @Serializable data class ResponseToken( - @JsonProperty("token_type") val tokenType: String, - @JsonProperty("expires_in") val expiresIn: Int, - @JsonProperty("access_token") val accessToken: String, - @JsonProperty("refresh_token") val refreshToken: String, + @SerialName("token_type") val tokenType: String, + @SerialName("expires_in") val expiresIn: Int, + @SerialName("access_token") val accessToken: String, + @SerialName("refresh_token") val refreshToken: String, ) + @Serializable data class MalRoot( - @JsonProperty("data") val data: List, + @SerialName("data") val data: List, ) + @Serializable data class MalDatum( - @JsonProperty("node") val node: MalNode, - @JsonProperty("list_status") val listStatus: MalStatus, + @SerialName("node") val node: MalNode, + @SerialName("list_status") val listStatus: MalStatus, ) + @Serializable data class MalNode( - @JsonProperty("id") val id: Int, - @JsonProperty("title") val title: String, + @SerialName("id") val id: Int, + @SerialName("title") val title: String, /* also, but not used main_picture -> @@ -623,42 +645,48 @@ class MALApi : SyncAPI() { */ ) + @Serializable data class MalStatus( - @JsonProperty("status") val status: String, - @JsonProperty("score") val score: Int, - @JsonProperty("num_episodes_watched") val numEpisodesWatched: Int, - @JsonProperty("is_rewatching") val isRewatching: Boolean, - @JsonProperty("updated_at") val updatedAt: String, + @SerialName("status") val status: String, + @SerialName("score") val score: Int, + @SerialName("num_episodes_watched") val numEpisodesWatched: Int, + @SerialName("is_rewatching") val isRewatching: Boolean, + @SerialName("updated_at") val updatedAt: String, ) + @Serializable data class MalUser( - @JsonProperty("id") val id: Int, - @JsonProperty("name") val name: String, - @JsonProperty("location") val location: String, - @JsonProperty("joined_at") val joinedAt: String, - @JsonProperty("picture") val picture: String?, + @SerialName("id") val id: Int, + @SerialName("name") val name: String, + @SerialName("location") val location: String, + @SerialName("joined_at") val joinedAt: String, + @SerialName("picture") val picture: String?, ) + @Serializable data class MalMainPicture( - @JsonProperty("large") val large: String?, - @JsonProperty("medium") val medium: String?, + @SerialName("large") val large: String?, + @SerialName("medium") val medium: String?, ) // Used for getDataAboutId() + @Serializable data class SmallMalAnime( - @JsonProperty("id") val id: Int, - @JsonProperty("title") val title: String?, - @JsonProperty("num_episodes") val numEpisodes: Int, - @JsonProperty("my_list_status") val myListStatus: MalStatus?, - @JsonProperty("main_picture") val mainPicture: MalMainPicture?, + @SerialName("id") val id: Int, + @SerialName("title") val title: String?, + @SerialName("num_episodes") val numEpisodes: Int, + @SerialName("my_list_status") val myListStatus: MalStatus?, + @SerialName("main_picture") val mainPicture: MalMainPicture?, ) + @Serializable data class MalSearchNode( - @JsonProperty("node") val node: Node, + @SerialName("node") val node: Node, ) + @Serializable data class MalSearch( - @JsonProperty("data") val data: List, + @SerialName("data") val data: List, //paging ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt index 4b17fdb2920..0f711cdff4a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/OpenSubtitlesApi.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.syncproviders.providers import android.util.Log -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.R @@ -218,57 +219,64 @@ class OpenSubtitlesApi : SubtitleAPI() { return null } + @Serializable data class OAuthToken( - @JsonProperty("token") var token: String? = null, - @JsonProperty("status") var status: Int? = null + @SerialName("token") var token: String? = null, + @SerialName("status") var status: Int? = null ) + @Serializable data class Results( - @JsonProperty("data") var data: List? = listOf() + @SerialName("data") var data: List? = listOf() ) + @Serializable data class ResultData( - @JsonProperty("id") var id: String? = null, - @JsonProperty("type") var type: String? = null, - @JsonProperty("attributes") var attributes: ResultAttributes? = ResultAttributes() + @SerialName("id") var id: String? = null, + @SerialName("type") var type: String? = null, + @SerialName("attributes") var attributes: ResultAttributes? = ResultAttributes() ) + @Serializable data class ResultAttributes( - @JsonProperty("subtitle_id") var subtitleId: String? = null, - @JsonProperty("language") var language: String? = null, - @JsonProperty("release") var release: String? = null, - @JsonProperty("url") var url: String? = null, - @JsonProperty("files") var files: List? = listOf(), - @JsonProperty("feature_details") var featDetails: ResultFeatureDetails? = ResultFeatureDetails(), - @JsonProperty("hearing_impaired") var hearingImpaired: Boolean? = null, + @SerialName("subtitle_id") var subtitleId: String? = null, + @SerialName("language") var language: String? = null, + @SerialName("release") var release: String? = null, + @SerialName("url") var url: String? = null, + @SerialName("files") var files: List? = listOf(), + @SerialName("feature_details") var featDetails: ResultFeatureDetails? = ResultFeatureDetails(), + @SerialName("hearing_impaired") var hearingImpaired: Boolean? = null, ) + @Serializable data class ResultFiles( - @JsonProperty("file_id") var fileId: Int? = null, - @JsonProperty("file_name") var fileName: String? = null + @SerialName("file_id") var fileId: Int? = null, + @SerialName("file_name") var fileName: String? = null ) + @Serializable data class ResultDownloadLink( - @JsonProperty("link") var link: String? = null, - @JsonProperty("file_name") var fileName: String? = null, - @JsonProperty("requests") var requests: Int? = null, - @JsonProperty("remaining") var remaining: Int? = null, - @JsonProperty("message") var message: String? = null, - @JsonProperty("reset_time") var resetTime: String? = null, - @JsonProperty("reset_time_utc") var resetTimeUtc: String? = null + @SerialName("link") var link: String? = null, + @SerialName("file_name") var fileName: String? = null, + @SerialName("requests") var requests: Int? = null, + @SerialName("remaining") var remaining: Int? = null, + @SerialName("message") var message: String? = null, + @SerialName("reset_time") var resetTime: String? = null, + @SerialName("reset_time_utc") var resetTimeUtc: String? = null ) + @Serializable data class ResultFeatureDetails( - @JsonProperty("year") var year: Int? = null, - @JsonProperty("title") var title: String? = null, - @JsonProperty("movie_name") var movieName: String? = null, - @JsonProperty("imdb_id") var imdbId: Int? = null, - @JsonProperty("tmdb_id") var tmdbId: Int? = null, - @JsonProperty("season_number") var seasonNumber: Int? = null, - @JsonProperty("episode_number") var episodeNumber: Int? = null, - @JsonProperty("parent_imdb_id") var parentImdbId: Int? = null, - @JsonProperty("parent_title") var parentTitle: String? = null, - @JsonProperty("parent_tmdb_id") var parentTmdbId: Int? = null, - @JsonProperty("parent_feature_id") var parentFeatureId: Int? = null + @SerialName("year") var year: Int? = null, + @SerialName("title") var title: String? = null, + @SerialName("movie_name") var movieName: String? = null, + @SerialName("imdb_id") var imdbId: Int? = null, + @SerialName("tmdb_id") var tmdbId: Int? = null, + @SerialName("season_number") var seasonNumber: Int? = null, + @SerialName("episode_number") var episodeNumber: Int? = null, + @SerialName("parent_imdb_id") var parentImdbId: Int? = null, + @SerialName("parent_title") var parentTitle: String? = null, + @SerialName("parent_tmdb_id") var parentTmdbId: Int? = null, + @SerialName("parent_feature_id") var parentFeatureId: Int? = null ) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index c4095e2d881..f87316f177f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -3,7 +3,8 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes import androidx.core.net.toUri import com.fasterxml.jackson.annotation.JsonInclude -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -74,10 +75,11 @@ class SimklApi : SyncAPI() { ThirtyMinutes("30m") } + @Serializable private class SimklCacheWrapper( - @JsonProperty("obj") val obj: T?, - @JsonProperty("validUntil") val validUntil: Long, - @JsonProperty("cacheTime") val cacheTime: Long = unixTime, + @SerialName("obj") val obj: T?, + @SerialName("validUntil") val validUntil: Long, + @SerialName("cacheTime") val cacheTime: Long = unixTime, ) { /** Returns true if cache is newer than cacheDays */ fun isFresh(): Boolean { @@ -209,81 +211,89 @@ class SimklApi : SyncAPI() { } // ------------------- - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable data class TokenRequest( - @JsonProperty("code") val code: String, - @JsonProperty("client_id") val clientId: String = CLIENT_ID, - @JsonProperty("client_secret") val clientSecret: String = CLIENT_SECRET, - @JsonProperty("redirect_uri") val redirectUri: String = "$APP_STRING://simkl", - @JsonProperty("grant_type") val grantType: String = "authorization_code" + @SerialName("code") val code: String, + @SerialName("client_id") val clientId: String = CLIENT_ID, + @SerialName("client_secret") val clientSecret: String = CLIENT_SECRET, + @SerialName("redirect_uri") val redirectUri: String = "$APP_STRING://simkl", + @SerialName("grant_type") val grantType: String = "authorization_code" ) + @Serializable data class TokenResponse( /** No expiration date */ - @JsonProperty("access_token") val accessToken: String, - @JsonProperty("token_type") val tokenType: String, - @JsonProperty("scope") val scope: String + @SerialName("access_token") val accessToken: String, + @SerialName("token_type") val tokenType: String, + @SerialName("scope") val scope: String ) // ------------------- /** https://simkl.docs.apiary.io/#reference/users/settings/receive-settings */ + @Serializable data class SettingsResponse( - @JsonProperty("user") + @SerialName("user") val user: User, - @JsonProperty("account") + @SerialName("account") val account: Account, ) { + @Serializable data class User( - @JsonProperty("name") + @SerialName("name") val name: String, /** Url */ - @JsonProperty("avatar") + @SerialName("avatar") val avatar: String ) + @Serializable data class Account( - @JsonProperty("id") + @SerialName("id") val id: Int, ) } + @Serializable data class PinAuthResponse( - @JsonProperty("result") val result: String, - @JsonProperty("device_code") val deviceCode: String, - @JsonProperty("user_code") val userCode: String, - @JsonProperty("verification_url") val verificationUrl: String, - @JsonProperty("expires_in") val expiresIn: Int, - @JsonProperty("interval") val interval: Int, + @SerialName("result") val result: String, + @SerialName("device_code") val deviceCode: String, + @SerialName("user_code") val userCode: String, + @SerialName("verification_url") val verificationUrl: String, + @SerialName("expires_in") val expiresIn: Int, + @SerialName("interval") val interval: Int, ) + @Serializable data class PinExchangeResponse( - @JsonProperty("result") val result: String, - @JsonProperty("message") val message: String? = null, - @JsonProperty("access_token") val accessToken: String? = null, + @SerialName("result") val result: String, + @SerialName("message") val message: String? = null, + @SerialName("access_token") val accessToken: String? = null, ) // ------------------- + @Serializable data class ActivitiesResponse( - @JsonProperty("all") val all: String?, - @JsonProperty("tv_shows") val tvShows: UpdatedAt, - @JsonProperty("anime") val anime: UpdatedAt, - @JsonProperty("movies") val movies: UpdatedAt, + @SerialName("all") val all: String?, + @SerialName("tv_shows") val tvShows: UpdatedAt, + @SerialName("anime") val anime: UpdatedAt, + @SerialName("movies") val movies: UpdatedAt, ) { + @Serializable data class UpdatedAt( - @JsonProperty("all") val all: String?, - @JsonProperty("removed_from_list") val removedFromList: String?, - @JsonProperty("rated_at") val ratedAt: String?, + @SerialName("all") val all: String?, + @SerialName("removed_from_list") val removedFromList: String?, + @SerialName("rated_at") val ratedAt: String?, ) } /** https://simkl.docs.apiary.io/#reference/tv/episodes/get-tv-show-episodes */ - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable data class EpisodeMetadata( - @JsonProperty("title") val title: String?, - @JsonProperty("description") val description: String?, - @JsonProperty("season") val season: Int?, - @JsonProperty("episode") val episode: Int, - @JsonProperty("img") val img: String? + @SerialName("title") val title: String?, + @SerialName("description") val description: String?, + @SerialName("season") val season: Int?, + @SerialName("episode") val episode: Int, + @SerialName("img") val img: String? ) { companion object { fun convertToEpisodes(list: List?): List? { @@ -306,37 +316,38 @@ class SimklApi : SyncAPI() { * https://simkl.docs.apiary.io/#introduction/about-simkl-api/standard-media-objects * Useful for finding shows from metadata */ - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable open class MediaObject( - @JsonProperty("title") val title: String?, - @JsonProperty("year") val year: Int?, - @JsonProperty("ids") val ids: Ids?, - @JsonProperty("total_episodes") val totalEpisodes: Int? = null, - @JsonProperty("status") val status: String? = null, - @JsonProperty("poster") val poster: String? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("seasons") val seasons: List? = null, - @JsonProperty("episodes") val episodes: List? = null + @SerialName("title") val title: String?, + @SerialName("year") val year: Int?, + @SerialName("ids") val ids: Ids?, + @SerialName("total_episodes") val totalEpisodes: Int? = null, + @SerialName("status") val status: String? = null, + @SerialName("poster") val poster: String? = null, + @SerialName("type") val type: String? = null, + @SerialName("seasons") val seasons: List? = null, + @SerialName("episodes") val episodes: List? = null ) { fun hasEnded(): Boolean { return status == "released" || status == "ended" } - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable data class Season( - @JsonProperty("number") val number: Int, - @JsonProperty("episodes") val episodes: List + @SerialName("number") val number: Int, + @SerialName("episodes") val episodes: List ) { - data class Episode(@JsonProperty("number") val number: Int) + @Serializable + data class Episode(@SerialName("number") val number: Int) } - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable data class Ids( - @JsonProperty("simkl") val simkl: Int?, - @JsonProperty("imdb") val imdb: String? = null, - @JsonProperty("tmdb") val tmdb: String? = null, - @JsonProperty("mal") val mal: String? = null, - @JsonProperty("anilist") val anilist: String? = null, + @SerialName("simkl") val simkl: Int?, + @SerialName("imdb") val imdb: String? = null, + @SerialName("tmdb") val tmdb: String? = null, + @SerialName("mal") val mal: String? = null, + @SerialName("anilist") val anilist: String? = null, ) { companion object { fun fromMap(map: Map): Ids { @@ -556,48 +567,49 @@ class SimklApi : SyncAPI() { } } - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable class HistoryMediaObject( - @JsonProperty("title") title: String? = null, - @JsonProperty("year") year: Int? = null, - @JsonProperty("ids") ids: Ids? = null, - @JsonProperty("seasons") seasons: List? = null, - @JsonProperty("episodes") episodes: List? = null, - @JsonProperty("rating") val rating: Int? = null, - @JsonProperty("rated_at") val ratedAt: String? = null, + @SerialName("title") title: String? = null, + @SerialName("year") year: Int? = null, + @SerialName("ids") ids: Ids? = null, + @SerialName("seasons") seasons: List? = null, + @SerialName("episodes") episodes: List? = null, + @SerialName("rating") val rating: Int? = null, + @SerialName("rated_at") val ratedAt: String? = null, ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes) - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable class RatingMediaObject( - @JsonProperty("title") title: String?, - @JsonProperty("year") year: Int?, - @JsonProperty("ids") ids: Ids?, - @JsonProperty("rating") val rating: Int, - @JsonProperty("rated_at") val ratedAt: String? = getDateTime(unixTime) + @SerialName("title") title: String?, + @SerialName("year") year: Int?, + @SerialName("ids") ids: Ids?, + @SerialName("rating") val rating: Int, + @SerialName("rated_at") val ratedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable class StatusMediaObject( - @JsonProperty("title") title: String?, - @JsonProperty("year") year: Int?, - @JsonProperty("ids") ids: Ids?, - @JsonProperty("to") val to: String, - @JsonProperty("watched_at") val watchedAt: String? = getDateTime(unixTime) + @SerialName("title") title: String?, + @SerialName("year") year: Int?, + @SerialName("ids") ids: Ids?, + @SerialName("to") val to: String, + @SerialName("watched_at") val watchedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) - @JsonInclude(JsonInclude.Include.NON_EMPTY) + @Serializable data class StatusRequest( - @JsonProperty("movies") val movies: List, - @JsonProperty("shows") val shows: List + @SerialName("movies") val movies: List, + @SerialName("shows") val shows: List ) /** https://simkl.docs.apiary.io/#reference/sync/get-all-items/get-all-items-in-the-user's-watchlist */ + @Serializable data class AllItemsResponse( - @JsonProperty("shows") + @SerialName("shows") val shows: List = emptyList(), - @JsonProperty("anime") + @SerialName("anime") val anime: List = emptyList(), - @JsonProperty("movies") + @SerialName("movies") val movies: List = emptyList(), ) { companion object { @@ -648,13 +660,14 @@ class SimklApi : SyncAPI() { fun toLibraryItem(): SyncAPI.LibraryItem } + @Serializable data class MovieMetadata( - @JsonProperty("last_watched_at") override val lastWatchedAt: String?, - @JsonProperty("status") override val status: String, - @JsonProperty("user_rating") override val userRating: Int?, - @JsonProperty("last_watched") override val lastWatched: String?, - @JsonProperty("watched_episodes_count") override val watchedEpisodesCount: Int?, - @JsonProperty("total_episodes_count") override val totalEpisodesCount: Int?, + @SerialName("last_watched_at") override val lastWatchedAt: String?, + @SerialName("status") override val status: String, + @SerialName("user_rating") override val userRating: Int?, + @SerialName("last_watched") override val lastWatched: String?, + @SerialName("watched_episodes_count") override val watchedEpisodesCount: Int?, + @SerialName("total_episodes_count") override val totalEpisodesCount: Int?, val movie: ShowMetadata.Show ) : Metadata { override fun getIds(): ShowMetadata.Show.Ids { @@ -681,14 +694,15 @@ class SimklApi : SyncAPI() { } } + @Serializable data class ShowMetadata( - @JsonProperty("last_watched_at") override val lastWatchedAt: String?, - @JsonProperty("status") override val status: String, - @JsonProperty("user_rating") override val userRating: Int?, - @JsonProperty("last_watched") override val lastWatched: String?, - @JsonProperty("watched_episodes_count") override val watchedEpisodesCount: Int?, - @JsonProperty("total_episodes_count") override val totalEpisodesCount: Int?, - @JsonProperty("show") val show: Show + @SerialName("last_watched_at") override val lastWatchedAt: String?, + @SerialName("status") override val status: String, + @SerialName("user_rating") override val userRating: Int?, + @SerialName("last_watched") override val lastWatched: String?, + @SerialName("watched_episodes_count") override val watchedEpisodesCount: Int?, + @SerialName("total_episodes_count") override val totalEpisodesCount: Int?, + @SerialName("show") val show: Show ) : Metadata { override fun getIds(): Show.Ids { return this.show.ids @@ -713,24 +727,26 @@ class SimklApi : SyncAPI() { ) } + @Serializable data class Show( - @JsonProperty("title") val title: String, - @JsonProperty("poster") val poster: String?, - @JsonProperty("year") val year: Int?, - @JsonProperty("ids") val ids: Ids, + @SerialName("title") val title: String, + @SerialName("poster") val poster: String?, + @SerialName("year") val year: Int?, + @SerialName("ids") val ids: Ids, ) { + @Serializable data class Ids( - @JsonProperty("simkl") val simkl: Int, - @JsonProperty("slug") val slug: String?, - @JsonProperty("imdb") val imdb: String?, - @JsonProperty("zap2it") val zap2it: String?, - @JsonProperty("tmdb") val tmdb: String?, - @JsonProperty("offen") val offen: String?, - @JsonProperty("tvdb") val tvdb: String?, - @JsonProperty("mal") val mal: String?, - @JsonProperty("anidb") val anidb: String?, - @JsonProperty("anilist") val anilist: String?, - @JsonProperty("traktslug") val traktslug: String? + @SerialName("simkl") val simkl: Int, + @SerialName("slug") val slug: String?, + @SerialName("imdb") val imdb: String?, + @SerialName("zap2it") val zap2it: String?, + @SerialName("tmdb") val tmdb: String?, + @SerialName("offen") val offen: String?, + @SerialName("tvdb") val tvdb: String?, + @SerialName("mal") val mal: String?, + @SerialName("anidb") val anidb: String?, + @SerialName("anilist") val anilist: String?, + @SerialName("traktslug") val traktslug: String? ) { fun matchesId(database: SimklSyncServices, id: String): Boolean { return when (database) { diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt index 19122768e23..94ed20edd02 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SubSource.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.syncproviders.providers -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities @@ -115,53 +116,61 @@ class SubSourceApi : SubtitleAPI() { } } + @Serializable data class ApiSearch( - @JsonProperty("success") val success: Boolean, - @JsonProperty("found") val found: List, + @SerialName("success") val success: Boolean, + @SerialName("found") val found: List, ) + @Serializable data class Found( - @JsonProperty("id") val id: Long, - @JsonProperty("title") val title: String, - @JsonProperty("seasons") val seasons: Long, - @JsonProperty("type") val type: String, - @JsonProperty("releaseYear") val releaseYear: Long, - @JsonProperty("linkName") val linkName: String, + @SerialName("id") val id: Long, + @SerialName("title") val title: String, + @SerialName("seasons") val seasons: Long, + @SerialName("type") val type: String, + @SerialName("releaseYear") val releaseYear: Long, + @SerialName("linkName") val linkName: String, ) + @Serializable data class ApiResponse( - @JsonProperty("success") val success: Boolean, - @JsonProperty("movie") val movie: Movie, - @JsonProperty("subs") val subs: List, + @SerialName("success") val success: Boolean, + @SerialName("movie") val movie: Movie, + @SerialName("subs") val subs: List, ) + @Serializable data class Movie( - @JsonProperty("id") val id: Long? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("year") val year: Long? = null, - @JsonProperty("fullName") val fullName: String? = null, + @SerialName("id") val id: Long? = null, + @SerialName("type") val type: String? = null, + @SerialName("year") val year: Long? = null, + @SerialName("fullName") val fullName: String? = null, ) + @Serializable data class Sub( - @JsonProperty("hi") val hi: Int? = null, - @JsonProperty("fullLink") val fullLink: String? = null, - @JsonProperty("linkName") val linkName: String? = null, - @JsonProperty("lang") val lang: String? = null, - @JsonProperty("releaseName") val releaseName: String? = null, - @JsonProperty("subId") val subId: Long? = null, + @SerialName("hi") val hi: Int? = null, + @SerialName("fullLink") val fullLink: String? = null, + @SerialName("linkName") val linkName: String? = null, + @SerialName("lang") val lang: String? = null, + @SerialName("releaseName") val releaseName: String? = null, + @SerialName("subId") val subId: Long? = null, ) + @Serializable data class SubData( - @JsonProperty("movie") val movie: String, - @JsonProperty("lang") val lang: String, - @JsonProperty("id") val id: String, + @SerialName("movie") val movie: String, + @SerialName("lang") val lang: String, + @SerialName("id") val id: String, ) + @Serializable data class SubTitleLink( - @JsonProperty("sub") val sub: SubToken, + @SerialName("sub") val sub: SubToken, ) + @Serializable data class SubToken( - @JsonProperty("downloadToken") val downloadToken: String, + @SerialName("downloadToken") val downloadToken: String, ) } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt index 1f1e6de4450..0e95ebb82bf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.syncproviders.providers -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities @@ -122,69 +123,77 @@ class SubDlApi : SubtitleAPI() { } } + @Serializable data class SubtitleOAuthEntity( - @JsonProperty("userEmail") var userEmail: String, - @JsonProperty("pass") var pass: String, - @JsonProperty("name") var name: String? = null, - @JsonProperty("accessToken") var accessToken: String? = null, - @JsonProperty("apiKey") var apiKey: String? = null, + @SerialName("userEmail") var userEmail: String, + @SerialName("pass") var pass: String, + @SerialName("name") var name: String? = null, + @SerialName("accessToken") var accessToken: String? = null, + @SerialName("apiKey") var apiKey: String? = null, ) + @Serializable data class OAuthTokenResponse( - @JsonProperty("token") val token: String, - @JsonProperty("userData") val userData: UserData? = null, - @JsonProperty("status") val status: Boolean? = null, - @JsonProperty("message") val message: String? = null, + @SerialName("token") val token: String, + @SerialName("userData") val userData: UserData? = null, + @SerialName("status") val status: Boolean? = null, + @SerialName("message") val message: String? = null, ) + @Serializable data class UserData( - @JsonProperty("email") val email: String, - @JsonProperty("name") val name: String, - @JsonProperty("country") val country: String, - @JsonProperty("scStepCode") val scStepCode: String, - @JsonProperty("scVerified") val scVerified: Boolean, - @JsonProperty("username") val username: String? = null, - @JsonProperty("scUsername") val scUsername: String, + @SerialName("email") val email: String, + @SerialName("name") val name: String, + @SerialName("country") val country: String, + @SerialName("scStepCode") val scStepCode: String, + @SerialName("scVerified") val scVerified: Boolean, + @SerialName("username") val username: String? = null, + @SerialName("scUsername") val scUsername: String, ) + @Serializable data class ApiKeyResponse( - @JsonProperty("ok") val ok: Boolean? = false, - @JsonProperty("api_key") val apiKey: String, - @JsonProperty("usage") val usage: Usage? = null, + @SerialName("ok") val ok: Boolean? = false, + @SerialName("api_key") val apiKey: String, + @SerialName("usage") val usage: Usage? = null, ) + @Serializable data class Usage( - @JsonProperty("total") val total: Long? = 0, - @JsonProperty("today") val today: Long? = 0, + @SerialName("total") val total: Long? = 0, + @SerialName("today") val today: Long? = 0, ) + @Serializable data class ApiResponse( - @JsonProperty("status") val status: Boolean? = null, - @JsonProperty("results") val results: List? = null, - @JsonProperty("subtitles") val subtitles: List? = null, + @SerialName("status") val status: Boolean? = null, + @SerialName("results") val results: List? = null, + @SerialName("subtitles") val subtitles: List? = null, ) + @Serializable data class Result( - @JsonProperty("sd_id") val sdId: Int? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("imdb_id") val imdbId: String? = null, - @JsonProperty("tmdb_id") val tmdbId: Long? = null, - @JsonProperty("first_air_date") val firstAirDate: String? = null, - @JsonProperty("year") val year: Int? = null, + @SerialName("sd_id") val sdId: Int? = null, + @SerialName("type") val type: String? = null, + @SerialName("name") val name: String? = null, + @SerialName("imdb_id") val imdbId: String? = null, + @SerialName("tmdb_id") val tmdbId: Long? = null, + @SerialName("first_air_date") val firstAirDate: String? = null, + @SerialName("year") val year: Int? = null, ) + @Serializable data class Subtitle( - @JsonProperty("release_name") val releaseName: String, - @JsonProperty("name") val name: String, - @JsonProperty("lang") val lang: String, // subdl language code - @JsonProperty("author") val author: String? = null, - @JsonProperty("url") val url: String? = null, - @JsonProperty("subtitlePage") val subtitlePage: String? = null, - @JsonProperty("season") val season: Int? = null, - @JsonProperty("episode") val episode: Int? = null, - @JsonProperty("language") val language: String? = null, // full language name - @JsonProperty("hi") val hearingImpaired: Boolean? = null, + @SerialName("release_name") val releaseName: String, + @SerialName("name") val name: String, + @SerialName("lang") val lang: String, // subdl language code + @SerialName("author") val author: String? = null, + @SerialName("url") val url: String? = null, + @SerialName("subtitlePage") val subtitlePage: String? = null, + @SerialName("season") val season: Int? = null, + @SerialName("episode") val episode: Int? = null, + @SerialName("language") val language: String? = null, // full language name + @SerialName("hi") val hearingImpaired: Boolean? = null, ) // https://subdl.com/api-files/language_list.json diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt index 1c24ca7e4f6..75de64418eb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.ui.player -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.api.Log import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.ErrorLoadingException @@ -278,93 +279,95 @@ object Torrent { // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/torrents.go#L18 // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/main/web/api/route.go#L7 + @Serializable data class TorrentRequest( - @JsonProperty("action") + @SerialName("action") val action: String, - @JsonProperty("hash") + @SerialName("hash") val hash: String = "", - @JsonProperty("link") + @SerialName("link") val link: String = "", - @JsonProperty("title") + @SerialName("title") val title: String = "", - @JsonProperty("poster") + @SerialName("poster") val poster: String = "", - @JsonProperty("data") + @SerialName("data") val data: String = "", - @JsonProperty("save_to_db") + @SerialName("save_to_db") val saveToDB: Boolean = false, ) // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/torr/state/state.go#L33 // omitempty = nullable + @Serializable data class TorrentStatus( - @JsonProperty("title") + @SerialName("title") var title: String, - @JsonProperty("poster") + @SerialName("poster") var poster: String, - @JsonProperty("data") + @SerialName("data") var data: String?, - @JsonProperty("timestamp") + @SerialName("timestamp") var timestamp: Long, - @JsonProperty("name") + @SerialName("name") var name: String?, - @JsonProperty("hash") + @SerialName("hash") var hash: String?, - @JsonProperty("stat") + @SerialName("stat") var stat: Int, - @JsonProperty("stat_string") + @SerialName("stat_string") var statString: String, - @JsonProperty("loaded_size") + @SerialName("loaded_size") var loadedSize: Long?, - @JsonProperty("torrent_size") + @SerialName("torrent_size") var torrentSize: Long?, - @JsonProperty("preloaded_bytes") + @SerialName("preloaded_bytes") var preloadedBytes: Long?, - @JsonProperty("preload_size") + @SerialName("preload_size") var preloadSize: Long?, - @JsonProperty("download_speed") + @SerialName("download_speed") var downloadSpeed: Double?, - @JsonProperty("upload_speed") + @SerialName("upload_speed") var uploadSpeed: Double?, - @JsonProperty("total_peers") + @SerialName("total_peers") var totalPeers: Int?, - @JsonProperty("pending_peers") + @SerialName("pending_peers") var pendingPeers: Int?, - @JsonProperty("active_peers") + @SerialName("active_peers") var activePeers: Int?, - @JsonProperty("connected_seeders") + @SerialName("connected_seeders") var connectedSeeders: Int?, - @JsonProperty("half_open_peers") + @SerialName("half_open_peers") var halfOpenPeers: Int?, - @JsonProperty("bytes_written") + @SerialName("bytes_written") var bytesWritten: Long?, - @JsonProperty("bytes_written_data") + @SerialName("bytes_written_data") var bytesWrittenData: Long?, - @JsonProperty("bytes_read") + @SerialName("bytes_read") var bytesRead: Long?, - @JsonProperty("bytes_read_data") + @SerialName("bytes_read_data") var bytesReadData: Long?, - @JsonProperty("bytes_read_useful_data") + @SerialName("bytes_read_useful_data") var bytesReadUsefulData: Long?, - @JsonProperty("chunks_written") + @SerialName("chunks_written") var chunksWritten: Long?, - @JsonProperty("chunks_read") + @SerialName("chunks_read") var chunksRead: Long?, - @JsonProperty("chunks_read_useful") + @SerialName("chunks_read_useful") var chunksReadUseful: Long?, - @JsonProperty("chunks_read_wasted") + @SerialName("chunks_read_wasted") var chunksReadWasted: Long?, - @JsonProperty("pieces_dirtied_good") + @SerialName("pieces_dirtied_good") var piecesDirtiedGood: Long?, - @JsonProperty("pieces_dirtied_bad") + @SerialName("pieces_dirtied_bad") var piecesDirtiedBad: Long?, - @JsonProperty("duration_seconds") + @SerialName("duration_seconds") var durationSeconds: Double?, - @JsonProperty("bit_rate") + @SerialName("bit_rate") var bitRate: String?, - @JsonProperty("file_stats") + @SerialName("file_stats") var fileStats: List?, - @JsonProperty("trackers") + @SerialName("trackers") var trackers: List?, ) { fun streamUrl(url: String): String { @@ -381,12 +384,13 @@ object Torrent { } } + @Serializable data class TorrentFileStat( - @JsonProperty("id") + @SerialName("id") val id: Int?, - @JsonProperty("path") + @SerialName("path") val path: String?, - @JsonProperty("length") + @SerialName("length") val length: Long?, ) } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHistoryAdaptor.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHistoryAdaptor.kt index 4868abb3d08..6f994765a63 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHistoryAdaptor.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchHistoryAdaptor.kt @@ -3,7 +3,8 @@ package com.lagradost.cloudstream3.ui.search import android.view.LayoutInflater import android.view.ViewGroup import androidx.core.view.isGone -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.databinding.SearchHistoryFooterBinding import com.lagradost.cloudstream3.databinding.SearchHistoryItemBinding @@ -14,11 +15,12 @@ import com.lagradost.cloudstream3.ui.settings.Globals.EMULATOR import com.lagradost.cloudstream3.ui.settings.Globals.TV import com.lagradost.cloudstream3.ui.settings.Globals.isLayout +@Serializable data class SearchHistoryItem( - @JsonProperty("searchedAt") val searchedAt: Long, - @JsonProperty("searchText") val searchText: String, - @JsonProperty("type") val type: List, - @JsonProperty("key") val key: String, + @SerialName("searchedAt") val searchedAt: Long, + @SerialName("searchText") val searchText: String, + @SerialName("type") val type: List, + @SerialName("key") val key: String, ) data class SearchHistoryCallback( diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchSuggestionApi.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchSuggestionApi.kt index 382b7918406..dca0dceb57d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchSuggestionApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/search/SearchSuggestionApi.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.ui.search -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.nicehttp.NiceResponse @@ -13,16 +14,18 @@ object SearchSuggestionApi { private const val TMDB_API_URL = "https://api.themoviedb.org/3/search/multi" private const val TMDB_API_KEY = "e6333b32409e02a4a6eba6fb7ff866bb" + @Serializable data class TmdbSearchResult( - @JsonProperty("results") val results: List? + @SerialName("results") val results: List? ) + @Serializable data class TmdbSearchItem( - @JsonProperty("media_type") val mediaType: String?, - @JsonProperty("title") val title: String?, - @JsonProperty("name") val name: String?, - @JsonProperty("original_title") val originalTitle: String?, - @JsonProperty("original_name") val originalName: String? + @SerialName("media_type") val mediaType: String?, + @SerialName("title") val title: String?, + @SerialName("name") val name: String?, + @SerialName("original_title") val originalTitle: String?, + @SerialName("original_name") val originalName: String? ) /** diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt index dbf2ff1dc53..19932f55876 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsGeneral.kt @@ -10,7 +10,8 @@ import androidx.core.content.edit import androidx.core.os.ConfigurationCompat import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder.allProviders import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -145,14 +146,15 @@ class SettingsGeneral : BasePreferenceFragmentCompat() { setToolBarScrollFlags() } + @Serializable data class CustomSite( - @JsonProperty("parentJavaClass") // javaClass.simpleName + @SerialName("parentJavaClass") // javaClass.simpleName val parentJavaClass: String, - @JsonProperty("name") + @SerialName("name") val name: String, - @JsonProperty("url") + @SerialName("url") val url: String, - @JsonProperty("lang") + @SerialName("lang") val lang: String, ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt index 482251b7831..97147194cbf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/extensions/ExtensionsViewModel.kt @@ -3,7 +3,8 @@ package com.lagradost.cloudstream3.ui.settings.extensions import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.amap @@ -16,10 +17,11 @@ import com.lagradost.cloudstream3.utils.UiText import com.lagradost.cloudstream3.utils.txt import com.lagradost.cloudstream3.utils.Coroutines.ioSafe +@Serializable data class RepositoryData( - @JsonProperty("iconUrl") val iconUrl: String?, - @JsonProperty("name") val name: String, - @JsonProperty("url") val url: String + @SerialName("iconUrl") val iconUrl: String?, + @SerialName("name") val name: String, + @SerialName("url") val url: String ){ constructor(name: String,url: String):this(null,name,url) } diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt index f9b1cb1fe88..30583b0cc14 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/ChromecastSubtitlesFragment.kt @@ -13,7 +13,8 @@ import android.widget.Toast import androidx.annotation.OptIn import androidx.media3.common.text.Cue import androidx.media3.common.util.UnstableApi -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_DEPRESSED import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_DROP_SHADOW import com.google.android.gms.cast.TextTrackStyle.EDGE_TYPE_NONE @@ -41,15 +42,16 @@ import com.lagradost.cloudstream3.utils.UIHelper.popCurrentPage const val CHROME_SUBTITLE_KEY = "chome_subtitle_settings" +@Serializable data class SaveChromeCaptionStyle( - @JsonProperty("fontFamily") var fontFamily: String? = null, - @JsonProperty("fontGenericFamily") var fontGenericFamily: Int? = null, - @JsonProperty("backgroundColor") var backgroundColor: Int = 0x00FFFFFF, // transparent - @JsonProperty("edgeColor") var edgeColor: Int = Color.BLACK, // BLACK - @JsonProperty("edgeType") var edgeType: Int = EDGE_TYPE_OUTLINE, - @JsonProperty("foregroundColor") var foregroundColor: Int = Color.WHITE, - @JsonProperty("fontScale") var fontScale: Float = 1.05f, - @JsonProperty("windowColor") var windowColor: Int = Color.TRANSPARENT, + @SerialName("fontFamily") var fontFamily: String? = null, + @SerialName("fontGenericFamily") var fontGenericFamily: Int? = null, + @SerialName("backgroundColor") var backgroundColor: Int = 0x00FFFFFF, // transparent + @SerialName("edgeColor") var edgeColor: Int = Color.BLACK, // BLACK + @SerialName("edgeType") var edgeType: Int = EDGE_TYPE_OUTLINE, + @SerialName("foregroundColor") var foregroundColor: Int = Color.WHITE, + @SerialName("fontScale") var fontScale: Float = 1.05f, + @SerialName("windowColor") var windowColor: Int = Color.TRANSPARENT, ) class ChromecastSubtitlesFragment : BaseFragment( diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt index 5f716cca3f1..a165baeacd1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/subtitles/SubtitlesFragment.kt @@ -25,7 +25,8 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.ui.CaptionStyleCompat import androidx.media3.ui.SubtitleView import androidx.preference.PreferenceManager -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.jaredrummler.android.colorpicker.ColorPickerDialog import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKey @@ -60,34 +61,35 @@ const val SUBTITLE_KEY = "subtitle_settings" const val SUBTITLE_AUTO_SELECT_KEY = "subs_auto_select" const val SUBTITLE_DOWNLOAD_KEY = "subs_auto_download" +@Serializable data class SaveCaptionStyle( - @JsonProperty("foregroundColor") var foregroundColor: Int, - @JsonProperty("backgroundColor") var backgroundColor: Int, - @JsonProperty("windowColor") var windowColor: Int, + @SerialName("foregroundColor") var foregroundColor: Int, + @SerialName("backgroundColor") var backgroundColor: Int, + @SerialName("windowColor") var windowColor: Int, @OptIn(UnstableApi::class) - @JsonProperty("edgeType") var edgeType: @CaptionStyleCompat.EdgeType Int, - @JsonProperty("edgeColor") var edgeColor: Int, + @SerialName("edgeType") var edgeType: @CaptionStyleCompat.EdgeType Int, + @SerialName("edgeColor") var edgeColor: Int, @FontRes - @JsonProperty("typeface") var typeface: Int?, - @JsonProperty("typefaceFilePath") var typefaceFilePath: String?, + @SerialName("typeface") var typeface: Int?, + @SerialName("typefaceFilePath") var typefaceFilePath: String?, /**in dp**/ - @JsonProperty("elevation") var elevation: Int, + @SerialName("elevation") var elevation: Int, /**in sp**/ - @JsonProperty("fixedTextSize") var fixedTextSize: Float?, + @SerialName("fixedTextSize") var fixedTextSize: Float?, @Px - @JsonProperty("edgeSize") var edgeSize: Float? = null, - @JsonProperty("removeCaptions") var removeCaptions: Boolean = false, - @JsonProperty("removeBloat") var removeBloat: Boolean = true, + @SerialName("edgeSize") var edgeSize: Float? = null, + @SerialName("removeCaptions") var removeCaptions: Boolean = false, + @SerialName("removeBloat") var removeBloat: Boolean = true, /** Apply caps lock to the text **/ - @JsonProperty("upperCase") var upperCase: Boolean = false, + @SerialName("upperCase") var upperCase: Boolean = false, /** Apply bold to the text **/ - @JsonProperty("bold") var bold: Boolean = false, + @SerialName("bold") var bold: Boolean = false, /** Apply italic to the text **/ - @JsonProperty("italic") var italic: Boolean = false, + @SerialName("italic") var italic: Boolean = false, /** in px, background radius, aka how round the background (backgroundColor) on each row is **/ - @JsonProperty("backgroundRadius") var backgroundRadius: Float? = null, + @SerialName("backgroundRadius") var backgroundRadius: Float? = null, /** The SSA_ALIGNMENT */ - @JsonProperty("alignment") var alignment: Int? = null, + @SerialName("alignment") var alignment: Int? = null, ) const val DEF_SUBS_ELEVATION = 20 diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index 88cb7481c9a..2c59c5d9647 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -9,7 +9,8 @@ import androidx.annotation.WorkerThread import androidx.core.net.toUri import androidx.fragment.app.FragmentActivity import androidx.preference.PreferenceManager -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.showToast @@ -118,18 +119,20 @@ object BackupUtils { private var restoreFileSelector: ActivityResultLauncher>? = null // Kinda hack, but I couldn't think of a better way + @Serializable data class BackupVars( - @JsonProperty("_Bool") val bool: Map?, - @JsonProperty("_Int") val int: Map?, - @JsonProperty("_String") val string: Map?, - @JsonProperty("_Float") val float: Map?, - @JsonProperty("_Long") val long: Map?, - @JsonProperty("_StringSet") val stringSet: Map?>?, + @SerialName("_Bool") val bool: Map?, + @SerialName("_Int") val int: Map?, + @SerialName("_String") val string: Map?, + @SerialName("_Float") val float: Map?, + @SerialName("_Long") val long: Map?, + @SerialName("_StringSet") val stringSet: Map?>?, ) + @Serializable data class BackupFile( - @JsonProperty("datastore") val datastore: BackupVars, - @JsonProperty("settings") val settings: BackupVars + @SerialName("datastore") val datastore: BackupVars, + @SerialName("settings") val settings: BackupVars ) @Suppress("UNCHECKED_CAST") diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index 19caead21ee..480576628a2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.utils import android.content.Context -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -148,16 +149,17 @@ object DataStoreHelper { _resultsSortingMode = value.ordinal } + @Serializable data class Account( - @JsonProperty("keyIndex") + @SerialName("keyIndex") val keyIndex: Int, - @JsonProperty("name") + @SerialName("name") val name: String, - @JsonProperty("customImage") + @SerialName("customImage") val customImage: String? = null, - @JsonProperty("defaultImageIndex") + @SerialName("defaultImageIndex") val defaultImageIndex: Int, - @JsonProperty("lockPin") + @SerialName("lockPin") val lockPin: String? = null, ) { val image @@ -232,9 +234,10 @@ object DataStoreHelper { } } + @Serializable data class PosDur( - @JsonProperty("position") val position: Long, - @JsonProperty("duration") val duration: Long + @SerialName("position") val position: Long, + @SerialName("duration") val duration: Long ) fun PosDur.fixVisual(): PosDur { @@ -252,23 +255,24 @@ object DataStoreHelper { /** * Used to display notifications on new episodes and posters in library. **/ + @Serializable abstract class LibrarySearchResponse( - @JsonProperty("id") override var id: Int?, - @JsonProperty("latestUpdatedTime") open val latestUpdatedTime: Long, - @JsonProperty("name") override val name: String, - @JsonProperty("url") override val url: String, - @JsonProperty("apiName") override val apiName: String, - @JsonProperty("type") override var type: TvType?, - @JsonProperty("posterUrl") override var posterUrl: String?, - @JsonProperty("year") open val year: Int?, - @JsonProperty("syncData") open val syncData: Map?, - @JsonProperty("quality") override var quality: SearchQuality?, - @JsonProperty("posterHeaders") override var posterHeaders: Map?, - @JsonProperty("plot") open val plot: String? = null, - @JsonProperty("score") override var score: Score? = null, - @JsonProperty("tags") open val tags: List? = null, + @SerialName("id") override var id: Int?, + @SerialName("latestUpdatedTime") open val latestUpdatedTime: Long, + @SerialName("name") override val name: String, + @SerialName("url") override val url: String, + @SerialName("apiName") override val apiName: String, + @SerialName("type") override var type: TvType?, + @SerialName("posterUrl") override var posterUrl: String?, + @SerialName("year") open val year: Int?, + @SerialName("syncData") open val syncData: Map?, + @SerialName("quality") override var quality: SearchQuality?, + @SerialName("posterHeaders") override var posterHeaders: Map?, + @SerialName("plot") open val plot: String? = null, + @SerialName("score") override var score: Score? = null, + @SerialName("tags") open val tags: List? = null, ) : SearchResponse { - @JsonProperty("rating", access = JsonProperty.Access.WRITE_ONLY) + @SerialName("rating") @Deprecated( "`rating` is the old scoring system, use score instead", replaceWith = ReplaceWith("score"), @@ -283,9 +287,10 @@ object DataStoreHelper { } } + @Serializable data class SubscribedData( - @JsonProperty("subscribedTime") val subscribedTime: Long, - @JsonProperty("lastSeenEpisodeCount") val lastSeenEpisodeCount: Map, + @SerialName("subscribedTime") val subscribedTime: Long, + @SerialName("lastSeenEpisodeCount") val lastSeenEpisodeCount: Map, override var id: Int?, override val latestUpdatedTime: Long, override val name: String, @@ -339,8 +344,9 @@ object DataStoreHelper { } } + @Serializable data class BookmarkedData( - @JsonProperty("bookmarkedTime") val bookmarkedTime: Long, + @SerialName("bookmarkedTime") val bookmarkedTime: Long, override var id: Int?, override val latestUpdatedTime: Long, override val name: String, @@ -392,8 +398,9 @@ object DataStoreHelper { } } + @Serializable data class FavoritesData( - @JsonProperty("favoritesTime") val favoritesTime: Long, + @SerialName("favoritesTime") val favoritesTime: Long, override var id: Int?, override val latestUpdatedTime: Long, override val name: String, @@ -445,21 +452,22 @@ object DataStoreHelper { } } + @Serializable data class ResumeWatchingResult( - @JsonProperty("name") override val name: String, - @JsonProperty("url") override val url: String, - @JsonProperty("apiName") override val apiName: String, - @JsonProperty("type") override var type: TvType? = null, - @JsonProperty("posterUrl") override var posterUrl: String?, - @JsonProperty("watchPos") val watchPos: PosDur?, - @JsonProperty("id") override var id: Int?, - @JsonProperty("parentId") val parentId: Int?, - @JsonProperty("episode") val episode: Int?, - @JsonProperty("season") val season: Int?, - @JsonProperty("isFromDownload") val isFromDownload: Boolean, - @JsonProperty("quality") override var quality: SearchQuality? = null, - @JsonProperty("posterHeaders") override var posterHeaders: Map? = null, - @JsonProperty("score") override var score: Score? = null, + @SerialName("name") override val name: String, + @SerialName("url") override val url: String, + @SerialName("apiName") override val apiName: String, + @SerialName("type") override var type: TvType? = null, + @SerialName("posterUrl") override var posterUrl: String?, + @SerialName("watchPos") val watchPos: PosDur?, + @SerialName("id") override var id: Int?, + @SerialName("parentId") val parentId: Int?, + @SerialName("episode") val episode: Int?, + @SerialName("season") val season: Int?, + @SerialName("isFromDownload") val isFromDownload: Boolean, + @SerialName("quality") override var quality: SearchQuality? = null, + @SerialName("posterHeaders") override var posterHeaders: Map? = null, + @SerialName("score") override var score: Score? = null, ) : SearchResponse /** diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/FillerEpisodeCheck.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/FillerEpisodeCheck.kt index 8456094d1e9..ed006e65da6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/FillerEpisodeCheck.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/FillerEpisodeCheck.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.utils import androidx.annotation.WorkerThread -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse.Companion.getAniListId import com.lagradost.cloudstream3.LoadResponse.Companion.getImdbId @@ -25,65 +26,69 @@ object FillerEpisodeCheck { return q + "cache" + z } + @Serializable data class Show( - @JsonProperty("slug") + @SerialName("slug") val slug: String, - @JsonProperty("title") + @SerialName("title") val title: String, - @JsonProperty("filler") + @SerialName("filler") val filler: ArrayList, - @JsonProperty("mixedCanon") + @SerialName("mixedCanon") val mixedCanon: ArrayList, - @JsonProperty("mangaCanon") + @SerialName("mangaCanon") val mangaCanon: ArrayList, - @JsonProperty("animeCanon") + @SerialName("animeCanon") val animeCanon: ArrayList, ) + @Serializable data class MappingRoot( - @JsonProperty("type") + @SerialName("type") val type: String?, - @JsonProperty("anidb_id") + @SerialName("anidb_id") val anidbId: Long?, - @JsonProperty("anilist_id") + @SerialName("anilist_id") val anilistId: Long?, - @JsonProperty("animecountdown_id") + @SerialName("animecountdown_id") val animecountdownId: Long?, - @JsonProperty("animenewsnetwork_id") + @SerialName("animenewsnetwork_id") val animenewsnetworkId: Long?, - @JsonProperty("anime-planet_id") + @SerialName("anime-planet_id") val animePlanetId: String?, - @JsonProperty("anisearch_id") + @SerialName("anisearch_id") val anisearchId: Long?, - @JsonProperty("imdb_id") + @SerialName("imdb_id") val imdbId: String?, - @JsonProperty("kitsu_id") + @SerialName("kitsu_id") val kitsuId: Long?, - @JsonProperty("livechart_id") + @SerialName("livechart_id") val livechartId: Long?, - @JsonProperty("mal_id") + @SerialName("mal_id") val malId: Long?, - @JsonProperty("simkl_id") + @SerialName("simkl_id") val simklId: Long?, - @JsonProperty("themoviedb_id") + @SerialName("themoviedb_id") val themoviedbId: Long?, - @JsonProperty("tvdb_id") + @SerialName("tvdb_id") val tvdbId: Long?, - @JsonProperty("season") + @SerialName("season") val season: Season?, ) + @Serializable data class Season( - @JsonProperty("tvdb") + @SerialName("tvdb") val tvdb: Long?, - @JsonProperty("tmdb") + @SerialName("tmdb") val tmdb: Long?, ) + @Serializable data class CombinedMedia( - @JsonProperty("mapping") + @SerialName("mapping") val mapping: MappingRoot?, - @JsonProperty("show") + @SerialName("show") val show: Show ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt index 681693be652..bd962052177 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/InAppUpdater.kt @@ -12,7 +12,8 @@ import androidx.core.content.ContextCompat import androidx.core.content.FileProvider import androidx.core.content.edit import androidx.preference.PreferenceManager -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.MainActivity.Companion.deleteFileOnExit @@ -42,38 +43,43 @@ object InAppUpdater { private const val PRERELEASE_PACKAGE_NAME = "com.lagradost.cloudstream3.prerelease" private const val LOG_TAG = "InAppUpdater" + @Serializable private data class GithubAsset( - @JsonProperty("name") val name: String, - @JsonProperty("size") val size: Int, // Size in bytes - @JsonProperty("browser_download_url") val browserDownloadUrl: String, - @JsonProperty("content_type") val contentType: String, // application/vnd.android.package-archive + @SerialName("name") val name: String, + @SerialName("size") val size: Int, // Size in bytes + @SerialName("browser_download_url") val browserDownloadUrl: String, + @SerialName("content_type") val contentType: String, // application/vnd.android.package-archive ) + @Serializable private data class GithubRelease( - @JsonProperty("tag_name") val tagName: String, // Version code - @JsonProperty("body") val body: String, // Description - @JsonProperty("assets") val assets: List, - @JsonProperty("target_commitish") val targetCommitish: String, // Branch - @JsonProperty("prerelease") val prerelease: Boolean, - @JsonProperty("node_id") val nodeId: String, + @SerialName("tag_name") val tagName: String, // Version code + @SerialName("body") val body: String, // Description + @SerialName("assets") val assets: List, + @SerialName("target_commitish") val targetCommitish: String, // Branch + @SerialName("prerelease") val prerelease: Boolean, + @SerialName("node_id") val nodeId: String, ) + @Serializable private data class GithubObject( - @JsonProperty("sha") val sha: String, // SHA-256 hash - @JsonProperty("type") val type: String, - @JsonProperty("url") val url: String, + @SerialName("sha") val sha: String, // SHA-256 hash + @SerialName("type") val type: String, + @SerialName("url") val url: String, ) + @Serializable private data class GithubTag( - @JsonProperty("object") val githubObject: GithubObject, + @SerialName("object") val githubObject: GithubObject, ) + @Serializable private data class Update( - @JsonProperty("shouldUpdate") val shouldUpdate: Boolean, - @JsonProperty("updateURL") val updateURL: String?, - @JsonProperty("updateVersion") val updateVersion: String?, - @JsonProperty("changelog") val changelog: String?, - @JsonProperty("updateNodeId") val updateNodeId: String?, + @SerialName("shouldUpdate") val shouldUpdate: Boolean, + @SerialName("updateURL") val updateURL: String?, + @SerialName("updateVersion") val updateVersion: String?, + @SerialName("changelog") val changelog: String?, + @SerialName("updateNodeId") val updateNodeId: String?, ) private suspend fun Activity.getAppUpdate(installPrerelease: Boolean): Update { diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt index 5054443d231..2124e408a97 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt @@ -3,7 +3,8 @@ package com.lagradost.cloudstream3.utils // TODO: FIX import android.util.Log -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder.apis //import com.lagradost.cloudstream3.animeproviders.AniflixProvider import com.lagradost.cloudstream3.app @@ -105,68 +106,74 @@ object SyncUtil { return current } + @Serializable data class SyncPage( - @JsonProperty("Pages") val pages: SyncPages?, + @SerialName("Pages") val pages: SyncPages?, ) + @Serializable data class SyncPages( - @JsonProperty("9anime") val nineanime: Map = emptyMap(), - @JsonProperty("Gogoanime") val gogoanime: Map = emptyMap(), - @JsonProperty("Twistmoe") val twistmoe: Map = emptyMap(), + @SerialName("9anime") val nineanime: Map = emptyMap(), + @SerialName("Gogoanime") val gogoanime: Map = emptyMap(), + @SerialName("Twistmoe") val twistmoe: Map = emptyMap(), ) + @Serializable data class ProviderPage( - @JsonProperty("url") val url: String?, + @SerialName("url") val url: String?, ) + @Serializable data class MalSyncPage( - @JsonProperty("identifier") val identifier: String?, - @JsonProperty("type") val type: String?, - @JsonProperty("page") val page: String?, - @JsonProperty("title") val title: String?, - @JsonProperty("url") val url: String?, - @JsonProperty("image") val image: String?, - @JsonProperty("hentai") val hentai: Boolean?, - @JsonProperty("sticky") val sticky: Boolean?, - @JsonProperty("active") val active: Boolean?, - @JsonProperty("actor") val actor: String?, - @JsonProperty("malId") val malId: Int?, - @JsonProperty("aniId") val aniId: Int?, - @JsonProperty("createdAt") val createdAt: String?, - @JsonProperty("updatedAt") val updatedAt: String?, - @JsonProperty("deletedAt") val deletedAt: String?, - @JsonProperty("Mal") val mal: Mal?, - @JsonProperty("Anilist") val anilist: Anilist?, - @JsonProperty("malUrl") val malUrl: String? + @SerialName("identifier") val identifier: String?, + @SerialName("type") val type: String?, + @SerialName("page") val page: String?, + @SerialName("title") val title: String?, + @SerialName("url") val url: String?, + @SerialName("image") val image: String?, + @SerialName("hentai") val hentai: Boolean?, + @SerialName("sticky") val sticky: Boolean?, + @SerialName("active") val active: Boolean?, + @SerialName("actor") val actor: String?, + @SerialName("malId") val malId: Int?, + @SerialName("aniId") val aniId: Int?, + @SerialName("createdAt") val createdAt: String?, + @SerialName("updatedAt") val updatedAt: String?, + @SerialName("deletedAt") val deletedAt: String?, + @SerialName("Mal") val mal: Mal?, + @SerialName("Anilist") val anilist: Anilist?, + @SerialName("malUrl") val malUrl: String? ) + @Serializable data class Anilist( -// @JsonProperty("altTitle") val altTitle: List?, -// @JsonProperty("externalLinks") val externalLinks: List?, - @JsonProperty("id") val id: Int?, - @JsonProperty("malId") val malId: Int?, - @JsonProperty("type") val type: String?, - @JsonProperty("title") val title: String?, - @JsonProperty("url") val url: String?, - @JsonProperty("image") val image: String?, - @JsonProperty("category") val category: String?, - @JsonProperty("hentai") val hentai: Boolean?, - @JsonProperty("createdAt") val createdAt: String?, - @JsonProperty("updatedAt") val updatedAt: String?, - @JsonProperty("deletedAt") val deletedAt: String? +// @SerialName("altTitle") val altTitle: List?, +// @SerialName("externalLinks") val externalLinks: List?, + @SerialName("id") val id: Int?, + @SerialName("malId") val malId: Int?, + @SerialName("type") val type: String?, + @SerialName("title") val title: String?, + @SerialName("url") val url: String?, + @SerialName("image") val image: String?, + @SerialName("category") val category: String?, + @SerialName("hentai") val hentai: Boolean?, + @SerialName("createdAt") val createdAt: String?, + @SerialName("updatedAt") val updatedAt: String?, + @SerialName("deletedAt") val deletedAt: String? ) + @Serializable data class Mal( -// @JsonProperty("altTitle") val altTitle: List?, - @JsonProperty("id") val id: Int?, - @JsonProperty("type") val type: String?, - @JsonProperty("title") val title: String?, - @JsonProperty("url") val url: String?, - @JsonProperty("image") val image: String?, - @JsonProperty("category") val category: String?, - @JsonProperty("hentai") val hentai: Boolean?, - @JsonProperty("createdAt") val createdAt: String?, - @JsonProperty("updatedAt") val updatedAt: String?, - @JsonProperty("deletedAt") val deletedAt: String? +// @SerialName("altTitle") val altTitle: List?, + @SerialName("id") val id: Int?, + @SerialName("type") val type: String?, + @SerialName("title") val title: String?, + @SerialName("url") val url: String?, + @SerialName("image") val image: String?, + @SerialName("category") val category: String?, + @SerialName("hentai") val hentai: Boolean?, + @SerialName("createdAt") val createdAt: String?, + @SerialName("updatedAt") val updatedAt: String?, + @SerialName("deletedAt") val deletedAt: String? ) } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt index 25a9fdf2a4f..2940c284027 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.utils.downloader import android.net.Uri -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.Score import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.services.DownloadQueueService @@ -15,9 +16,10 @@ import java.util.Objects object DownloadObjects { /** An item can either be something to resume or something new to start */ + @Serializable data class DownloadQueueWrapper( - @JsonProperty("resumePackage") val resumePackage: DownloadResumePackage?, - @JsonProperty("downloadItem") val downloadItem: DownloadQueueItem?, + @SerialName("resumePackage") val resumePackage: DownloadResumePackage?, + @SerialName("downloadItem") val downloadItem: DownloadQueueItem?, ) { init { assert(resumePackage != null || downloadItem != null) { @@ -30,25 +32,26 @@ object DownloadObjects { return DownloadQueueService.downloadInstances.value.any { it.downloadQueueWrapper.id == this.id } } - @JsonProperty("id") + @SerialName("id") val id = resumePackage?.item?.ep?.id ?: downloadItem!!.episode.id - @JsonProperty("parentId") + @SerialName("parentId") val parentId = resumePackage?.item?.ep?.parentId ?: downloadItem!!.episode.parentId } /** General data about the episode and show to start a download from. */ + @Serializable data class DownloadQueueItem( - @JsonProperty("episode") val episode: ResultEpisode, - @JsonProperty("isMovie") val isMovie: Boolean, - @JsonProperty("resultName") val resultName: String, - @JsonProperty("resultType") val resultType: TvType, - @JsonProperty("resultPoster") val resultPoster: String?, - @JsonProperty("apiName") val apiName: String, - @JsonProperty("resultId") val resultId: Int, - @JsonProperty("resultUrl") val resultUrl: String, - @JsonProperty("links") val links: List? = null, - @JsonProperty("subs") val subs: List? = null, + @SerialName("episode") val episode: ResultEpisode, + @SerialName("isMovie") val isMovie: Boolean, + @SerialName("resultName") val resultName: String, + @SerialName("resultType") val resultType: TvType, + @SerialName("resultPoster") val resultPoster: String?, + @SerialName("apiName") val apiName: String, + @SerialName("resultId") val resultId: Int, + @SerialName("resultUrl") val resultUrl: String, + @SerialName("links") val links: List? = null, + @SerialName("subs") val subs: List? = null, ) { fun toWrapper(): DownloadQueueWrapper { return DownloadQueueWrapper(null, this) @@ -56,22 +59,24 @@ object DownloadObjects { } + @Serializable abstract class DownloadCached( - @JsonProperty("id") open val id: Int, + @SerialName("id") open val id: Int, ) + @Serializable data class DownloadEpisodeCached( - @JsonProperty("name") val name: String?, - @JsonProperty("poster") val poster: String?, - @JsonProperty("episode") val episode: Int, - @JsonProperty("season") val season: Int?, - @JsonProperty("parentId") val parentId: Int, - @JsonProperty("score") var score: Score? = null, - @JsonProperty("description") val description: String?, - @JsonProperty("cacheTime") val cacheTime: Long, + @SerialName("name") val name: String?, + @SerialName("poster") val poster: String?, + @SerialName("episode") val episode: Int, + @SerialName("season") val season: Int?, + @SerialName("parentId") val parentId: Int, + @SerialName("score") var score: Score? = null, + @SerialName("description") val description: String?, + @SerialName("cacheTime") val cacheTime: Long, override val id: Int, ) : DownloadCached(id) { - @JsonProperty("rating", access = JsonProperty.Access.WRITE_ONLY) + @SerialName("rating") @Deprecated( "`rating` is the old scoring system, use score instead", replaceWith = ReplaceWith("score"), @@ -87,71 +92,78 @@ object DownloadObjects { } /** What to display to the user for a downloaded show/movie. Includes info such as name, poster and url */ + @Serializable data class DownloadHeaderCached( - @JsonProperty("apiName") val apiName: String, - @JsonProperty("url") val url: String, - @JsonProperty("type") val type: TvType, - @JsonProperty("name") val name: String, - @JsonProperty("poster") val poster: String?, - @JsonProperty("cacheTime") val cacheTime: Long, + @SerialName("apiName") val apiName: String, + @SerialName("url") val url: String, + @SerialName("type") val type: TvType, + @SerialName("name") val name: String, + @SerialName("poster") val poster: String?, + @SerialName("cacheTime") val cacheTime: Long, override val id: Int, ) : DownloadCached(id) + @Serializable data class DownloadResumePackage( - @JsonProperty("item") val item: DownloadItem, + @SerialName("item") val item: DownloadItem, /** Tills which link should get resumed */ - @JsonProperty("linkIndex") val linkIndex: Int?, + @SerialName("linkIndex") val linkIndex: Int?, ) { fun toWrapper(): DownloadQueueWrapper { return DownloadQueueWrapper(this, null) } } + @Serializable data class DownloadItem( - @JsonProperty("source") val source: String?, - @JsonProperty("folder") val folder: String?, - @JsonProperty("ep") val ep: DownloadEpisodeMetadata, - @JsonProperty("links") val links: List, + @SerialName("source") val source: String?, + @SerialName("folder") val folder: String?, + @SerialName("ep") val ep: DownloadEpisodeMetadata, + @SerialName("links") val links: List, ) /** Metadata for a specific episode and how to display it. */ + @Serializable data class DownloadEpisodeMetadata( - @JsonProperty("id") val id: Int, - @JsonProperty("parentId") val parentId: Int, - @JsonProperty("mainName") val mainName: String, - @JsonProperty("sourceApiName") val sourceApiName: String?, - @JsonProperty("poster") val poster: String?, - @JsonProperty("name") val name: String?, - @JsonProperty("season") val season: Int?, - @JsonProperty("episode") val episode: Int?, - @JsonProperty("type") val type: TvType?, + @SerialName("id") val id: Int, + @SerialName("parentId") val parentId: Int, + @SerialName("mainName") val mainName: String, + @SerialName("sourceApiName") val sourceApiName: String?, + @SerialName("poster") val poster: String?, + @SerialName("name") val name: String?, + @SerialName("season") val season: Int?, + @SerialName("episode") val episode: Int?, + @SerialName("type") val type: TvType?, ) + @Serializable data class DownloadedFileInfo( - @JsonProperty("totalBytes") val totalBytes: Long, - @JsonProperty("relativePath") val relativePath: String, - @JsonProperty("displayName") val displayName: String, - @JsonProperty("extraInfo") val extraInfo: String? = null, - @JsonProperty("basePath") val basePath: String? = null, // null is for legacy downloads. See getBasePath() + @SerialName("totalBytes") val totalBytes: Long, + @SerialName("relativePath") val relativePath: String, + @SerialName("displayName") val displayName: String, + @SerialName("extraInfo") val extraInfo: String? = null, + @SerialName("basePath") val basePath: String? = null, // null is for legacy downloads. See getBasePath() // Hash of the link associated with this DownloadFile, used so not override old data in the DownloadedFileInfo - @JsonProperty("linkHash") val linkHash : Int? = null + @SerialName("linkHash") val linkHash : Int? = null ) + @Serializable data class DownloadedFileInfoResult( - @JsonProperty("fileLength") val fileLength: Long, - @JsonProperty("totalBytes") val totalBytes: Long, - @JsonProperty("path") val path: Uri, + @SerialName("fileLength") val fileLength: Long, + @SerialName("totalBytes") val totalBytes: Long, + @SerialName("path") val path: Uri, ) + @Serializable data class ResumeWatching( - @JsonProperty("parentId") val parentId: Int, - @JsonProperty("episodeId") val episodeId: Int?, - @JsonProperty("episode") val episode: Int?, - @JsonProperty("season") val season: Int?, - @JsonProperty("updateTime") val updateTime: Long, - @JsonProperty("isFromDownload") val isFromDownload: Boolean, + @SerialName("parentId") val parentId: Int, + @SerialName("episodeId") val episodeId: Int?, + @SerialName("episode") val episode: Int?, + @SerialName("season") val season: Int?, + @SerialName("updateTime") val updateTime: Long, + @SerialName("isFromDownload") val isFromDownload: Boolean, ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt index 0db90afeaef..4e1559fb388 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt @@ -47,22 +47,25 @@ class AniSkip : SkipAPI() { } } + @Serializable data class AniSkipResponse( - @JsonSerialize val found: Boolean, - @JsonSerialize val results: List?, - @JsonSerialize val message: String?, - @JsonSerialize val statusCode: Int + val found: Boolean, + val results: List?, + val message: String?, + val statusCode: Int ) + @Serializable data class Stamp( - @JsonSerialize val interval: AniSkipInterval, - @JsonSerialize val skipType: String, - @JsonSerialize val skipId: String, - @JsonSerialize val episodeLength: Double + val interval: AniSkipInterval, + val skipType: String, + val skipId: String, + val episodeLength: Double ) + @Serializable data class AniSkipInterval( - @JsonSerialize val startTime: Double, - @JsonSerialize val endTime: Double + val startTime: Double, + val endTime: Double ) } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AnimeSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AnimeSkip.kt index f9254576bb5..1764aefff2e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AnimeSkip.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AnimeSkip.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.utils.videoskip -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.AnimeLoadResponse import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.LoadResponse @@ -34,57 +35,65 @@ class AnimeSkipAuth : AuthAPI() { return BigInteger(1, md.digest(input.toByteArray())).toString(16).padStart(32, '0') } + @Serializable data class LoginRoot( - @JsonProperty("data") + @SerialName("data") val data: LoginData, ) + @Serializable data class LoginData( - @JsonProperty("login") + @SerialName("login") val login: Login, ) + @Serializable data class Login( - @JsonProperty("authToken") + @SerialName("authToken") val authToken: String, - @JsonProperty("refreshToken") + @SerialName("refreshToken") val refreshToken: String, - @JsonProperty("account") + @SerialName("account") val account: Account, ) + @Serializable data class ApiRoot( - @JsonProperty("data") + @SerialName("data") val data: ApiData, ) + @Serializable data class ApiData( - @JsonProperty("myApiClients") + @SerialName("myApiClients") val myApiClients: List, ) + @Serializable data class MyApiClient( - @JsonProperty("id") + @SerialName("id") val id: String, ) + @Serializable data class Account( - @JsonProperty("profileUrl") + @SerialName("profileUrl") val profileUrl: String, - @JsonProperty("username") + @SerialName("username") val username: String, - @JsonProperty("email") + @SerialName("email") val email: String, ) + @Serializable data class Payload( - @JsonProperty("profileUrl") + @SerialName("profileUrl") val profileUrl: String, - @JsonProperty("username") + @SerialName("username") val username: String, - @JsonProperty("email") + @SerialName("email") val email: String, - @JsonProperty("clientId") + @SerialName("clientId") val clientId: String, ) @@ -187,51 +196,57 @@ class AnimeSkip : SkipAPI() { name?.replace(asciiRegex, "")?.lowercase() } + @Serializable data class Root( - @JsonProperty("data") + @SerialName("data") val data: Data, ) + @Serializable data class Data( - @JsonProperty("searchShows") + @SerialName("searchShows") val searchShows: List, ) + @Serializable data class SearchShow( - @JsonProperty("name") + @SerialName("name") val name: String, - @JsonProperty("originalName") + @SerialName("originalName") val originalName: String?, - @JsonProperty("seasonCount") + @SerialName("seasonCount") val seasonCount: Long, - @JsonProperty("episodeCount") + @SerialName("episodeCount") val episodeCount: Long, - @JsonProperty("baseDuration") + @SerialName("baseDuration") val baseDuration: Double, - @JsonProperty("episodes") + @SerialName("episodes") val episodes: List, ) + @Serializable data class Episode( - @JsonProperty("number") + @SerialName("number") val number: String?, - @JsonProperty("absoluteNumber") + @SerialName("absoluteNumber") val absoluteNumber: String?, - @JsonProperty("season") + @SerialName("season") val season: String?, - @JsonProperty("timestamps") + @SerialName("timestamps") val timestamps: List, ) + @Serializable data class Timestamp( - @JsonProperty("at") + @SerialName("at") val at: Double, - @JsonProperty("type") + @SerialName("type") val type: Type, ) + @Serializable data class Type( - @JsonProperty("name") + @SerialName("name") val name: String, ) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/IntroDbSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/IntroDbSkip.kt index 869515f4390..334d0510255 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/IntroDbSkip.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/IntroDbSkip.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.utils.videoskip -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse.Companion.getImdbId import com.lagradost.cloudstream3.TvType @@ -56,8 +57,9 @@ class IntroDbSkip : SkipAPI() { } + @Serializable data class IntroDbResponse( - @JsonProperty("imdb_id") val imdbId: String?, + @SerialName("imdb_id") val imdbId: String?, val season: Int?, val episode: Int?, val intro: Segment?, @@ -65,13 +67,14 @@ class IntroDbSkip : SkipAPI() { val outro: Segment?, ) + @Serializable data class Segment( - @JsonProperty("start_sec") val startSec: Double?, - @JsonProperty("end_sec") val endSec: Double?, - @JsonProperty("start_ms") val startMs: Long?, - @JsonProperty("end_ms") val endMs: Long?, + @SerialName("start_sec") val startSec: Double?, + @SerialName("end_sec") val endSec: Double?, + @SerialName("start_ms") val startMs: Long?, + @SerialName("end_ms") val endMs: Long?, val confidence: Double?, - @JsonProperty("submission_count") val submissionCount: Int?, - @JsonProperty("updated_at") val updatedAt: String?, + @SerialName("submission_count") val submissionCount: Int?, + @SerialName("updated_at") val updatedAt: String?, ) } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/TheIntroDBSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/TheIntroDBSkip.kt index cc2661cb096..38a7633acc2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/TheIntroDBSkip.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/TheIntroDBSkip.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.utils.videoskip -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse.Companion.getImdbId import com.lagradost.cloudstream3.LoadResponse.Companion.getTMDbId @@ -52,25 +53,27 @@ class TheIntroDBSkip : SkipAPI() { }.flatten() } + @Serializable data class Root( - @JsonProperty("tmdb_id") + @SerialName("tmdb_id") val tmdbId: Long, - @JsonProperty("type") + @SerialName("type") val type: String, - @JsonProperty("intro") + @SerialName("intro") val intro: List = emptyList(), - @JsonProperty("recap") + @SerialName("recap") val recap: List = emptyList(), - @JsonProperty("credits") + @SerialName("credits") val credits: List = emptyList(), - @JsonProperty("preview") + @SerialName("preview") val preview: List = emptyList(), ) + @Serializable data class Stamp( - @JsonProperty("start_ms") + @SerialName("start_ms") val startMs: Long?, - @JsonProperty("end_ms") + @SerialName("end_ms") val endMs: Long?, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 2d6436f4be0..75a57c4630f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -7,7 +7,8 @@ package com.lagradost.cloudstream3 import com.fasterxml.jackson.annotation.JsonAutoDetect -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.kotlinModule @@ -369,15 +370,17 @@ const val PROVIDER_STATUS_SLOW = 2 const val PROVIDER_STATUS_OK = 1 const val PROVIDER_STATUS_DOWN = 0 +@Serializable data class ProvidersInfoJson( - @JsonProperty("name") var name: String, - @JsonProperty("url") var url: String, - @JsonProperty("credentials") var credentials: String? = null, - @JsonProperty("status") var status: Int, + @SerialName("name") var name: String, + @SerialName("url") var url: String, + @SerialName("credentials") var credentials: String? = null, + @SerialName("status") var status: Int, ) +@Serializable data class SettingsJson( - @JsonProperty("enableAdult") var enableAdult: Boolean = false, + @SerialName("enableAdult") var enableAdult: Boolean = false, ) @@ -840,10 +843,10 @@ enum class DubStatus(val id: Int) { * Internally it stores it as an int up to 10^9 to represent up to 10 significant digits. So think * of this as a decimal class specifically for ratings. * */ -@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) +@Serializable class Score private constructor( /** Decimal between [0, 10^9] representing the min score and max score respectively */ - @JsonProperty("data") + @SerialName("data") private val data: Int, ) { override fun hashCode(): Int = this.data.hashCode() @@ -2695,32 +2698,38 @@ data class Tracker( val cover: String? = null, ) +@Serializable data class AniSearch( - @JsonProperty("data") var data: Data? = Data() + @SerialName("data") var data: Data? = Data() ) { + @Serializable data class Data( - @JsonProperty("Page") var page: Page? = Page() + @SerialName("Page") var page: Page? = Page() ) { + @Serializable data class Page( - @JsonProperty("media") var media: ArrayList = arrayListOf() + @SerialName("media") var media: ArrayList = arrayListOf() ) { + @Serializable data class Media( - @JsonProperty("title") var title: Title? = null, - @JsonProperty("id") var id: Int? = null, - @JsonProperty("idMal") var idMal: Int? = null, - @JsonProperty("seasonYear") var seasonYear: Int? = null, - @JsonProperty("format") var format: String? = null, - @JsonProperty("coverImage") var coverImage: CoverImage? = null, - @JsonProperty("bannerImage") var bannerImage: String? = null, + @SerialName("title") var title: Title? = null, + @SerialName("id") var id: Int? = null, + @SerialName("idMal") var idMal: Int? = null, + @SerialName("seasonYear") var seasonYear: Int? = null, + @SerialName("format") var format: String? = null, + @SerialName("coverImage") var coverImage: CoverImage? = null, + @SerialName("bannerImage") var bannerImage: String? = null, ) { + @Serializable data class CoverImage( - @JsonProperty("extraLarge") var extraLarge: String? = null, - @JsonProperty("large") var large: String? = null, + @SerialName("extraLarge") var extraLarge: String? = null, + @SerialName("large") var large: String? = null, ) + @Serializable data class Title( - @JsonProperty("romaji") var romaji: String? = null, - @JsonProperty("english") var english: String? = null, + @SerialName("romaji") var romaji: String? = null, + @SerialName("english") var english: String? = null, ) { fun isMatchingTitles(title: String?): Boolean { if (title == null) return false diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Blogger.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Blogger.kt index 4fc2ac6c7de..125d74c0c83 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Blogger.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Blogger.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson @@ -39,8 +40,9 @@ open class Blogger : ExtractorApi() { return sources } + @Serializable private data class ResponseSource( - @JsonProperty("play_url") val play_url: String, - @JsonProperty("format_id") val format_id: Int + @SerialName("play_url") val play_url: String, + @SerialName("format_id") val format_id: Int ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt index 38d35da2eda..82b3444c389 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64DecodeArray @@ -129,59 +130,65 @@ open class ByseSX : ExtractorApi() { } } +@Serializable data class DetailsRoot( val id: Long, val code: String, val title: String, - @JsonProperty("poster_url") + @SerialName("poster_url") val posterUrl: String, val description: String, - @JsonProperty("created_at") + @SerialName("created_at") val createdAt: String, - @JsonProperty("owner_private") + @SerialName("owner_private") val ownerPrivate: Boolean, - @JsonProperty("embed_frame_url") + @SerialName("embed_frame_url") val embedFrameUrl: String, ) +@Serializable data class PlaybackRoot( val playback: Playback, ) +@Serializable data class Playback( val algorithm: String, val iv: String, val payload: String, - @JsonProperty("key_parts") + @SerialName("key_parts") val keyParts: List, - @JsonProperty("expires_at") + @SerialName("expires_at") val expiresAt: String, - @JsonProperty("decrypt_keys") + @SerialName("decrypt_keys") val decryptKeys: DecryptKeys, val iv2: String, val payload2: String, ) +@Serializable data class DecryptKeys( - @JsonProperty("edge_1") + @SerialName("edge_1") val edge1: String, - @JsonProperty("edge_2") + @SerialName("edge_2") val edge2: String, - @JsonProperty("legacy_fallback") + @SerialName("legacy_fallback") val legacyFallback: String, ) +@Serializable data class PlaybackDecrypt( val sources: List, ) +@Serializable data class PlaybackDecryptSource( val quality: String, val label: String, - @JsonProperty("mime_type") + @SerialName("mime_type") val mimeType: String, val url: String, - @JsonProperty("bitrate_kbps") + @SerialName("bitrate_kbps") val bitrateKbps: Long, val height: Any?, ) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt index d8029fcbfb2..ef46f749b43 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64Decode @@ -41,14 +42,15 @@ open class GUpload: ExtractorApi() { ) } + @Serializable private data class VideoInfo( - @JsonProperty("videoUrl") val videoUrl: String, - @JsonProperty("posterUrl") val posterUrl: String? = null, - @JsonProperty("videoId") val videoId: String? = null, - @JsonProperty("primaryColor") val primaryColor: String? = null, - @JsonProperty("audioTracks") val audioTracks: List = emptyList(), - @JsonProperty("subtitleTracks") val subtitleTracks: List = emptyList(), - @JsonProperty("vastFallbackList") val vastFallbackList: List = emptyList(), - @JsonProperty("videoOwnerId") val videoOwnerId: Long = 0, + @SerialName("videoUrl") val videoUrl: String, + @SerialName("posterUrl") val posterUrl: String? = null, + @SerialName("videoId") val videoId: String? = null, + @SerialName("primaryColor") val primaryColor: String? = null, + @SerialName("audioTracks") val audioTracks: List = emptyList(), + @SerialName("subtitleTracks") val subtitleTracks: List = emptyList(), + @SerialName("vastFallbackList") val vastFallbackList: List = emptyList(), + @SerialName("videoOwnerId") val videoOwnerId: Long = 0, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gdriveplayer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gdriveplayer.kt index 088f325d082..4f665926a4f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gdriveplayer.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gdriveplayer.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.fleeksoft.ksoup.nodes.Element import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.extractors.helper.AesHelper.cryptoAESHandler @@ -119,10 +120,11 @@ open class Gdriveplayer : ExtractorApi() { } + @Serializable data class Tracks( - @JsonProperty("file") val file: String, - @JsonProperty("kind") val kind: String, - @JsonProperty("label") val label: String + @SerialName("file") val file: String, + @SerialName("kind") val kind: String, + @SerialName("label") val label: String ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gofile.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gofile.kt index 02e27a9bfea..b9a089d10a4 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gofile.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Gofile.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi @@ -74,26 +75,31 @@ open class Gofile : ExtractorApi() { } } + @Serializable data class AccountResponse( - @JsonProperty("data") val data: AccountData? = null + @SerialName("data") val data: AccountData? = null ) + @Serializable data class AccountData( - @JsonProperty("token") val token: String? = null + @SerialName("token") val token: String? = null ) + @Serializable data class GofileResponse( - @JsonProperty("data") val data: GofileData? = null + @SerialName("data") val data: GofileData? = null ) + @Serializable data class GofileData( - @JsonProperty("children") val children: Map? = null + @SerialName("children") val children: Map? = null ) + @Serializable data class GofileFile( - @JsonProperty("type") val type: String? = null, - @JsonProperty("name") val name: String? = null, - @JsonProperty("link") val link: String? = null, - @JsonProperty("size") val size: Long? = 0L + @SerialName("type") val type: String? = null, + @SerialName("name") val name: String? = null, + @SerialName("link") val link: String? = null, + @SerialName("size") val size: Long? = 0L ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDMomPlayerExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDMomPlayerExtractor.kt index bed860a7ed3..26e1cc93ef5 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDMomPlayerExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDMomPlayerExtractor.kt @@ -6,7 +6,8 @@ import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.extractors.helper.AesHelper -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue @@ -61,11 +62,12 @@ open class HDMomPlayer : ExtractorApi() { ) } + @Serializable data class Track( - @JsonProperty("file") val file: String?, - @JsonProperty("label") val label: String?, - @JsonProperty("kind") val kind: String?, - @JsonProperty("language") val language: String?, - @JsonProperty("default") val default: String? + @SerialName("file") val file: String?, + @SerialName("label") val label: String?, + @SerialName("kind") val kind: String?, + @SerialName("language") val language: String?, + @SerialName("default") val default: String? ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDPlayerSystemExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDPlayerSystemExtractor.kt index 9cff2049fac..a88fb9af04f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDPlayerSystemExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/HDPlayerSystemExtractor.kt @@ -5,7 +5,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable open class HDPlayerSystem : ExtractorApi() { override val name = "HDPlayerSystem" @@ -48,10 +49,11 @@ open class HDPlayerSystem : ExtractorApi() { ) } + @Serializable data class SystemResponse( - @JsonProperty("hls") val hls: String, - @JsonProperty("videoImage") val videoImage: String? = null, - @JsonProperty("videoSource") val videoSource: String, - @JsonProperty("securedLink") val securedLink: String + @SerialName("hls") val hls: String, + @SerialName("videoImage") val videoImage: String? = null, + @SerialName("videoSource") val videoSource: String, + @SerialName("securedLink") val securedLink: String ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Jeniusplay.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Jeniusplay.kt index c9a9aadae2f..64404a568bf 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Jeniusplay.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Jeniusplay.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.extractors.helper.JwPlayerHelper @@ -45,9 +46,10 @@ open class Jeniusplay : ExtractorApi() { } } + @Serializable data class ResponseSource( - @JsonProperty("hls") val hls: Boolean, - @JsonProperty("videoSource") val videoSource: String, - @JsonProperty("securedLink") val securedLink: String?, + @SerialName("hls") val hls: Boolean, + @SerialName("videoSource") val videoSource: String, + @SerialName("securedLink") val securedLink: String?, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Linkbox.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Linkbox.kt index bfa94326aae..415f3d92528 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Linkbox.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Linkbox.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi @@ -36,22 +37,26 @@ open class Linkbox : ExtractorApi() { } } + @Serializable data class Resolutions( - @JsonProperty("url") val url: String? = null, - @JsonProperty("resolution") val resolution: String? = null, + @SerialName("url") val url: String? = null, + @SerialName("resolution") val resolution: String? = null, ) + @Serializable data class ItemInfo( - @JsonProperty("resolutionList") val resolutionList: ArrayList? = arrayListOf(), + @SerialName("resolutionList") val resolutionList: ArrayList? = arrayListOf(), ) + @Serializable data class Data( - @JsonProperty("itemInfo") val itemInfo: ItemInfo? = null, - @JsonProperty("itemId") val itemId: String? = null, + @SerialName("itemInfo") val itemInfo: ItemInfo? = null, + @SerialName("itemId") val itemId: String? = null, ) + @Serializable data class Responses( - @JsonProperty("data") val data: Data? = null, + @SerialName("data") val data: Data? = null, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MailRuExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MailRuExtractor.kt index f1fd1288caf..437052a4732 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MailRuExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/MailRuExtractor.kt @@ -5,7 +5,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable open class MailRu : ExtractorApi() { override val name = "MailRu" @@ -40,13 +41,15 @@ open class MailRu : ExtractorApi() { } } + @Serializable data class MailRuData( - @JsonProperty("provider") val provider: String, - @JsonProperty("videos") val videos: List + @SerialName("provider") val provider: String, + @SerialName("videos") val videos: List ) + @Serializable data class MailRuVideoData( - @JsonProperty("url") val url: String, - @JsonProperty("key") val key: String + @SerialName("url") val url: String, + @SerialName("key") val key: String ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OdnoklassnikiExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OdnoklassnikiExtractor.kt index 8f1b8fbc7c4..f6766448c6a 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OdnoklassnikiExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/OdnoklassnikiExtractor.kt @@ -2,7 +2,8 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.USER_AGENT @@ -66,8 +67,9 @@ open class Odnoklassniki : ExtractorApi() { } } + @Serializable data class OkRuVideo( - @JsonProperty("name") val name: String, - @JsonProperty("url") val url: String, + @SerialName("name") val name: String, + @SerialName("url") val url: String, ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PeaceMakerstExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PeaceMakerstExtractor.kt index 4efd20589be..7a10aadbed1 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PeaceMakerstExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PeaceMakerstExtractor.kt @@ -5,7 +5,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable open class PeaceMakerst : ExtractorApi() { override val name = "PeaceMakerst" @@ -60,29 +61,34 @@ open class PeaceMakerst : ExtractorApi() { ) } + @Serializable data class PeaceResponse( - @JsonProperty("videoImage") val videoImage: String?, - @JsonProperty("videoSources") val videoSources: List, - @JsonProperty("sIndex") val sIndex: String, - @JsonProperty("sourceList") val sourceList: Map + @SerialName("videoImage") val videoImage: String?, + @SerialName("videoSources") val videoSources: List, + @SerialName("sIndex") val sIndex: String, + @SerialName("sourceList") val sourceList: Map ) + @Serializable data class VideoSource( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String, - @JsonProperty("type") val type: String + @SerialName("file") val file: String, + @SerialName("label") val label: String, + @SerialName("type") val type: String ) + @Serializable data class Teve2ApiResponse( - @JsonProperty("Media") val media: Teve2Media + @SerialName("Media") val media: Teve2Media ) + @Serializable data class Teve2Media( - @JsonProperty("Link") val link: Teve2Link + @SerialName("Link") val link: Teve2Link ) + @Serializable data class Teve2Link( - @JsonProperty("ServiceUrl") val serviceUrl: String, - @JsonProperty("SecurePath") val securePath: String + @SerialName("ServiceUrl") val serviceUrl: String, + @SerialName("SecurePath") val securePath: String ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PlayLtXyz.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PlayLtXyz.kt index a5ecfb5d83a..8264d8a09a2 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PlayLtXyz.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/PlayLtXyz.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson @@ -11,8 +12,9 @@ open class PlayLtXyz: ExtractorApi() { override val mainUrl: String = "https://play.playlt.xyz" override val requiresReferer = true + @Serializable private data class ResponseData( - @JsonProperty("data") val data: String? = null + @SerialName("data") val data: String? = null ) override suspend fun getUrl(url: String, referer: String?): List { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Rabbitstream.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Rabbitstream.kt index a266fed8e66..3b51a98e5c5 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Rabbitstream.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Rabbitstream.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app @@ -174,27 +175,31 @@ open class Rabbitstream : ExtractorApi() { return String(decryptedData, StandardCharsets.UTF_8) } + @Serializable data class Tracks( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, - @JsonProperty("kind") val kind: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("label") val label: String? = null, + @SerialName("kind") val kind: String? = null, ) + @Serializable data class Sources( - @JsonProperty("file") val file: String? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("label") val label: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("type") val type: String? = null, + @SerialName("label") val label: String? = null, ) + @Serializable data class SourcesResponses( - @JsonProperty("sources") val sources: List? = emptyList(), - @JsonProperty("tracks") val tracks: List? = emptyList(), + @SerialName("sources") val sources: List? = emptyList(), + @SerialName("tracks") val tracks: List? = emptyList(), ) + @Serializable data class SourcesEncrypted( - @JsonProperty("sources") val sources: String? = null, - @JsonProperty("encrypted") val encrypted: Boolean? = null, - @JsonProperty("tracks") val tracks: List? = emptyList(), + @SerialName("sources") val sources: String? = null, + @SerialName("encrypted") val encrypted: Boolean? = null, + @SerialName("tracks") val tracks: List? = emptyList(), ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt index 1ac5a104fe2..42eb8835d34 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/SobreatsesuypExtractor.kt @@ -4,7 +4,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable open class Sobreatsesuyp : ExtractorApi() { override val name = "Sobreatsesuyp" @@ -45,8 +46,9 @@ open class Sobreatsesuyp : ExtractorApi() { } } + @Serializable data class SobreatsesuypVideoData( - @JsonProperty("title") val title: String? = null, - @JsonProperty("file") val file: String? = null + @SerialName("title") val title: String? = null, + @SerialName("file") val file: String? = null ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamEmbed.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamEmbed.kt index 7b2846d6bbf..57d25392047 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamEmbed.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamEmbed.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.AppUtils.parseJson @@ -30,14 +31,15 @@ open class StreamEmbed : ExtractorApi() { ).forEach(callback) } + @Serializable private data class Details( - @JsonProperty("id") val id: String, - @JsonProperty("uid") val uid: String, - @JsonProperty("slug") val slug: String, - @JsonProperty("title") val title: String, - @JsonProperty("quality") val quality: String, - @JsonProperty("type") val type: String, - @JsonProperty("status") val status: String, - @JsonProperty("md5") val md5: String, + @SerialName("id") val id: String, + @SerialName("uid") val uid: String, + @SerialName("slug") val slug: String, + @SerialName("title") val title: String, + @SerialName("quality") val quality: String, + @SerialName("type") val type: String, + @SerialName("status") val status: String, + @SerialName("md5") val md5: String, ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamSB.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamSB.kt index 67cf1f8da9c..6695e7718b7 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamSB.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/StreamSB.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.newSubtitleFile @@ -189,25 +190,28 @@ open class StreamSB : ExtractorApi() { } } + @Serializable data class Subs ( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("label") val label: String? = null, ) + @Serializable data class StreamData ( - @JsonProperty("file") val file: String, - @JsonProperty("cdn_img") val cdnImg: String, - @JsonProperty("hash") val hash: String, - @JsonProperty("subs") val subs: ArrayList? = arrayListOf(), - @JsonProperty("length") val length: String, - @JsonProperty("id") val id: String, - @JsonProperty("title") val title: String, - @JsonProperty("backup") val backup: String, + @SerialName("file") val file: String, + @SerialName("cdn_img") val cdnImg: String, + @SerialName("hash") val hash: String, + @SerialName("subs") val subs: ArrayList? = arrayListOf(), + @SerialName("length") val length: String, + @SerialName("id") val id: String, + @SerialName("title") val title: String, + @SerialName("backup") val backup: String, ) + @Serializable data class Main ( - @JsonProperty("stream_data") val streamData: StreamData, - @JsonProperty("status_code") val statusCode: Int, + @SerialName("stream_data") val streamData: StreamData, + @SerialName("status_code") val statusCode: Int, ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt index da2dd62bef5..6688d288d86 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorLink @@ -26,18 +27,20 @@ open class Slmaxed : ExtractorApi() { val embedRegex = Regex("""/e/([^/]*)""") + @Serializable data class JsonResponse( - @JsonProperty val status: String? = null, - @JsonProperty val message: String? = null, - @JsonProperty val type: String? = null, - @JsonProperty val token: String? = null, - @JsonProperty val result: Map? = null + @SerialName val status: String? = null, + @SerialName val message: String? = null, + @SerialName val type: String? = null, + @SerialName val token: String? = null, + @SerialName val result: Map? = null ) + @Serializable data class Result( - @JsonProperty val label: String? = null, - @JsonProperty val file: String? = null, - @JsonProperty val type: String? = null + @SerialName val label: String? = null, + @SerialName val file: String? = null, + @SerialName val type: String? = null ) override suspend fun getUrl(url: String, referer: String?): List? { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamplay.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamplay.kt index 639eec33584..9ec73ad810b 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamplay.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamplay.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder.getCaptchaToken import com.lagradost.cloudstream3.ErrorLoadingException import com.lagradost.cloudstream3.SubtitleFile @@ -74,9 +75,10 @@ open class Streamplay : ExtractorApi() { } + @Serializable data class Source( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("label") val label: String? = null, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamup.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamup.kt index ea85a005ea0..3844fb8bea2 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamup.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamup.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.newSubtitleFile @@ -52,18 +53,20 @@ open class Streamup() : ExtractorApi() { } } + @Serializable private data class StreamUpFileInfo( val title: String, val thumbnail: String, - @JsonProperty("streaming_url") + @SerialName("streaming_url") val streamingUrl: String, val subtitles: List? ) + @Serializable private data class StreamUpSubtitle( - @JsonProperty("file_path") + @SerialName("file_path") val filePath: String, - @JsonProperty("language") + @SerialName("language") val language: String, ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt index 1345da96cdf..332d9ccca06 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TRsTXExtractor.kt @@ -5,7 +5,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable open class TRsTX : ExtractorApi() { override val name = "TRsTX" @@ -62,8 +63,9 @@ open class TRsTX : ExtractorApi() { } } + @Serializable data class TrstxVideoData( - @JsonProperty("title") val title: String? = null, - @JsonProperty("file") val file: String? = null + @SerialName("title") val title: String? = null, + @SerialName("file") val file: String? = null ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Tantifilm.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Tantifilm.kt index 2ac30d2c69b..c3162ebcf77 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Tantifilm.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Tantifilm.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.AppUtils.parseJson @@ -12,17 +13,19 @@ open class Tantifilm : ExtractorApi() { override var mainUrl = "https://cercafilm.net" override val requiresReferer = false + @Serializable data class TantifilmJsonData ( - @JsonProperty("success") val success : Boolean, - @JsonProperty("data") val data : List, - @JsonProperty("captions")val captions : List, - @JsonProperty("is_vr") val is_vr : Boolean + @SerialName("success") val success : Boolean, + @SerialName("data") val data : List, + @SerialName("captions")val captions : List, + @SerialName("is_vr") val is_vr : Boolean ) + @Serializable data class TantifilmData ( - @JsonProperty("file") val file : String, - @JsonProperty("label") val label : String, - @JsonProperty("type") val type : String + @SerialName("file") val file : String, + @SerialName("label") val label : String, + @SerialName("type") val type : String ) override suspend fun getUrl(url: String, referer: String?): List? { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TauVideoExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TauVideoExtractor.kt index 1c9cce2a834..810e23d86dc 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TauVideoExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/TauVideoExtractor.kt @@ -5,7 +5,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable open class TauVideo : ExtractorApi() { override val name = "TauVideo" @@ -33,12 +34,14 @@ open class TauVideo : ExtractorApi() { } } + @Serializable data class TauVideoUrls( - @JsonProperty("urls") val urls: List + @SerialName("urls") val urls: List ) + @Serializable data class TauVideoData( - @JsonProperty("url") val url: String, - @JsonProperty("label") val label: String, + @SerialName("url") val url: String, + @SerialName("label") val label: String, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Uservideo.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Uservideo.kt index f6c3002813d..247bd099d42 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Uservideo.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Uservideo.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.AppUtils @@ -44,10 +45,11 @@ open class Uservideo : ExtractorApi() { } + @Serializable data class Sources( - @JsonProperty("src") val src: String? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("label") val label: String? = null, + @SerialName("src") val src: String? = null, + @SerialName("type") val type: String? = null, + @SerialName("label") val label: String? = null, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vicloud.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vicloud.kt index 5ff48cce827..734aef98ac8 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vicloud.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vicloud.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.ExtractorApi @@ -41,13 +42,15 @@ open class Vicloud : ExtractorApi() { } + @Serializable private data class Sources( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("label") val label: String? = null, ) + @Serializable private data class Responses( - @JsonProperty("sources") val sources: List? = arrayListOf(), + @SerialName("sources") val sources: List? = arrayListOf(), ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VideoSeyredExtractor.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VideoSeyredExtractor.kt index fdfe23c8243..ec3106e72c8 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VideoSeyredExtractor.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/VideoSeyredExtractor.kt @@ -5,7 +5,8 @@ package com.lagradost.cloudstream3.extractors import com.lagradost.api.Log import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.utils.* -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue @@ -48,24 +49,27 @@ open class VideoSeyred : ExtractorApi() { } } + @Serializable data class VideoSeyredSource( - @JsonProperty("image") val image: String, - @JsonProperty("title") val title: String, - @JsonProperty("sources") val sources: List, - @JsonProperty("tracks") val tracks: List + @SerialName("image") val image: String, + @SerialName("title") val title: String, + @SerialName("sources") val sources: List, + @SerialName("tracks") val tracks: List ) + @Serializable data class VSSource( - @JsonProperty("file") val file: String, - @JsonProperty("type") val type: String, - @JsonProperty("default") val default: String + @SerialName("file") val file: String, + @SerialName("type") val type: String, + @SerialName("default") val default: String ) + @Serializable data class VSTrack( - @JsonProperty("file") val file: String, - @JsonProperty("kind") val kind: String, - @JsonProperty("language") val language: String? = null, - @JsonProperty("label") val label: String? = null, - @JsonProperty("default") val default: String? = null + @SerialName("file") val file: String, + @SerialName("kind") val kind: String, + @SerialName("language") val language: String? = null, + @SerialName("label") val label: String? = null, + @SerialName("default") val default: String? = null ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidoza.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidoza.kt index 2a078034000..f945b6caaed 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidoza.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vidoza.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.api.Log import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app @@ -53,10 +54,11 @@ open class Vidoza: ExtractorApi() { private class VinovoDataList: ArrayList() + @Serializable private data class VinovoVideoData( - @JsonProperty("src") val source: String, - @JsonProperty("type") val type: String?, - @JsonProperty("label") val label: String?, - @JsonProperty("res") val resolution: String?, + @SerialName("src") val source: String, + @SerialName("type") val type: String?, + @SerialName("label") val label: String?, + @SerialName("res") val resolution: String?, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vinovo.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vinovo.kt index f490390990c..51c1f7b08d4 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vinovo.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Vinovo.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app @@ -59,8 +60,9 @@ open class VinovoTo : ExtractorApi() { ) } + @Serializable private data class VinovoFileResp( - @JsonProperty("status") val status: String, - @JsonProperty("token") val token: String, + @SerialName("status") val status: String, + @SerialName("token") val token: String, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/XStreamCdn.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/XStreamCdn.kt index 6e3a8126def..5a2fb036273 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/XStreamCdn.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/XStreamCdn.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.newSubtitleFile @@ -76,28 +77,32 @@ open class XStreamCdn : ExtractorApi() { override val requiresReferer = false open var domainUrl: String = "embedsito.com" + @Serializable private data class ResponseData( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String, + @SerialName("file") val file: String, + @SerialName("label") val label: String, //val type: String // Mp4 ) + @Serializable private data class Player( - @JsonProperty("poster_file") val poster_file: String? = null, + @SerialName("poster_file") val poster_file: String? = null, ) + @Serializable private data class ResponseJson( - @JsonProperty("success") val success: Boolean, - @JsonProperty("player") val player: Player? = null, - @JsonProperty("data") val data: List?, - @JsonProperty("captions") val captions: List?, + @SerialName("success") val success: Boolean, + @SerialName("player") val player: Player? = null, + @SerialName("data") val data: List?, + @SerialName("captions") val captions: List?, ) + @Serializable private data class Captions( - @JsonProperty("id") val id: String, - @JsonProperty("hash") val hash: String, - @JsonProperty("language") val language: String, - @JsonProperty("extension") val extension: String + @SerialName("id") val id: String, + @SerialName("hash") val hash: String, + @SerialName("language") val language: String, + @SerialName("extension") val extension: String ) override fun getExtractorUrl(id: String): String { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/YourUpload.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/YourUpload.kt index cdb6deb46ed..80ab128d3c3 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/YourUpload.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/YourUpload.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorApi @@ -42,8 +43,9 @@ open class YourUpload: ExtractorApi() { return sources } + @Serializable private data class ResponseSource( - @JsonProperty("file") val file: String, + @SerialName("file") val file: String, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt index 9c5ceb8c0b3..66479ab0303 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors.helper -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.base64DecodeArray import com.lagradost.cloudstream3.base64Encode import com.lagradost.cloudstream3.utils.AppUtils @@ -91,10 +92,11 @@ object AesHelper { .toByteArray() } + @Serializable private data class AesData( - @JsonProperty("ct") val ct: String, - @JsonProperty("iv") val iv: String, - @JsonProperty("s") val s: String + @SerialName("ct") val ct: String, + @SerialName("iv") val iv: String, + @SerialName("s") val s: String ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt index ce36843b352..8600571d0ed 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors.helper -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.fleeksoft.ksoup.nodes.Document import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64Decode @@ -145,19 +146,22 @@ object GogoHelper { } } + @Serializable data class GogoSources( - @JsonProperty("source") val source: List?, - @JsonProperty("sourceBk") val sourceBk: List?, + @SerialName("source") val source: List?, + @SerialName("sourceBk") val sourceBk: List?, ) + @Serializable data class GogoSource( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String?, - @JsonProperty("type") val type: String?, - @JsonProperty("default") val default: String? = null + @SerialName("file") val file: String, + @SerialName("label") val label: String?, + @SerialName("type") val type: String?, + @SerialName("default") val default: String? = null ) + @Serializable data class GogoJsonData( - @JsonProperty("data") val data: String? = null + @SerialName("data") val data: String? = null ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt index 43ceb2314cf..f8780ac562b 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.extractors.helper -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.api.Log import com.lagradost.cloudstream3.Prerelease import com.lagradost.cloudstream3.SubtitleFile @@ -141,15 +142,17 @@ object JwPlayerHelper { return this.replace(Regex("\"?$str\"?"), "\"$str\"") } + @Serializable private data class Source( - @JsonProperty("file") val file: String, - @JsonProperty("label") val label: String?, - @JsonProperty("type") val type: String?, + @SerialName("file") val file: String, + @SerialName("label") val label: String?, + @SerialName("type") val type: String?, ) + @Serializable data class Track( - @JsonProperty("file") val file: String? = null, - @JsonProperty("label") val label: String? = null, - @JsonProperty("kind") val kind: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("label") val label: String? = null, + @SerialName("kind") val kind: String? = null, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt index 35aec2b1d46..a9634d80cdf 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/WcoHelper.kt @@ -1,25 +1,28 @@ package com.lagradost.cloudstream3.extractors.helper -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.app class WcoHelper { companion object { private const val BACKUP_KEY_DATA = "github_keys_backup" + @Serializable data class ExternalKeys( - @JsonProperty("wco_key") + @SerialName("wco_key") val wcoKey: String? = null, - @JsonProperty("wco_cipher_key") + @SerialName("wco_cipher_key") val wcocipher: String? = null ) + @Serializable data class NewExternalKeys( - @JsonProperty("cipherKey") + @SerialName("cipherKey") val cipherkey: String? = null, - @JsonProperty("encryptKey") + @SerialName("encryptKey") val encryptKey: String? = null, - @JsonProperty("mainKey") + @SerialName("mainKey") val mainKey: String? = null, ) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/CrossTmdbProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/CrossTmdbProvider.kt index 6fde6efe3b3..c331c1499d0 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/CrossTmdbProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/CrossTmdbProvider.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.metaproviders -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull import com.lagradost.cloudstream3.ErrorLoadingException @@ -35,9 +36,10 @@ class CrossTmdbProvider : TmdbProvider() { //.distinctBy { it.uniqueId } + @Serializable data class CrossMetaData( - @JsonProperty("isSuccess") val isSuccess: Boolean, - @JsonProperty("movies") val movies: List>? = null, + @SerialName("isSuccess") val isSuccess: Boolean, + @SerialName("movies") val movies: List>? = null, ) override suspend fun loadLinks( diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt index 4982a77e2fc..bf8789d9b7b 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.metaproviders -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.api.BuildConfig import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.Actor @@ -218,60 +219,63 @@ abstract class MyDramaListAPI : MainAPI() { class Recommendations : ArrayList() + @Serializable data class MediaSummary( - @JsonProperty("id") val id: Long, - @JsonProperty("title") val title: String, - @JsonProperty("original_title") val originalTitle: String, - @JsonProperty("year") val year: Int? = null, - @JsonProperty("rating") val rating: Double? = null, - @JsonProperty("permalink") val permalink: String? = null, - @JsonProperty("type") val type: String, - @JsonProperty("media_type") val mediaType: String? = null, - @JsonProperty("country") val country: String? = null, - @JsonProperty("language") val language: String? = null, - @JsonProperty("images") val images: Images, + @SerialName("id") val id: Long, + @SerialName("title") val title: String, + @SerialName("original_title") val originalTitle: String, + @SerialName("year") val year: Int? = null, + @SerialName("rating") val rating: Double? = null, + @SerialName("permalink") val permalink: String? = null, + @SerialName("type") val type: String, + @SerialName("media_type") val mediaType: String? = null, + @SerialName("country") val country: String? = null, + @SerialName("language") val language: String? = null, + @SerialName("images") val images: Images, ) + @Serializable data class Images( - @JsonProperty("thumb") val thumb: String? = null, - @JsonProperty("medium") val medium: String? = null, - @JsonProperty("poster") val poster: String? = null, + @SerialName("thumb") val thumb: String? = null, + @SerialName("medium") val medium: String? = null, + @SerialName("poster") val poster: String? = null, ) + @Serializable data class Media( - @JsonProperty("id") val id: Long, - @JsonProperty("slug") val slug: String, - @JsonProperty("title") val title: String, - @JsonProperty("original_title") val originalTitle: String, - @JsonProperty("year") val mediaYear: Int, - @JsonProperty("episodes") val episodes: Long, - @JsonProperty("rating") val mediaRating: Double, - @JsonProperty("permalink") val permalink: String? = null, - @JsonProperty("synopsis") val synopsis: String? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("media_type") val mediaType: String? = null, - @JsonProperty("country") val country: String? = null, - @JsonProperty("language") val language: String? = null, - @JsonProperty("images") val images: Images, - @JsonProperty("alt_titles") val altTitles: List? = null, - @JsonProperty("votes") val votes: Long? = null, - @JsonProperty("aired_start") val airedStart: String? = null, - @JsonProperty("released") val released: String? = null, - @JsonProperty("release_dates_fmt") val releaseDatesFmt: String, - @JsonProperty("genres") val genres: List? = null, - @JsonProperty("trailer") val trailer: Trailer?, - @JsonProperty("watchers") val watchers: Long, - @JsonProperty("ranked") val ranked: Long, - @JsonProperty("popularity") val popularity: Long, - @JsonProperty("runtime") val runtime: Long, - @JsonProperty("reviews_count") val reviewsCount: Long, - @JsonProperty("recs_count") val recsCount: Long, - @JsonProperty("comments_count") val commentsCount: Long, - @JsonProperty("certification") val certification: String, - @JsonProperty("status") val status: String, - @JsonProperty("enable_ads") val enableAds: Boolean, - @JsonProperty("sources") val sources: List, - @JsonProperty("updated_at") val updatedAt: Long, + @SerialName("id") val id: Long, + @SerialName("slug") val slug: String, + @SerialName("title") val title: String, + @SerialName("original_title") val originalTitle: String, + @SerialName("year") val mediaYear: Int, + @SerialName("episodes") val episodes: Long, + @SerialName("rating") val mediaRating: Double, + @SerialName("permalink") val permalink: String? = null, + @SerialName("synopsis") val synopsis: String? = null, + @SerialName("type") val type: String? = null, + @SerialName("media_type") val mediaType: String? = null, + @SerialName("country") val country: String? = null, + @SerialName("language") val language: String? = null, + @SerialName("images") val images: Images, + @SerialName("alt_titles") val altTitles: List? = null, + @SerialName("votes") val votes: Long? = null, + @SerialName("aired_start") val airedStart: String? = null, + @SerialName("released") val released: String? = null, + @SerialName("release_dates_fmt") val releaseDatesFmt: String, + @SerialName("genres") val genres: List? = null, + @SerialName("trailer") val trailer: Trailer?, + @SerialName("watchers") val watchers: Long, + @SerialName("ranked") val ranked: Long, + @SerialName("popularity") val popularity: Long, + @SerialName("runtime") val runtime: Long, + @SerialName("reviews_count") val reviewsCount: Long, + @SerialName("recs_count") val recsCount: Long, + @SerialName("comments_count") val commentsCount: Long, + @SerialName("certification") val certification: String, + @SerialName("status") val status: String, + @SerialName("enable_ads") val enableAds: Boolean, + @SerialName("sources") val sources: List, + @SerialName("updated_at") val updatedAt: Long, ) { suspend fun fetchCredits(): List { val actors = app.get("$API_HOST/titles/$id/credits") { @@ -343,95 +347,108 @@ abstract class MyDramaListAPI : MainAPI() { } } + @Serializable data class Genre( - @JsonProperty("id") val id: Long, - @JsonProperty("name") val name: String, - @JsonProperty("slug") val slug: String, + @SerialName("id") val id: Long, + @SerialName("name") val name: String, + @SerialName("slug") val slug: String, ) + @Serializable data class Tag( - @JsonProperty("id") val id: Long, - @JsonProperty("name") val name: String, - @JsonProperty("slug") val slug: String, + @SerialName("id") val id: Long, + @SerialName("name") val name: String, + @SerialName("slug") val slug: String, ) + @Serializable data class Source( - @JsonProperty("xid") val xid: String, - @JsonProperty("name") val name: String, - @JsonProperty("source") val source: String, - @JsonProperty("source_type") val sourceType: String, - @JsonProperty("link") val link: String, - @JsonProperty("image") val image: String, + @SerialName("xid") val xid: String, + @SerialName("name") val name: String, + @SerialName("source") val source: String, + @SerialName("source_type") val sourceType: String, + @SerialName("link") val link: String, + @SerialName("image") val image: String, ) + @Serializable data class Trailer( - @JsonProperty("id") val id: Long? = null, + @SerialName("id") val id: Long? = null, ) + @Serializable data class Credits( - @JsonProperty("cast") val cast: List, - @JsonProperty("crew") val crew: List, + @SerialName("cast") val cast: List, + @SerialName("crew") val crew: List, ) + @Serializable data class Cast( - @JsonProperty("id") val id: Long, - @JsonProperty("name") val name: String, - @JsonProperty("url") val url: String, - @JsonProperty("slug") val slug: String, - @JsonProperty("images") val images: Images, - @JsonProperty("character_name") val characterName: String, - @JsonProperty("role") val role: String, + @SerialName("id") val id: Long, + @SerialName("name") val name: String, + @SerialName("url") val url: String, + @SerialName("slug") val slug: String, + @SerialName("images") val images: Images, + @SerialName("character_name") val characterName: String, + @SerialName("role") val role: String, ) + @Serializable data class Crew( - @JsonProperty("id") val id: Long, - @JsonProperty("name") val name: String, - @JsonProperty("slug") val slug: String, - @JsonProperty("images") val images: Images, - @JsonProperty("job") val job: String, + @SerialName("id") val id: Long, + @SerialName("name") val name: String, + @SerialName("slug") val slug: String, + @SerialName("images") val images: Images, + @SerialName("job") val job: String, ) class ShowEpisodes : ArrayList() + @Serializable data class ShowEpisodesItem( - @JsonProperty("name") val name: String, - @JsonProperty("release_date") val releaseDate: String, - @JsonProperty("episodes") val episodes: List, - @JsonProperty("timezone") val timezone: String, - @JsonProperty("total") val total: Int, + @SerialName("name") val name: String, + @SerialName("release_date") val releaseDate: String, + @SerialName("episodes") val episodes: List, + @SerialName("timezone") val timezone: String, + @SerialName("total") val total: Int, ) + @Serializable data class ShowEpisode( - @JsonProperty("id") val id: Int, - @JsonProperty("episode_number") val episodeNumber: Int, - @JsonProperty("rating") val rating: Double, - @JsonProperty("votes") val votes: Int, - @JsonProperty("released_at") val releasedAt: String, + @SerialName("id") val id: Int, + @SerialName("episode_number") val episodeNumber: Int, + @SerialName("rating") val rating: Double, + @SerialName("votes") val votes: Int, + @SerialName("released_at") val releasedAt: String, ) + @Serializable data class TrailerRoot( - @JsonProperty("trailer") val trailer: TrailerNode, + @SerialName("trailer") val trailer: TrailerNode, ) + @Serializable data class TrailerNode( - @JsonProperty("trailer") val trailerDetails: TrailerDetails, + @SerialName("trailer") val trailerDetails: TrailerDetails, ) + @Serializable data class TrailerDetails( - @JsonProperty("id") val id: Long, - @JsonProperty("source") val source: String, + @SerialName("id") val id: Long, + @SerialName("source") val source: String, ) + @Serializable data class LinkData( - @JsonProperty("id") val id: Long? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("season") val season: Int? = null, - @JsonProperty("episode") val episode: Int? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("year") val year: Int? = null, - @JsonProperty("orgTitle") val orgTitle: String? = null, - @JsonProperty("lastSeason") val lastSeason: Int? = null, - @JsonProperty("date") val date: String? = null, - @JsonProperty("airedDate") val airedDate: String? = null, + @SerialName("id") val id: Long? = null, + @SerialName("type") val type: String? = null, + @SerialName("season") val season: Int? = null, + @SerialName("episode") val episode: Int? = null, + @SerialName("title") val title: String? = null, + @SerialName("year") val year: Int? = null, + @SerialName("orgTitle") val orgTitle: String? = null, + @SerialName("lastSeason") val lastSeason: Int? = null, + @SerialName("date") val date: String? = null, + @SerialName("airedDate") val airedDate: String? = null, ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt index 89f935da327..77416fe8aa5 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TmdbProvider.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.metaproviders -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.Episode import com.lagradost.cloudstream3.ErrorLoadingException @@ -51,12 +52,13 @@ import java.util.Calendar * episode and season starting from 1 * they are null if movie * */ +@Serializable data class TmdbLink( - @JsonProperty("imdbID") val imdbID: String?, - @JsonProperty("tmdbID") val tmdbID: Int?, - @JsonProperty("episode") val episode: Int?, - @JsonProperty("season") val season: Int?, - @JsonProperty("movieName") val movieName: String? = null, + @SerialName("imdbID") val imdbID: String?, + @SerialName("tmdbID") val tmdbID: Int?, + @SerialName("episode") val episode: Int?, + @SerialName("season") val season: Int?, + @SerialName("movieName") val movieName: String? = null, ) open class TmdbProvider : MainAPI() { diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt index 63f6d564c4b..93162197f2a 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -1,7 +1,8 @@ package com.lagradost.cloudstream3.metaproviders -import com.fasterxml.jackson.annotation.JsonAlias -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonNames import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.ActorData @@ -321,138 +322,148 @@ open class TraktProvider : MainAPI() { val mediaDetails: MediaDetails? = null, ) + @Serializable data class MediaDetails( - @JsonProperty("title") val title: String? = null, - @JsonProperty("year") val year: Int? = null, - @JsonProperty("ids") val ids: Ids? = null, - @JsonProperty("tagline") val tagline: String? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("released") val released: String? = null, - @JsonProperty("runtime") val runtime: Int? = null, - @JsonProperty("country") val country: String? = null, - @JsonProperty("updatedAt") val updatedAt: String? = null, - @JsonProperty("trailer") val trailer: String? = null, - @JsonProperty("homepage") val homepage: String? = null, - @JsonProperty("status") val status: String? = null, - @JsonProperty("rating") val rating: Double? = null, - @JsonProperty("votes") val votes: Long? = null, - @JsonProperty("comment_count") val commentCount: Long? = null, - @JsonProperty("language") val language: String? = null, - @JsonProperty("languages") val languages: List? = null, - @JsonProperty("available_translations") val availableTranslations: List? = null, - @JsonProperty("genres") val genres: List? = null, - @JsonProperty("certification") val certification: String? = null, - @JsonProperty("aired_episodes") val airedEpisodes: Int? = null, - @JsonProperty("first_aired") val firstAired: String? = null, - @JsonProperty("airs") val airs: Airs? = null, - @JsonProperty("network") val network: String? = null, - @JsonProperty("images") val images: Images? = null, - @JsonProperty("movie") @JsonAlias("show") val media: MediaDetails? = null + @SerialName("title") val title: String? = null, + @SerialName("year") val year: Int? = null, + @SerialName("ids") val ids: Ids? = null, + @SerialName("tagline") val tagline: String? = null, + @SerialName("overview") val overview: String? = null, + @SerialName("released") val released: String? = null, + @SerialName("runtime") val runtime: Int? = null, + @SerialName("country") val country: String? = null, + @SerialName("updatedAt") val updatedAt: String? = null, + @SerialName("trailer") val trailer: String? = null, + @SerialName("homepage") val homepage: String? = null, + @SerialName("status") val status: String? = null, + @SerialName("rating") val rating: Double? = null, + @SerialName("votes") val votes: Long? = null, + @SerialName("comment_count") val commentCount: Long? = null, + @SerialName("language") val language: String? = null, + @SerialName("languages") val languages: List? = null, + @SerialName("available_translations") val availableTranslations: List? = null, + @SerialName("genres") val genres: List? = null, + @SerialName("certification") val certification: String? = null, + @SerialName("aired_episodes") val airedEpisodes: Int? = null, + @SerialName("first_aired") val firstAired: String? = null, + @SerialName("airs") val airs: Airs? = null, + @SerialName("network") val network: String? = null, + @SerialName("images") val images: Images? = null, + @SerialName("movie") @JsonNames("show") val media: MediaDetails? = null ) + @Serializable data class Airs( - @JsonProperty("day") val day: String? = null, - @JsonProperty("time") val time: String? = null, - @JsonProperty("timezone") val timezone: String? = null, + @SerialName("day") val day: String? = null, + @SerialName("time") val time: String? = null, + @SerialName("timezone") val timezone: String? = null, ) + @Serializable data class Ids( - @JsonProperty("trakt") val trakt: Int? = null, - @JsonProperty("slug") val slug: String? = null, - @JsonProperty("tvdb") val tvdb: Int? = null, - @JsonProperty("imdb") val imdb: String? = null, - @JsonProperty("tmdb") val tmdb: Int? = null, - @JsonProperty("tvrage") val tvrage: String? = null, + @SerialName("trakt") val trakt: Int? = null, + @SerialName("slug") val slug: String? = null, + @SerialName("tvdb") val tvdb: Int? = null, + @SerialName("imdb") val imdb: String? = null, + @SerialName("tmdb") val tmdb: Int? = null, + @SerialName("tvrage") val tvrage: String? = null, ) + @Serializable data class Images( - @JsonProperty("poster") val poster: List? = null, - @JsonProperty("fanart") val fanart: List? = null, - @JsonProperty("logo") val logo: List? = null, - @JsonProperty("clearart") val clearArt: List? = null, - @JsonProperty("banner") val banner: List? = null, - @JsonProperty("thumb") val thumb: List? = null, - @JsonProperty("screenshot") val screenshot: List? = null, - @JsonProperty("headshot") val headshot: List? = null, + @SerialName("poster") val poster: List? = null, + @SerialName("fanart") val fanart: List? = null, + @SerialName("logo") val logo: List? = null, + @SerialName("clearart") val clearArt: List? = null, + @SerialName("banner") val banner: List? = null, + @SerialName("thumb") val thumb: List? = null, + @SerialName("screenshot") val screenshot: List? = null, + @SerialName("headshot") val headshot: List? = null, ) + @Serializable data class People( - @JsonProperty("cast") val cast: List? = null, + @SerialName("cast") val cast: List? = null, ) + @Serializable data class Cast( - @JsonProperty("character") val character: String? = null, - @JsonProperty("characters") val characters: List? = null, - @JsonProperty("episode_count") val episodeCount: Long? = null, - @JsonProperty("person") val person: Person? = null, - @JsonProperty("images") val images: Images? = null, + @SerialName("character") val character: String? = null, + @SerialName("characters") val characters: List? = null, + @SerialName("episode_count") val episodeCount: Long? = null, + @SerialName("person") val person: Person? = null, + @SerialName("images") val images: Images? = null, ) + @Serializable data class Person( - @JsonProperty("name") val name: String? = null, - @JsonProperty("ids") val ids: Ids? = null, - @JsonProperty("images") val images: Images? = null, + @SerialName("name") val name: String? = null, + @SerialName("ids") val ids: Ids? = null, + @SerialName("images") val images: Images? = null, ) + @Serializable data class Seasons( - @JsonProperty("aired_episodes") val airedEpisodes: Int? = null, - @JsonProperty("episode_count") val episodeCount: Int? = null, - @JsonProperty("episodes") val episodes: List? = null, - @JsonProperty("first_aired") val firstAired: String? = null, - @JsonProperty("ids") val ids: Ids? = null, - @JsonProperty("images") val images: Images? = null, - @JsonProperty("network") val network: String? = null, - @JsonProperty("number") val number: Int? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("rating") val rating: Double? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("updated_at") val updatedAt: String? = null, - @JsonProperty("votes") val votes: Int? = null, + @SerialName("aired_episodes") val airedEpisodes: Int? = null, + @SerialName("episode_count") val episodeCount: Int? = null, + @SerialName("episodes") val episodes: List? = null, + @SerialName("first_aired") val firstAired: String? = null, + @SerialName("ids") val ids: Ids? = null, + @SerialName("images") val images: Images? = null, + @SerialName("network") val network: String? = null, + @SerialName("number") val number: Int? = null, + @SerialName("overview") val overview: String? = null, + @SerialName("rating") val rating: Double? = null, + @SerialName("title") val title: String? = null, + @SerialName("updated_at") val updatedAt: String? = null, + @SerialName("votes") val votes: Int? = null, ) + @Serializable data class TraktEpisode( - @JsonProperty("available_translations") val availableTranslations: List? = null, - @JsonProperty("comment_count") val commentCount: Int? = null, - @JsonProperty("episode_type") val episodeType: String? = null, - @JsonProperty("first_aired") val firstAired: String? = null, - @JsonProperty("ids") val ids: Ids? = null, - @JsonProperty("images") val images: Images? = null, - @JsonProperty("number") val number: Int? = null, - @JsonProperty("number_abs") val numberAbs: Int? = null, - @JsonProperty("overview") val overview: String? = null, - @JsonProperty("rating") val rating: Double? = null, - @JsonProperty("runtime") val runtime: Int? = null, - @JsonProperty("season") val season: Int? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("updated_at") val updatedAt: String? = null, - @JsonProperty("votes") val votes: Int? = null, + @SerialName("available_translations") val availableTranslations: List? = null, + @SerialName("comment_count") val commentCount: Int? = null, + @SerialName("episode_type") val episodeType: String? = null, + @SerialName("first_aired") val firstAired: String? = null, + @SerialName("ids") val ids: Ids? = null, + @SerialName("images") val images: Images? = null, + @SerialName("number") val number: Int? = null, + @SerialName("number_abs") val numberAbs: Int? = null, + @SerialName("overview") val overview: String? = null, + @SerialName("rating") val rating: Double? = null, + @SerialName("runtime") val runtime: Int? = null, + @SerialName("season") val season: Int? = null, + @SerialName("title") val title: String? = null, + @SerialName("updated_at") val updatedAt: String? = null, + @SerialName("votes") val votes: Int? = null, ) + @Serializable data class LinkData( - @JsonProperty("id") val id: Int? = null, - @JsonProperty("trakt_id") val traktId: Int? = null, - @JsonProperty("trakt_slug") val traktSlug: String? = null, - @JsonProperty("tmdb_id") val tmdbId: Int? = null, - @JsonProperty("imdb_id") val imdbId: String? = null, - @JsonProperty("tvdb_id") val tvdbId: Int? = null, - @JsonProperty("tvrage_id") val tvrageId: String? = null, - @JsonProperty("type") val type: String? = null, - @JsonProperty("season") val season: Int? = null, - @JsonProperty("episode") val episode: Int? = null, - @JsonProperty("ani_id") val aniId: String? = null, - @JsonProperty("anime_id") val animeId: String? = null, - @JsonProperty("title") val title: String? = null, - @JsonProperty("year") val year: Int? = null, - @JsonProperty("org_title") val orgTitle: String? = null, - @JsonProperty("is_anime") val isAnime: Boolean = false, - @JsonProperty("aired_year") val airedYear: Int? = null, - @JsonProperty("last_season") val lastSeason: Int? = null, - @JsonProperty("eps_title") val epsTitle: String? = null, - @JsonProperty("jp_title") val jpTitle: String? = null, - @JsonProperty("date") val date: String? = null, - @JsonProperty("aired_date") val airedDate: String? = null, - @JsonProperty("is_asian") val isAsian: Boolean = false, - @JsonProperty("is_bollywood") val isBollywood: Boolean = false, - @JsonProperty("is_cartoon") val isCartoon: Boolean = false, + @SerialName("id") val id: Int? = null, + @SerialName("trakt_id") val traktId: Int? = null, + @SerialName("trakt_slug") val traktSlug: String? = null, + @SerialName("tmdb_id") val tmdbId: Int? = null, + @SerialName("imdb_id") val imdbId: String? = null, + @SerialName("tvdb_id") val tvdbId: Int? = null, + @SerialName("tvrage_id") val tvrageId: String? = null, + @SerialName("type") val type: String? = null, + @SerialName("season") val season: Int? = null, + @SerialName("episode") val episode: Int? = null, + @SerialName("ani_id") val aniId: String? = null, + @SerialName("anime_id") val animeId: String? = null, + @SerialName("title") val title: String? = null, + @SerialName("year") val year: Int? = null, + @SerialName("org_title") val orgTitle: String? = null, + @SerialName("is_anime") val isAnime: Boolean = false, + @SerialName("aired_year") val airedYear: Int? = null, + @SerialName("last_season") val lastSeason: Int? = null, + @SerialName("eps_title") val epsTitle: String? = null, + @SerialName("jp_title") val jpTitle: String? = null, + @SerialName("date") val date: String? = null, + @SerialName("aired_date") val airedDate: String? = null, + @SerialName("is_asian") val isAsian: Boolean = false, + @SerialName("is_bollywood") val isBollywood: Boolean = false, + @SerialName("is_cartoon") val isCartoon: Boolean = false, ) } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt index 61f87b8bab9..bad31a85d2d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.plugins -import com.fasterxml.jackson.annotation.JsonProperty +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.MainAPI import com.lagradost.cloudstream3.utils.ExtractorApi @@ -64,17 +65,18 @@ abstract class BasePlugin { var filename: String? = null + @Serializable class Manifest { - @JsonProperty("name") + @SerialName("name") var name: String? = null - @JsonProperty("pluginClassName") + @SerialName("pluginClassName") var pluginClassName: String? = null - @JsonProperty("version") + @SerialName("version") var version: Int? = null - @JsonProperty("requiresResources") + @SerialName("requiresResources") var requiresResources: Boolean = false } } \ No newline at end of file diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 6333674ea5a..77e6dd89344 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -1,6 +1,6 @@ package com.lagradost.cloudstream3.utils -import com.fasterxml.jackson.annotation.JsonIgnore +import kotlinx.serialization.Transient import com.fleeksoft.ksoup.Ksoup import com.lagradost.cloudstream3.AudioFile import com.lagradost.cloudstream3.IDownloadableMinimum @@ -656,7 +656,7 @@ constructor( return videoSize } - @JsonIgnore + @Transient fun getAllHeaders(): Map { if (referer.isBlank()) { return headers From 167b3bad5d1a681dad6cfbfb00dfbfbd461a90e8 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:22:31 -0600 Subject: [PATCH 006/192] Update --- .../cloudstream3/extractors/Streamlare.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt index 6688d288d86..d5455a28c76 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/Streamlare.kt @@ -29,18 +29,18 @@ open class Slmaxed : ExtractorApi() { @Serializable data class JsonResponse( - @SerialName val status: String? = null, - @SerialName val message: String? = null, - @SerialName val type: String? = null, - @SerialName val token: String? = null, - @SerialName val result: Map? = null + @SerialName("status") val status: String? = null, + @SerialName("message") val message: String? = null, + @SerialName("type") val type: String? = null, + @SerialName("token") val token: String? = null, + @SerialName("result") val result: Map? = null ) @Serializable data class Result( - @SerialName val label: String? = null, - @SerialName val file: String? = null, - @SerialName val type: String? = null + @SerialName("label") val label: String? = null, + @SerialName("file") val file: String? = null, + @SerialName("type") val type: String? = null ) override suspend fun getUrl(url: String, referer: String?): List? { @@ -69,4 +69,4 @@ open class Slmaxed : ExtractorApi() { } } } -} \ No newline at end of file +} From 67a44394ecccb2fbcec5fedd39e709407c9d85be Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:24:45 -0600 Subject: [PATCH 007/192] - --- .../kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 77e6dd89344..88781771e57 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -1,6 +1,5 @@ package com.lagradost.cloudstream3.utils -import kotlinx.serialization.Transient import com.fleeksoft.ksoup.Ksoup import com.lagradost.cloudstream3.AudioFile import com.lagradost.cloudstream3.IDownloadableMinimum @@ -656,7 +655,6 @@ constructor( return videoSize } - @Transient fun getAllHeaders(): Map { if (referer.isBlank()) { return headers From 4329599c3a1753c4172e51f11018ae8bcaaf9b05 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:30:57 -0600 Subject: [PATCH 008/192] Fix --- .../com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt index 4e1559fb388..fa58cd93871 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/videoskip/AniSkip.kt @@ -1,6 +1,6 @@ package com.lagradost.cloudstream3.utils.videoskip -import com.fasterxml.jackson.databind.annotation.JsonSerialize +import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.AnimeLoadResponse import com.lagradost.cloudstream3.LoadResponse import com.lagradost.cloudstream3.LoadResponse.Companion.getMalId @@ -68,4 +68,4 @@ class AniSkip : SkipAPI() { val startTime: Double, val endTime: Double ) -} \ No newline at end of file +} From 4f0d8673f3fdc9f11817f7b59723a5bbc04ec7d5 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:33:36 -0600 Subject: [PATCH 009/192] Data class --- .../cloudstream3/syncproviders/providers/SimklApi.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index f87316f177f..1e556417835 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -568,7 +568,7 @@ class SimklApi : SyncAPI() { } @Serializable - class HistoryMediaObject( + data class HistoryMediaObject( @SerialName("title") title: String? = null, @SerialName("year") year: Int? = null, @SerialName("ids") ids: Ids? = null, @@ -579,7 +579,7 @@ class SimklApi : SyncAPI() { ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes) @Serializable - class RatingMediaObject( + data class RatingMediaObject( @SerialName("title") title: String?, @SerialName("year") year: Int?, @SerialName("ids") ids: Ids?, @@ -588,7 +588,7 @@ class SimklApi : SyncAPI() { ) : MediaObject(title, year, ids) @Serializable - class StatusMediaObject( + data class StatusMediaObject( @SerialName("title") title: String?, @SerialName("year") year: Int?, @SerialName("ids") ids: Ids?, From 809e9bdc13fb9ddc7e61457bdd7d6d1c57e5e40b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:35:00 -0600 Subject: [PATCH 010/192] Fix --- .../cloudstream3/syncproviders/providers/KitsuApi.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt index 90009b7f7ac..89de1544cc2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt @@ -184,9 +184,9 @@ class KitsuApi: SyncAPI() { return null } + @Serializable data class KitsuResponse( - @field:JsonProperty(value = "data") - val data: KitsuNode, + @SerialName("data") val data: KitsuNode, ) val url = From 11d07f4ab885303f58da81af9efc127699e095bf Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:39:37 -0600 Subject: [PATCH 011/192] No data class --- .../syncproviders/providers/SimklApi.kt | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 1e556417835..43a7219ce5a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -568,30 +568,30 @@ class SimklApi : SyncAPI() { } @Serializable - data class HistoryMediaObject( - @SerialName("title") title: String? = null, - @SerialName("year") year: Int? = null, - @SerialName("ids") ids: Ids? = null, - @SerialName("seasons") seasons: List? = null, - @SerialName("episodes") episodes: List? = null, + class HistoryMediaObject( + title: String? = null, + year: Int? = null, + ids: Ids? = null, + seasons: List? = null, + episodes: List? = null, @SerialName("rating") val rating: Int? = null, @SerialName("rated_at") val ratedAt: String? = null, ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes) @Serializable - data class RatingMediaObject( - @SerialName("title") title: String?, - @SerialName("year") year: Int?, - @SerialName("ids") ids: Ids?, + class RatingMediaObject( + title: String?, + year: Int?, + ids: Ids?, @SerialName("rating") val rating: Int, @SerialName("rated_at") val ratedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) @Serializable - data class StatusMediaObject( - @SerialName("title") title: String?, - @SerialName("year") year: Int?, - @SerialName("ids") ids: Ids?, + class StatusMediaObject( + title: String?, + year: Int?, + ids: Ids?, @SerialName("to") val to: String, @SerialName("watched_at") val watchedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) From 19fdb8386ca251095ac31a1363f5a6400b3a7899 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:42:02 -0600 Subject: [PATCH 012/192] Add --- gradle/libs.versions.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f1ff5ede09d..c194a4f8051 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -127,6 +127,7 @@ buildkonfig = { id = "com.codingfeline.buildkonfig", version.ref = "buildkonfigG dokka = { id = "org.jetbrains.dokka", version.ref = "dokkaGradlePlugin" } kotlin-jvm = { id = "org.jetbrains.kotlin.jvm" , version.ref = "kotlinGradlePlugin" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlinGradlePlugin" } +kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinGradlePlugin" } [bundles] coil = ["coil", "coil-network-ktor3"] From 52e5689f0499029308a680189bdec4a321456049 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:42:35 -0600 Subject: [PATCH 013/192] add --- build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/build.gradle.kts b/build.gradle.kts index e35c1f61148..609a94b3ad4 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,6 +6,7 @@ plugins { alias(libs.plugins.dokka) apply false alias(libs.plugins.kotlin.jvm) apply false alias(libs.plugins.kotlin.multiplatform) apply false + alias(libs.plugins.kotlin.serialization) apply false } allprojects { From 0e552c1b602ef04a2d753033b54da7f815354589 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:43:10 -0600 Subject: [PATCH 014/192] Add --- app/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3982f09c932..ce5e2412d54 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -8,6 +8,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { alias(libs.plugins.android.application) alias(libs.plugins.dokka) + alias(libs.plugins.kotlin.serialization) } val javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get()) From 2167bf2bf05e34affed430ee2da0d61b5db9bc58 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:43:41 -0600 Subject: [PATCH 015/192] Add --- library/build.gradle.kts | 1 + 1 file changed, 1 insertion(+) diff --git a/library/build.gradle.kts b/library/build.gradle.kts index cf3c3aff5bc..a610619c17d 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -12,6 +12,7 @@ plugins { alias(libs.plugins.android.multiplatform.library) alias(libs.plugins.buildkonfig) alias(libs.plugins.dokka) + alias(libs.plugins.kotlin.serialization) } val javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get()) From e26c8fc51b7b5fc32a6e66e9e7403e274fa50c45 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:49:10 -0600 Subject: [PATCH 016/192] Update --- .../kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt index 82b3444c389..91c83869e7f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/ByseSX.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.extractors import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64DecodeArray @@ -190,5 +191,5 @@ data class PlaybackDecryptSource( val url: String, @SerialName("bitrate_kbps") val bitrateKbps: Long, - val height: Any?, + val height: JsonElement?, ) From 80fff23c7881e80bf03a01b342c509d3b914acf3 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:51:33 -0600 Subject: [PATCH 017/192] JsonElement --- .../com/lagradost/cloudstream3/extractors/GUpload.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt index ef46f749b43..d6c60bdb70e 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/GUpload.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.extractors import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64Decode @@ -48,9 +49,9 @@ open class GUpload: ExtractorApi() { @SerialName("posterUrl") val posterUrl: String? = null, @SerialName("videoId") val videoId: String? = null, @SerialName("primaryColor") val primaryColor: String? = null, - @SerialName("audioTracks") val audioTracks: List = emptyList(), - @SerialName("subtitleTracks") val subtitleTracks: List = emptyList(), + @SerialName("audioTracks") val audioTracks: List = emptyList(), + @SerialName("subtitleTracks") val subtitleTracks: List = emptyList(), @SerialName("vastFallbackList") val vastFallbackList: List = emptyList(), @SerialName("videoOwnerId") val videoOwnerId: Long = 0, ) -} \ No newline at end of file +} From 817b5d31d4b7998d196d629d6f98cad6ec610834 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 13 May 2026 19:53:00 -0600 Subject: [PATCH 018/192] Use JsonElement --- .../com/lagradost/cloudstream3/metaproviders/MyDramaList.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt index bf8789d9b7b..3735a714549 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt @@ -2,6 +2,7 @@ package com.lagradost.cloudstream3.metaproviders import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement import com.lagradost.api.BuildConfig import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.Actor @@ -262,7 +263,7 @@ abstract class MyDramaListAPI : MainAPI() { @SerialName("aired_start") val airedStart: String? = null, @SerialName("released") val released: String? = null, @SerialName("release_dates_fmt") val releaseDatesFmt: String, - @SerialName("genres") val genres: List? = null, + @SerialName("genres") val genres: List? = null, @SerialName("trailer") val trailer: Trailer?, @SerialName("watchers") val watchers: Long, @SerialName("ranked") val ranked: Long, From bc8efcdbc2dc4e5369407f68831e5f0c759fea64 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:06:56 -0600 Subject: [PATCH 019/192] Fix --- .../syncproviders/providers/AniListApi.kt | 53 ++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 2d87fa7709a..9aed46a48b4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -744,8 +744,11 @@ class AniListApi : SyncAPI() { } /** Used to query a saved MediaItem on the list to get the id for removal */ + @Serializable data class MediaListItemRoot(@SerialName("data") val data: MediaListItem? = null) + @Serializable data class MediaListItem(@SerialName("MediaList") val mediaList: MediaListId? = null) + @Serializable data class MediaListId(@SerialName("id") val id: Long? = null) private suspend fun postDataAboutId( @@ -848,14 +851,17 @@ class AniListApi : SyncAPI() { return seasons.toList() } + @Serializable data class SeasonResponse( @SerialName("data") val data: SeasonData, ) + @Serializable data class SeasonData( @SerialName("Media") val media: SeasonMedia, ) + @Serializable data class SeasonMedia( @SerialName("id") val id: Int?, @SerialName("title") val title: MediaTitle?, @@ -876,22 +882,26 @@ class AniListApi : SyncAPI() { @SerialName("recommendations") val recommendations: RecommendationConnection?, ) + @Serializable data class RecommendationConnection( @SerialName("edges") val edges: List = emptyList(), @SerialName("nodes") val nodes: List = emptyList(), //@SerialName("pageInfo") val pageInfo: PageInfo, ) + @Serializable data class RecommendationEdge( //@SerialName("rating") val rating: Int, @SerialName("node") val node: Recommendation, ) + @Serializable data class Recommendation( val id: Long, @SerialName("mediaRecommendation") val mediaRecommendation: SeasonMedia?, ) + @Serializable data class CharacterName( @SerialName("name") val first: String?, @SerialName("middle") val middle: String?, @@ -903,17 +913,20 @@ class AniListApi : SyncAPI() { @SerialName("userPreferred") val userPreferred: String?, ) + @Serializable data class CharacterImage( @SerialName("large") val large: String?, @SerialName("medium") val medium: String?, ) + @Serializable data class Character( @SerialName("name") val name: CharacterName?, @SerialName("age") val age: String?, @SerialName("image") val image: CharacterImage?, ) + @Serializable data class CharacterEdge( @SerialName("id") val id: Int?, /** @@ -934,11 +947,13 @@ class AniListApi : SyncAPI() { @SerialName("node") val node: Character?, ) + @Serializable data class StaffImage( @SerialName("large") val large: String?, @SerialName("medium") val medium: String?, ) + @Serializable data class StaffName( @SerialName("name") val first: String?, @SerialName("middle") val middle: String?, @@ -949,24 +964,28 @@ class AniListApi : SyncAPI() { @SerialName("userPreferred") val userPreferred: String?, ) + @Serializable data class Staff( @SerialName("image") val image: StaffImage?, @SerialName("name") val name: StaffName?, @SerialName("age") val age: Int?, ) + @Serializable data class CharacterConnection( @SerialName("edges") val edges: List?, @SerialName("nodes") val nodes: List?, //@SerialName("pageInfo") pageInfo: PageInfo ) + @Serializable data class MediaTrailer( @SerialName("id") val id: String?, @SerialName("site") val site: String?, @SerialName("thumbnail") val thumbnail: String?, ) + @Serializable data class MediaCoverImage( @SerialName("extraLarge") val extraLarge: String?, @SerialName("large") val large: String?, @@ -974,29 +993,35 @@ class AniListApi : SyncAPI() { @SerialName("color") val color: String?, ) + @Serializable data class SeasonNextAiringEpisode( @SerialName("episode") val episode: Int?, @SerialName("timeUntilAiring") val timeUntilAiring: Int?, ) + @Serializable data class SeasonEdges( @SerialName("edges") val edges: List?, ) + @Serializable data class SeasonEdge( @SerialName("id") val id: Int?, @SerialName("relationType") val relationType: String?, @SerialName("node") val node: SeasonNode?, ) + @Serializable data class AniListFavoritesMediaConnection( @SerialName("nodes") val nodes: List, ) + @Serializable data class AniListFavourites( @SerialName("anime") val anime: AniListFavoritesMediaConnection, ) + @Serializable data class MediaTitle( @SerialName("romaji") val romaji: String?, @SerialName("english") val english: String?, @@ -1004,6 +1029,7 @@ class AniListApi : SyncAPI() { @SerialName("userPreferred") val userPreferred: String?, ) + @Serializable data class SeasonNode( @SerialName("id") val id: Int, @SerialName("format") val format: String?, @@ -1014,10 +1040,12 @@ class AniListApi : SyncAPI() { // @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, ) + @Serializable data class AniListAvatar( @SerialName("large") val large: String?, ) + @Serializable data class AniListViewer( @SerialName("id") val id: Int, @SerialName("name") val name: String, @@ -1025,25 +1053,30 @@ class AniListApi : SyncAPI() { @SerialName("favourites") val favourites: AniListFavourites?, ) + @Serializable data class AniListData( @SerialName("Viewer") val viewer: AniListViewer?, ) + @Serializable data class AniListRoot( @SerialName("data") val data: AniListData?, ) + @Serializable data class AniListUser( @SerialName("id") val id: Int, @SerialName("name") val name: String, @SerialName("picture") val picture: String?, ) + @Serializable data class LikeNode( @SerialName("id") val id: Int?, //@SerialName("idMal") public int idMal; ) + @Serializable data class LikePageInfo( @SerialName("total") val total: Int?, @SerialName("currentPage") val currentPage: Int?, @@ -1052,27 +1085,33 @@ class AniListApi : SyncAPI() { @SerialName("hasNextPage") val hasNextPage: Boolean?, ) + @Serializable data class LikeAnime( @SerialName("nodes") val nodes: List?, @SerialName("pageInfo") val pageInfo: LikePageInfo?, ) + @Serializable data class LikeFavourites( @SerialName("anime") val anime: LikeAnime?, ) + @Serializable data class LikeViewer( @SerialName("favourites") val favourites: LikeFavourites?, ) + @Serializable data class LikeData( @SerialName("Viewer") val viewer: LikeViewer?, ) + @Serializable data class LikeRoot( @SerialName("data") val data: LikeData?, ) + @Serializable data class AniListTitleHolder( @SerialName("title") val title: Title?, @SerialName("isFavourite") val isFavourite: Boolean?, @@ -1083,17 +1122,20 @@ class AniListApi : SyncAPI() { @SerialName("type") val type: AniListStatusType?, ) + @Serializable data class GetDataMediaListEntry( @SerialName("progress") val progress: Int?, @SerialName("status") val status: String?, @SerialName("score") val score: Int?, ) + @Serializable data class Nodes( @SerialName("id") val id: Int?, @SerialName("mediaRecommendation") val mediaRecommendation: MediaRecommendation? ) + @Serializable data class GetDataMedia( @SerialName("isFavourite") val isFavourite: Boolean?, @SerialName("episodes") val episodes: Int?, @@ -1101,28 +1143,34 @@ class AniListApi : SyncAPI() { @SerialName("mediaListEntry") val mediaListEntry: GetDataMediaListEntry? ) + @Serializable data class Recommendations( @SerialName("nodes") val nodes: List? ) + @Serializable data class GetDataData( @SerialName("Media") val media: GetDataMedia?, ) + @Serializable data class GetDataRoot( @SerialName("data") val data: GetDataData?, ) + @Serializable data class GetSearchTitle( @SerialName("romaji") val romaji: String?, ) + @Serializable data class TrailerObject( @SerialName("id") val id: String?, @SerialName("thumbnail") val thumbnail: String?, @SerialName("site") val site: String?, ) + @Serializable data class GetSearchMedia( @SerialName("id") val id: Int, @SerialName("idMal") val idMal: Int?, @@ -1138,15 +1186,18 @@ class AniListApi : SyncAPI() { @SerialName("relations") val relations: SeasonEdges? ) + @Serializable data class GetSearchPage( @SerialName("Page") val page: GetSearchData?, ) + @Serializable data class GetSearchData( @SerialName("media") val media: List?, ) + @Serializable data class GetSearchRoot( @SerialName("data") val data: GetSearchPage?, ) -} \ No newline at end of file +} From 2694184cac598a596947e49c64348c4863070144 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:09:53 -0600 Subject: [PATCH 020/192] Fix --- .../cloudstream3/syncproviders/providers/KitsuApi.kt | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt index 89de1544cc2..12ad3d2fc76 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/KitsuApi.kt @@ -787,18 +787,22 @@ query { return map } + @Serializable data class KitsuResponse( val data: Data? = null ) { + @Serializable data class Data( val lookupMapping: LookupMapping? = null ) + @Serializable data class LookupMapping( val id: String? = null, val episodes: Episodes? = null ) + @Serializable data class Episodes( val nodes: List? = null ) @@ -812,18 +816,22 @@ query { val thumbnail: Thumbnail? = null ) + @Serializable data class Description( val en: String? = null ) + @Serializable data class Thumbnail( val original: Original? = null ) + @Serializable data class Original( val url: String? = null ) + @Serializable data class Titles( val canonical: String? = null ) From ca8032f06c02ed74700f252407246349a0cf374e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:22:33 -0600 Subject: [PATCH 021/192] Fix val --- .../syncproviders/providers/SimklApi.kt | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 43a7219ce5a..9807fe36010 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -568,30 +568,30 @@ class SimklApi : SyncAPI() { } @Serializable - class HistoryMediaObject( - title: String? = null, - year: Int? = null, - ids: Ids? = null, - seasons: List? = null, - episodes: List? = null, + data class HistoryMediaObject( + @SerialName("title") val title: String? = null, + @SerialName("year") val year: Int? = null, + @SerialName("ids") val ids: Ids? = null, + @SerialName("seasons") val seasons: List? = null, + @SerialName("episodes") val episodes: List? = null, @SerialName("rating") val rating: Int? = null, @SerialName("rated_at") val ratedAt: String? = null, ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes) @Serializable - class RatingMediaObject( - title: String?, - year: Int?, - ids: Ids?, + data class RatingMediaObject( + @SerialName("title") val title: String?, + @SerialName("year") val year: Int?, + @SerialName("ids") val ids: Ids?, @SerialName("rating") val rating: Int, @SerialName("rated_at") val ratedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) @Serializable - class StatusMediaObject( - title: String?, - year: Int?, - ids: Ids?, + data class StatusMediaObject( + @SerialName("title") val title: String?, + @SerialName("year") val year: Int?, + @SerialName("ids") val ids: Ids?, @SerialName("to") val to: String, @SerialName("watched_at") val watchedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) From e062e6ecb3e375053185e97338d4c8a7c5c85c43 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:33:59 -0600 Subject: [PATCH 022/192] Try transient --- .../syncproviders/providers/SimklApi.kt | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 9807fe36010..6dda3c92f3f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -5,6 +5,7 @@ import androidx.core.net.toUri import com.fasterxml.jackson.annotation.JsonInclude import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import com.lagradost.cloudstream3.BuildConfig import com.lagradost.cloudstream3.CloudStreamApp import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -569,29 +570,29 @@ class SimklApi : SyncAPI() { @Serializable data class HistoryMediaObject( - @SerialName("title") val title: String? = null, - @SerialName("year") val year: Int? = null, - @SerialName("ids") val ids: Ids? = null, - @SerialName("seasons") val seasons: List? = null, - @SerialName("episodes") val episodes: List? = null, + @Transient override val title: String? = null, + @Transient override val year: Int? = null, + @Transient override val ids: Ids? = null, + @Transient override val seasons: List? = null, + @Transient override val episodes: List? = null, @SerialName("rating") val rating: Int? = null, @SerialName("rated_at") val ratedAt: String? = null, ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes) @Serializable data class RatingMediaObject( - @SerialName("title") val title: String?, - @SerialName("year") val year: Int?, - @SerialName("ids") val ids: Ids?, + @Transient override val title: String?, + @Transient override val year: Int?, + @Transient override val ids: Ids?, @SerialName("rating") val rating: Int, @SerialName("rated_at") val ratedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) @Serializable data class StatusMediaObject( - @SerialName("title") val title: String?, - @SerialName("year") val year: Int?, - @SerialName("ids") val ids: Ids?, + @Transient override val title: String?, + @Transient override val year: Int?, + @Transient override val ids: Ids?, @SerialName("to") val to: String, @SerialName("watched_at") val watchedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) From b451213a8795dc9ac884a0b8afaa49427857c9c1 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:38:38 -0600 Subject: [PATCH 023/192] Fix defaults --- .../syncproviders/providers/SimklApi.kt | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 6dda3c92f3f..c0d0e406d02 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -319,15 +319,15 @@ class SimklApi : SyncAPI() { */ @Serializable open class MediaObject( - @SerialName("title") val title: String?, - @SerialName("year") val year: Int?, - @SerialName("ids") val ids: Ids?, + @SerialName("title") open val title: String?, + @SerialName("year") open val year: Int?, + @SerialName("ids") open val ids: Ids?, @SerialName("total_episodes") val totalEpisodes: Int? = null, @SerialName("status") val status: String? = null, @SerialName("poster") val poster: String? = null, @SerialName("type") val type: String? = null, - @SerialName("seasons") val seasons: List? = null, - @SerialName("episodes") val episodes: List? = null + @SerialName("seasons") open val seasons: List? = null, + @SerialName("episodes") open val episodes: List? = null ) { fun hasEnded(): Boolean { return status == "released" || status == "ended" @@ -581,18 +581,18 @@ class SimklApi : SyncAPI() { @Serializable data class RatingMediaObject( - @Transient override val title: String?, - @Transient override val year: Int?, - @Transient override val ids: Ids?, + @Transient override val title: String? = null, + @Transient override val year: Int? = null, + @Transient override val ids: Ids? = null, @SerialName("rating") val rating: Int, @SerialName("rated_at") val ratedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) @Serializable data class StatusMediaObject( - @Transient override val title: String?, - @Transient override val year: Int?, - @Transient override val ids: Ids?, + @Transient override val title: String? = null, + @Transient override val year: Int? = null, + @Transient override val ids: Ids? = null, @SerialName("to") val to: String, @SerialName("watched_at") val watchedAt: String? = getDateTime(unixTime) ) : MediaObject(title, year, ids) From 5a9517a162c07216ba30772153f45a9792b6495a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:43:45 -0600 Subject: [PATCH 024/192] Fix cast --- .../cloudstream3/syncproviders/providers/SimklApi.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index c0d0e406d02..5b3e3e24b4e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -364,11 +364,12 @@ class SimklApi : SyncAPI() { } fun toSyncSearchResult(): SyncAPI.SyncSearchResult? { + val currentIds = this.ids return SyncAPI.SyncSearchResult( this.title ?: return null, "Simkl", - this.ids?.simkl?.toString() ?: return null, - getUrlFromId(this.ids.simkl), + currentIds?.simkl?.toString() ?: return null, + getUrlFromId(currentIds.simkl), this.poster?.let { getPosterUrl(it) }, if (this.type == "movie") TvType.Movie else TvType.TvSeries ) From b913d2cadad301f9f425b23e95dabf519932d714 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 12:54:36 -0600 Subject: [PATCH 025/192] Fix defaults --- .../cloudstream3/utils/DataStoreHelper.kt | 85 ++++++++++--------- 1 file changed, 43 insertions(+), 42 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index 480576628a2..509e1bddac0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.utils import android.content.Context import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -291,20 +292,20 @@ object DataStoreHelper { data class SubscribedData( @SerialName("subscribedTime") val subscribedTime: Long, @SerialName("lastSeenEpisodeCount") val lastSeenEpisodeCount: Map, - override var id: Int?, - override val latestUpdatedTime: Long, - override val name: String, - override val url: String, - override val apiName: String, - override var type: TvType?, - override var posterUrl: String?, - override val year: Int?, - override val syncData: Map? = null, - override var quality: SearchQuality? = null, - override var posterHeaders: Map? = null, - override val plot: String? = null, - override var score: Score? = null, - override val tags: List? = null, + @Transient override var id: Int? = null, + @Transient override val latestUpdatedTime: Long = 0L, + @Transient override val name: String = "", + @Transient override val url: String = "", + @Transient override val apiName: String = "", + @Transient override var type: TvType? = null, + @Transient override var posterUrl: String? = null, + @Transient override val year: Int? = null, + @Transient override val syncData: Map? = null, + @Transient override var quality: SearchQuality? = null, + @Transient override var posterHeaders: Map? = null, + @Transient override val plot: String? = null, + @Transient override var score: Score? = null, + @Transient override val tags: List? = null, ) : LibrarySearchResponse( id, latestUpdatedTime, @@ -347,20 +348,20 @@ object DataStoreHelper { @Serializable data class BookmarkedData( @SerialName("bookmarkedTime") val bookmarkedTime: Long, - override var id: Int?, - override val latestUpdatedTime: Long, - override val name: String, - override val url: String, - override val apiName: String, - override var type: TvType?, - override var posterUrl: String?, - override val year: Int?, - override val syncData: Map? = null, - override var quality: SearchQuality? = null, - override var posterHeaders: Map? = null, - override val plot: String? = null, - override var score: Score? = null, - override val tags: List? = null, + @Transient override var id: Int? = null, + @Transient override val latestUpdatedTime: Long = 0L, + @Transient override val name: String = "", + @Transient override val url: String = "", + @Transient override val apiName: String = "", + @Transient override var type: TvType? = null, + @Transient override var posterUrl: String? = null, + @Transient override val year: Int? = null, + @Transient override val syncData: Map? = null, + @Transient override var quality: SearchQuality? = null, + @Transient override var posterHeaders: Map? = null, + @Transient override val plot: String? = null, + @Transient override var score: Score? = null, + @Transient override val tags: List? = null, ) : LibrarySearchResponse( id, latestUpdatedTime, @@ -401,20 +402,20 @@ object DataStoreHelper { @Serializable data class FavoritesData( @SerialName("favoritesTime") val favoritesTime: Long, - override var id: Int?, - override val latestUpdatedTime: Long, - override val name: String, - override val url: String, - override val apiName: String, - override var type: TvType?, - override var posterUrl: String?, - override val year: Int?, - override val syncData: Map? = null, - override var quality: SearchQuality? = null, - override var posterHeaders: Map? = null, - override val plot: String? = null, - override var score: Score? = null, - override val tags: List? = null, + @Transient override var id: Int? = null, + @Transient override val latestUpdatedTime: Long = 0L, + @Transient override val name: String = "", + @Transient override val url: String = "", + @Transient override val apiName: String = "", + @Transient override var type: TvType? = null, + @Transient override var posterUrl: String? = null, + @Transient override val year: Int? = null, + @Transient override val syncData: Map? = null, + @Transient override var quality: SearchQuality? = null, + @Transient override var posterHeaders: Map? = null, + @Transient override val plot: String? = null, + @Transient override var score: Score? = null, + @Transient override val tags: List? = null, ) : LibrarySearchResponse( id, latestUpdatedTime, From 120bb7321355853f76cc6b0a735ca3782a4c1e45 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:05:03 -0600 Subject: [PATCH 026/192] +ExtractorLink --- .../kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt index 88781771e57..d4d71364fbb 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/ExtractorApi.kt @@ -1,5 +1,6 @@ package com.lagradost.cloudstream3.utils +import kotlinx.serialization.Serializable import com.fleeksoft.ksoup.Ksoup import com.lagradost.cloudstream3.AudioFile import com.lagradost.cloudstream3.IDownloadableMinimum @@ -617,6 +618,7 @@ open class DrmExtractorLink private constructor( * @property audioTracks List of separate audio tracks that can be used with this video * @see newExtractorLink * */ +@Serializable open class ExtractorLink @Deprecated("Use newExtractorLink", level = DeprecationLevel.WARNING) constructor( From 2a9aca28ab08f9a4a7ddf2861271500cf83c7ac0 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:06:55 -0600 Subject: [PATCH 027/192] +SubtitleData --- .../lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt index ee6170aa53f..7ab08be9070 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/PlayerSubtitleHelper.kt @@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.ui.subtitles.SaveCaptionStyle import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment.Companion.setSubtitleViewStyle import com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF import com.lagradost.cloudstream3.utils.UIHelper.toPx +import kotlinx.serialization.Serializable enum class SubtitleStatus { IS_ACTIVE, @@ -33,6 +34,7 @@ enum class SubtitleOrigin { * @param headers if empty it will use the base onlineDataSource headers else only the specified headers * @param languageCode usually, tags such as "en", "es-mx", or "zh-hant-TW". But it could be something like "English 4" * */ +@Serializable data class SubtitleData( val originalName: String, val nameSuffix: String, @@ -142,4 +144,4 @@ class PlayerSubtitleHelper { setSubStyle(it) } } -} \ No newline at end of file +} From 52e468ba3709a4ddcd83ffd92ea4bb4c1e6dd12a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:08:40 -0600 Subject: [PATCH 028/192] +ResultEpisode --- .../java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt index cbf94fd9796..0540e437023 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/result/ResultFragment.kt @@ -21,6 +21,7 @@ import com.lagradost.cloudstream3.utils.DataStoreHelper.getViewPos import com.lagradost.cloudstream3.utils.Event import com.lagradost.cloudstream3.utils.ImageLoader.loadImage import com.lagradost.cloudstream3.utils.UiImage +import kotlinx.serialization.Serializable const val START_ACTION_RESUME_LATEST = 1 const val START_ACTION_LOAD_EP = 2 @@ -34,6 +35,7 @@ enum class VideoWatchState { Watched } +@Serializable data class ResultEpisode( val headerName: String, val name: String?, From 164331f90a99be2fd0eb63114b71f84c2b692e37 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:13:57 -0600 Subject: [PATCH 029/192] Transient --- .../cloudstream3/utils/downloader/DownloadObjects.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt index 2940c284027..bfceff3d81e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.utils.downloader import android.net.Uri import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import com.lagradost.cloudstream3.Score import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.services.DownloadQueueService @@ -74,7 +75,7 @@ object DownloadObjects { @SerialName("score") var score: Score? = null, @SerialName("description") val description: String?, @SerialName("cacheTime") val cacheTime: Long, - override val id: Int, + @Transient override val id: Int = 0, ) : DownloadCached(id) { @SerialName("rating") @Deprecated( @@ -100,7 +101,7 @@ object DownloadObjects { @SerialName("name") val name: String, @SerialName("poster") val poster: String?, @SerialName("cacheTime") val cacheTime: Long, - override val id: Int, + @Transient override val id: Int = 0, ) : DownloadCached(id) @Serializable @@ -233,4 +234,4 @@ object DownloadObjects { return Objects.hash(startByte, endByte) } } -} \ No newline at end of file +} From 8a1d1f8b4819cd93f48983db6447d5393fa89d4c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:15:31 -0600 Subject: [PATCH 030/192] +AudioFile --- .../src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 75a57c4630f..e3d48031a9e 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -6,7 +6,6 @@ package com.lagradost.cloudstream3 -import com.fasterxml.jackson.annotation.JsonAutoDetect import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import com.fasterxml.jackson.databind.DeserializationFeature @@ -1173,6 +1172,7 @@ suspend fun newSubtitleFile( * @see newAudioFile * */ @ConsistentCopyVisibility +@Serializable data class AudioFile internal constructor( var url: String, var headers: Map? = null From 35c0d6599dd3693a2f1afef591b13fe68a456ef8 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:19:30 -0600 Subject: [PATCH 031/192] +SeasonData --- .../src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index e3d48031a9e..8bc1ad3095c 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -2188,6 +2188,7 @@ data class NextAiring( * @param name To be shown next to the season like "Season $displaySeason $name" but if displaySeason is null then "$name" * @param displaySeason What to be displayed next to the season name, if null then the name is the only thing shown. * */ +@Serializable data class SeasonData( val season: Int, val name: String? = null, From 95f553ff891ec3fec6815ea38fe5882aef1843e6 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:23:12 -0600 Subject: [PATCH 032/192] Add UriSerializer --- .../utils/ serializer/UriSerializer.kt | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt new file mode 100644 index 00000000000..ec069af037a --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt @@ -0,0 +1,22 @@ +package com.lagradost.cloudstream3.utils.serializer + +import android.net.Uri +import kotlinx.serialization.KSerializer +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder + +object UriSerializer : KSerializer { + override val descriptor: SerialDescriptor = + PrimitiveSerialDescriptor("Uri", PrimitiveKind.STRING) + + override fun serialize(encoder: Encoder, value: Uri) { + encoder.encodeString(value.toString()) + } + + override fun deserialize(decoder: Decoder): Uri { + return Uri.parse(decoder.decodeString()) + } +} From bc54724c14507290215d5148f1805768fc9d2831 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:26:05 -0600 Subject: [PATCH 033/192] Use UriSerializer --- .../lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt index 9489c7381ad..a89d506c1a0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt @@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.utils.newExtractorLink import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF import com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF +import com.lagradost.cloudstream3.utils.serializer.UriSerializer import com.lagradost.cloudstream3.utils.txt /** @@ -53,6 +54,7 @@ class CloudStreamPackage : OpenInAppAction( @Serializable data class MinimalVideoLink( @SerialName("uri") + @Serializable(with = UriSerializer::class) val uri: Uri?, @SerialName("url") val url: String?, @@ -161,4 +163,4 @@ class CloudStreamPackage : OpenInAppAction( override fun onResult(activity: Activity, intent: Intent?) { // No results yet } -} \ No newline at end of file +} From cb4e6d30fb5bc874e0df29e9e750176560191b60 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:27:10 -0600 Subject: [PATCH 034/192] Use UriSerializer --- .../cloudstream3/utils/downloader/DownloadObjects.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt index bfceff3d81e..4343c587e63 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt @@ -10,6 +10,7 @@ import com.lagradost.cloudstream3.services.DownloadQueueService import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.utils.ExtractorLink +import com.lagradost.cloudstream3.utils.serializer.UriSerializer import com.lagradost.safefile.SafeFile import java.io.IOException import java.io.OutputStream @@ -153,7 +154,9 @@ object DownloadObjects { data class DownloadedFileInfoResult( @SerialName("fileLength") val fileLength: Long, @SerialName("totalBytes") val totalBytes: Long, - @SerialName("path") val path: Uri, + @SerialName("path") + @Serializable(with = UriSerializer::class) + val path: Uri, ) From 74960eab88d24496881b730a494f56a19deb0b45 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:36:04 -0600 Subject: [PATCH 035/192] Fix parser --- .../lagradost/cloudstream3/MainActivity.kt | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt index 40202c5756e..2eb8bef3a20 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainActivity.kt @@ -10,26 +10,31 @@ import com.lagradost.nicehttp.ResponseParser import io.ktor.client.engine.okhttp.OkHttpEngine import okhttp3.OkHttpClient import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.serializer +import kotlinx.serialization.serializerOrNull import kotlin.reflect.KClass // Short name for requests client to make it nicer to use -@OptIn(ExperimentalSerializationApi::class) -private val jacksonResponseParser = object : ResponseParser { +@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) +private val jsonResponseParser = object : ResponseParser { val mapper: ObjectMapper = jacksonObjectMapper().configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false ) - val kotlinxJson = Json { ignoreUnknownKeys = true } + + val json = Json { ignoreUnknownKeys = true } override fun parse(text: String, kClass: KClass): T { - val serializer = kotlinxJson.serializersModule.getContextual(kClass) + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases + val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) return if (serializer != null) { try { - kotlinxJson.decodeFromString(serializer, text) - } catch (e: Exception) { + json.decodeFromString(serializer, text) + } catch (_: Exception) { mapper.readValue(text, kClass.java) } } else { @@ -40,18 +45,20 @@ private val jacksonResponseParser = object : ResponseParser { override fun parseSafe(text: String, kClass: KClass): T? { return try { parse(text, kClass) - } catch (e: Exception) { + } catch (_: Exception) { null } } override fun writeValueAsString(obj: Any): String { - val serializer = kotlinxJson.serializersModule.getContextual(obj::class) + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases + val serializer = obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class) return if (serializer != null) { try { - // If it has a serializer, encode it safely via Kotlinx - kotlinxJson.encodeToString(JsonElement.serializer(), kotlinxJson.parseToJsonElement(obj.toString())) - } catch (e: Exception) { + // If it has a serializer, encode it safely via kotlinx.serialization + json.encodeToString(JsonElement.serializer(), json.parseToJsonElement(obj.toString())) + } catch (_: Exception) { mapper.writeValueAsString(obj) } } else { @@ -59,10 +66,9 @@ private val jacksonResponseParser = object : ResponseParser { } } } - /** The default networking helper. This helper performs SSL checks. * If you need to make requests to websites with invalid SSL certificates use insecureApp instead. */ -var app = Requests(responseParser = jacksonResponseParser).apply { +var app = Requests(responseParser = jsonResponseParser).apply { defaultHeaders = mapOf("user-agent" to USER_AGENT) } @@ -75,6 +81,6 @@ val okHttpClient = (app.baseClient.engine as? OkHttpEngine) * This should NEVER be used for sensitive networking operations such as logins. Only use this when required. */ @Prerelease @UnsafeSSL -var insecureApp = Requests(responseParser = jacksonResponseParser).apply { +var insecureApp = Requests(responseParser = jsonResponseParser).apply { defaultHeaders = mapOf("user-agent" to USER_AGENT) } From 9aeac028562fa30b536d36d319a8de21d51ea38c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 13:54:46 -0600 Subject: [PATCH 036/192] Try support in DataStore --- .../lagradost/cloudstream3/utils/DataStore.kt | 63 +++++++++++++++---- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 0a1db85fadb..e13dd1e0a71 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -4,12 +4,18 @@ import android.content.Context import android.content.SharedPreferences import androidx.preference.PreferenceManager import com.fasterxml.jackson.databind.DeserializationFeature -import com.fasterxml.jackson.databind.json.JsonMapper -import com.fasterxml.jackson.module.kotlin.kotlinModule +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass import com.lagradost.cloudstream3.mvvm.logError +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.serializer +import kotlinx.serialization.serializerOrNull import kotlin.reflect.KClass import kotlin.reflect.KProperty import androidx.core.content.edit @@ -87,9 +93,45 @@ data class Editor( } } +@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) object DataStore { - val mapper: JsonMapper = JsonMapper.builder().addModule(kotlinModule()) - .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).build() + // Jackson fallback for classes not yet migrated to @Serializable + val mapper: ObjectMapper = jacksonObjectMapper().configure( + DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, + false + ) + + val json = Json { ignoreUnknownKeys = true } + + private fun String.parseToKotlinObject(kClass: KClass): T { + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases + val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) + return if (serializer != null) { + try { + json.decodeFromString(serializer, this) + } catch (_: Exception) { + mapper.readValue(this, kClass.java) + } + } else { + mapper.readValue(this, kClass.java) + } + } + + private fun anyToJsonString(obj: Any): String { + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases + val serializer = obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class) + return if (serializer != null) { + try { + json.encodeToString(JsonElement.serializer(), json.parseToJsonElement(obj.toString())) + } catch (_: Exception) { + mapper.writeValueAsString(obj) + } + } else { + mapper.writeValueAsString(obj) + } + } private fun getPreferences(context: Context): SharedPreferences { return context.getSharedPreferences(PREFERENCES_NAME, Context.MODE_PRIVATE) @@ -99,7 +141,6 @@ object DataStore { return getPreferences(this) } - fun getFolderName(folder: String, path: String): String { return "${folder}/${path}" } @@ -165,7 +206,7 @@ object DataStore { fun Context.setKey(path: String, value: T) { try { getSharedPrefs().edit { - putString(path, mapper.writeValueAsString(value)) + putString(path, value?.let { anyToJsonString(it) }) } } catch (e: Exception) { logError(e) @@ -175,7 +216,7 @@ object DataStore { fun Context.getKey(path: String, valueType: Class): T? { try { val json: String = getSharedPrefs().getString(path, null) ?: return null - return json.toKotlinObject(valueType) + return json.parseToKotlinObject(valueType.kotlin) } catch (e: Exception) { return null } @@ -186,11 +227,11 @@ object DataStore { } inline fun String.toKotlinObject(): T { - return mapper.readValue(this, T::class.java) + return parseToKotlinObject(T::class) } - fun String.toKotlinObject(valueType: Class): T { - return mapper.readValue(this, valueType) + fun String.toKotlinObject(valueType: Class): T { + return parseToKotlinObject(valueType.kotlin) } // GET KEY GIVEN PATH AND DEFAULT VALUE, NULL IF ERROR @@ -214,4 +255,4 @@ object DataStore { inline fun Context.getKey(folder: String, path: String, defVal: T?): T? { return getKey(getFolderName(folder, path), defVal) ?: defVal } -} \ No newline at end of file +} From f152393caef0723efe50d1ba46588f5b3ec8a914 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:02:37 -0600 Subject: [PATCH 037/192] Fix --- .../main/java/com/lagradost/cloudstream3/utils/DataStore.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index e13dd1e0a71..e629209a9a0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -103,7 +103,7 @@ object DataStore { val json = Json { ignoreUnknownKeys = true } - private fun String.parseToKotlinObject(kClass: KClass): T { + internal fun String.parseToKotlinObject(kClass: KClass): T { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) @@ -213,7 +213,7 @@ object DataStore { } } - fun Context.getKey(path: String, valueType: Class): T? { + fun Context.getKey(path: String, valueType: Class): T? { try { val json: String = getSharedPrefs().getString(path, null) ?: return null return json.parseToKotlinObject(valueType.kotlin) From 249468710c96d77040634753062f9a075b44242f Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:06:48 -0600 Subject: [PATCH 038/192] Fix --- .../main/java/com/lagradost/cloudstream3/utils/DataStore.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index e629209a9a0..a548758e199 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -9,6 +9,7 @@ import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass +import com.lagradost.cloudstream3.InternalAPI import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi @@ -103,7 +104,8 @@ object DataStore { val json = Json { ignoreUnknownKeys = true } - internal fun String.parseToKotlinObject(kClass: KClass): T { + @InternalAPI + fun String.parseToKotlinObject(kClass: KClass): T { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) From e8cad1679b77207152063cf5eeafef7b11ccafdc Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:17:10 -0600 Subject: [PATCH 039/192] Public --- .../main/java/com/lagradost/cloudstream3/utils/DataStore.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index a548758e199..2adb9141acf 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -120,7 +120,8 @@ object DataStore { } } - private fun anyToJsonString(obj: Any): String { + @InternalAPI + fun anyToJsonString(obj: Any): String { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases val serializer = obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class) From 162e23f59a641c7f26c1ace3d4f2b7c9cc469c5d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:23:06 -0600 Subject: [PATCH 040/192] Try AppUtils support --- .../lagradost/cloudstream3/utils/AppUtils.kt | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index 6832ab8d27f..c9154d6698d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -2,28 +2,60 @@ package com.lagradost.cloudstream3.utils import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.mapper +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.json.Json +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.serializer +import kotlinx.serialization.serializerOrNull import java.io.Reader +val json = Json { ignoreUnknownKeys = true } + +@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) object AppUtils { /** Any object as json string */ fun Any.toJson(): String { if (this is String) return this - return mapper.writeValueAsString(this) + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases + val serializer = this::class.serializerOrNull() ?: json.serializersModule.getContextual(this::class) + return if (serializer != null) { + try { + json.encodeToString(JsonElement.serializer(), json.parseToJsonElement(this.toString())) + } catch (_: Exception) { + mapper.writeValueAsString(this) + } + } else { + mapper.writeValueAsString(this) + } } - inline fun parseJson(value: String): T { - return mapper.readValue(value) + inline fun parseJson(value: String): T { + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases + val serializer = T::class.serializerOrNull() ?: json.serializersModule.getContextual(T::class) + return if (serializer != null) { + try { + json.decodeFromString(serializer, value) + } catch (_: Exception) { + mapper.readValue(value) + } + } else { + mapper.readValue(value) + } } - inline fun parseJson(reader: Reader, valueType: Class): T { + inline fun parseJson(reader: Reader, valueType: Class): T { + // Reader-based parsing has no kotlinx equivalent, fall back to Jackson return mapper.readValue(reader, valueType) } - inline fun tryParseJson(value: String?): T? { + inline fun tryParseJson(value: String?): T? { return try { parseJson(value ?: return null) } catch (_: Exception) { null } } -} \ No newline at end of file +} From 03f390574f61aca1578a89a372cce656f92c5d21 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:26:58 -0600 Subject: [PATCH 041/192] Fix? --- .../kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index c9154d6698d..bc0cca6fc53 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -31,7 +31,7 @@ object AppUtils { } } - inline fun parseJson(value: String): T { + inline fun parseJson(value: String): T { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases val serializer = T::class.serializerOrNull() ?: json.serializersModule.getContextual(T::class) @@ -46,12 +46,12 @@ object AppUtils { } } - inline fun parseJson(reader: Reader, valueType: Class): T { + inline fun parseJson(reader: Reader, valueType: Class): T { // Reader-based parsing has no kotlinx equivalent, fall back to Jackson return mapper.readValue(reader, valueType) } - inline fun tryParseJson(value: String?): T? { + inline fun tryParseJson(value: String?): T? { return try { parseJson(value ?: return null) } catch (_: Exception) { From 1c1ee88651444f5774fb0b608bf98465d3aa8b18 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:29:06 -0600 Subject: [PATCH 042/192] - --- .../kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index bc0cca6fc53..2772e36892f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -31,7 +31,7 @@ object AppUtils { } } - inline fun parseJson(value: String): T { + inline fun parseJson(value: String): T { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases val serializer = T::class.serializerOrNull() ?: json.serializersModule.getContextual(T::class) @@ -46,7 +46,7 @@ object AppUtils { } } - inline fun parseJson(reader: Reader, valueType: Class): T { + inline fun parseJson(reader: Reader, valueType: Class): T { // Reader-based parsing has no kotlinx equivalent, fall back to Jackson return mapper.readValue(reader, valueType) } From 3d893a934ed5c792efa7862b91e3e1abfcfd215c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:35:48 -0600 Subject: [PATCH 043/192] - --- .../kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index 2772e36892f..96c52551bfd 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -46,7 +46,7 @@ object AppUtils { } } - inline fun parseJson(reader: Reader, valueType: Class): T { + inline fun parseJson(reader: Reader, valueType: Class): T { // Reader-based parsing has no kotlinx equivalent, fall back to Jackson return mapper.readValue(reader, valueType) } From f9cc1d5e5e5e698b10e328ab6051bc4139dcbad2 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:39:52 -0600 Subject: [PATCH 044/192] Fix parse --- .../java/com/lagradost/cloudstream3/utils/SyncUtil.kt | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt index 2124e408a97..7243e5823b5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt @@ -9,7 +9,6 @@ import com.lagradost.cloudstream3.APIHolder.apis //import com.lagradost.cloudstream3.animeproviders.AniflixProvider import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError -import com.lagradost.cloudstream3.utils.AppUtils.parseJson import java.util.concurrent.TimeUnit object SyncUtil { @@ -71,11 +70,10 @@ object SyncUtil { //Gogoanime, Twistmoe and 9anime val url = "https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/pages/$site/$slug.json" - val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).text() - val mapped = parseJson(response) + val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).parsed() - val overrideMal = mapped?.malId ?: mapped?.mal?.id ?: mapped?.anilist?.malId - val overrideAnilist = mapped?.aniId ?: mapped?.anilist?.id + val overrideMal = response?.malId ?: response?.mal?.id ?: response?.anilist?.malId + val overrideAnilist = response?.aniId ?: response?.anilist?.id if (overrideMal != null) { return overrideMal.toString() to overrideAnilist?.toString() @@ -176,4 +174,4 @@ object SyncUtil { @SerialName("updatedAt") val updatedAt: String?, @SerialName("deletedAt") val deletedAt: String? ) -} \ No newline at end of file +} From 656477c2df78528fadfbfe7f5ab85bc413d17823 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 14:41:34 -0600 Subject: [PATCH 045/192] Fix --- app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt index 7243e5823b5..a64b2e56fdd 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt @@ -70,7 +70,7 @@ object SyncUtil { //Gogoanime, Twistmoe and 9anime val url = "https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/pages/$site/$slug.json" - val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).parsed() + val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).parsed() val overrideMal = response?.malId ?: response?.mal?.id ?: response?.anilist?.malId val overrideAnilist = response?.aniId ?: response?.anilist?.id From fda28863de979a54b6fea344044637d9c706cf3f Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 15:10:39 -0600 Subject: [PATCH 046/192] Fix --- .../lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt | 2 +- .../java/com/lagradost/cloudstream3/plugins/PluginManager.kt | 2 +- .../com/lagradost/cloudstream3/plugins/RepositoryManager.kt | 2 +- .../lagradost/cloudstream3/syncproviders/providers/SimklApi.kt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt index a89d506c1a0..46a0d6158d2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt @@ -101,7 +101,7 @@ class CloudStreamPackage : OpenInAppAction( } } - + @Serializable data class MinimalSubtitleLink( @SerialName("url") val url: String, diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt index a8d3ee103d6..cd2fc7bf8a7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/PluginManager.kt @@ -612,7 +612,7 @@ object PluginManager { return false } InputStreamReader(stream).use { reader -> - manifest = parseJson(reader, BasePlugin.Manifest::class.java) + manifest = parseJson(reader.readText()) } } diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt index ba149f79a5f..6eae658c099 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt @@ -47,7 +47,7 @@ data class Repository( * 2: Slow * 3: Beta only * */ - @Serializable +@Serializable data class SitePlugin( // Url to the .cs3 file @SerialName("url") val url: String, diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 5b3e3e24b4e..c22122d331e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -238,7 +238,7 @@ class SimklApi : SyncAPI() { @SerialName("account") val account: Account, ) { - @Serializable + @Serializable data class User( @SerialName("name") val name: String, From b49ca7a7f68a6c9fa4fa36c586c140419ea4bcff Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 15:22:59 -0600 Subject: [PATCH 047/192] Fix --- .../main/java/com/lagradost/cloudstream3/utils/DataStore.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 2adb9141acf..81f5ba96ee5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -121,13 +121,14 @@ object DataStore { } @InternalAPI + @Suppress("UNCHECKED_CAST") fun anyToJsonString(obj: Any): String { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases - val serializer = obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class) + val serializer = (obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class)) as? KSerializer return if (serializer != null) { try { - json.encodeToString(JsonElement.serializer(), json.parseToJsonElement(obj.toString())) + json.encodeToString(serializer, obj) } catch (_: Exception) { mapper.writeValueAsString(obj) } From 9cef364c42723048a828a114e909b1e1d78b07ea Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 15:25:43 -0600 Subject: [PATCH 048/192] Fix --- app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 81f5ba96ee5..014297ec97e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -13,6 +13,7 @@ import com.lagradost.cloudstream3.InternalAPI import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.serializer From a1faeb4f6bce303555394eed69e272ee3845fa7f Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 15:37:18 -0600 Subject: [PATCH 049/192] Try fix --- .../main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index 2c59c5d9647..d5306cd99fb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -22,6 +22,7 @@ import com.lagradost.cloudstream3.syncproviders.AccountManager import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.ANILIST_CACHED_LIST import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_CACHED_LIST import com.lagradost.cloudstream3.syncproviders.providers.KitsuApi.Companion.KITSU_CACHED_LIST +import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.DataStore.getDefaultSharedPrefs @@ -262,8 +263,7 @@ object BackupUtils { val input = activity.contentResolver.openInputStream(uri) ?: return@ioSafe - val restoredValue = - mapper.readValue(input) + val restoredValue = parseJson(input) restore( activity, From a0aeb13e8b4eb258058fff1f525d425b70401aa0 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 15:41:36 -0600 Subject: [PATCH 050/192] Fix --- .../main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index d5306cd99fb..841853b94a1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -263,7 +263,8 @@ object BackupUtils { val input = activity.contentResolver.openInputStream(uri) ?: return@ioSafe - val restoredValue = parseJson(input) + val text = input.bufferedReader().readText() + val restoredValue = parseJson(text) restore( activity, From 0f3e2e336b36b6e3f01d7e9c04ef6e4a270eb09f Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 15:49:30 -0600 Subject: [PATCH 051/192] - --- .../java/com/lagradost/cloudstream3/utils/DataStore.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 014297ec97e..a548758e199 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -13,7 +13,6 @@ import com.lagradost.cloudstream3.InternalAPI import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi -import kotlinx.serialization.KSerializer import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonElement import kotlinx.serialization.serializer @@ -121,15 +120,13 @@ object DataStore { } } - @InternalAPI - @Suppress("UNCHECKED_CAST") - fun anyToJsonString(obj: Any): String { + private fun anyToJsonString(obj: Any): String { // @Serializable generates a serializer at compile time; contextual serializers are // registered manually in serializersModule, we need both to support all cases - val serializer = (obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class)) as? KSerializer + val serializer = obj::class.serializerOrNull() ?: json.serializersModule.getContextual(obj::class) return if (serializer != null) { try { - json.encodeToString(serializer, obj) + json.encodeToString(JsonElement.serializer(), json.parseToJsonElement(obj.toString())) } catch (_: Exception) { mapper.writeValueAsString(obj) } From 58244ecd40d3fb204ca7fdf4634eae1d8cde569a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 14 May 2026 17:37:25 -0600 Subject: [PATCH 052/192] Fix --- .../java/com/lagradost/cloudstream3/utils/BackupUtils.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index 841853b94a1..a57fd87b524 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -23,6 +23,7 @@ import com.lagradost.cloudstream3.syncproviders.providers.AniListApi.Companion.A import com.lagradost.cloudstream3.syncproviders.providers.MALApi.Companion.MAL_CACHED_LIST import com.lagradost.cloudstream3.syncproviders.providers.KitsuApi.Companion.KITSU_CACHED_LIST import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.Coroutines.ioSafe import com.lagradost.cloudstream3.utils.Coroutines.main import com.lagradost.cloudstream3.utils.DataStore.getDefaultSharedPrefs @@ -137,9 +138,7 @@ object BackupUtils { ) @Suppress("UNCHECKED_CAST") - private fun getBackup(context: Context?): BackupFile? { - if (context == null) return null - + private fun getBackup(context: Context): BackupFile { val allData = context.getSharedPrefs().all.filter { it.key.isTransferable() } val allSettings = context.getDefaultSharedPrefs().all.filter { it.key.isTransferable() } @@ -218,7 +217,7 @@ object BackupUtils { fileStream = stream.openNew() printStream = PrintWriter(fileStream) - printStream.print(mapper.writeValueAsString(backupFile)) + printStream.print(backupFile.toJson()) showToast( R.string.backup_success, From 56bbf25a6f68b5f05ae72e52bf85326413e1e676 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Fri, 15 May 2026 17:58:34 -0600 Subject: [PATCH 053/192] Support --- .../cloudstream3/syncproviders/providers/SimklApi.kt | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index c22122d331e..998f66c0da4 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -18,7 +18,6 @@ import com.lagradost.cloudstream3.Score import com.lagradost.cloudstream3.SimklSyncServices import com.lagradost.cloudstream3.TvType import com.lagradost.cloudstream3.app -import com.lagradost.cloudstream3.mapper import com.lagradost.cloudstream3.mvvm.debugPrint import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING @@ -32,6 +31,7 @@ import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.ui.SyncWatchType import com.lagradost.cloudstream3.ui.library.ListSorting import com.lagradost.cloudstream3.utils.AppUtils.toJson +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJso import com.lagradost.cloudstream3.utils.DataStoreHelper.toYear import com.lagradost.cloudstream3.utils.txt import java.math.BigInteger @@ -121,12 +121,8 @@ class SimklApi : SyncAPI() { */ inline fun getKey(path: String): T? { // Required for generic otherwise "LinkedHashMap cannot be cast to MediaObject" - val type = mapper.typeFactory.constructParametricType( - SimklCacheWrapper::class.java, - T::class.java - ) val cache = getKey(SIMKL_CACHE_KEY, path)?.let { - mapper.readValue>(it, type) + tryParseJson>(it) } return if (cache?.isFresh() == true) { From 63dc8e26cbd4e8726ee15cbaa8dcc69a058afddd Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Fri, 15 May 2026 17:59:15 -0600 Subject: [PATCH 054/192] Fix --- .../lagradost/cloudstream3/syncproviders/providers/SimklApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index 998f66c0da4..f886126ddbe 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -31,7 +31,7 @@ import com.lagradost.cloudstream3.syncproviders.SyncIdName import com.lagradost.cloudstream3.ui.SyncWatchType import com.lagradost.cloudstream3.ui.library.ListSorting import com.lagradost.cloudstream3.utils.AppUtils.toJson -import com.lagradost.cloudstream3.utils.AppUtils.tryParseJso +import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.DataStoreHelper.toYear import com.lagradost.cloudstream3.utils.txt import java.math.BigInteger From 4ed9d0140258f22facac15196cac6492b4c53a03 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:14:06 -0600 Subject: [PATCH 055/192] Update --- .../lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt index 46a0d6158d2..665000f5679 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/actions/temp/CloudStreamPackage.kt @@ -23,7 +23,7 @@ import com.lagradost.cloudstream3.utils.newExtractorLink import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.SubtitleHelper.fromCodeToLangTagIETF import com.lagradost.cloudstream3.utils.SubtitleHelper.fromLanguageToTagIETF -import com.lagradost.cloudstream3.utils.serializer.UriSerializer +import com.lagradost.cloudstream3.utils.serializers.UriSerializer import com.lagradost.cloudstream3.utils.txt /** From 3625dd3a644d27c4b88406214fe9644667aae8dc Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:14:36 -0600 Subject: [PATCH 056/192] Update --- .../lagradost/cloudstream3/utils/downloader/DownloadObjects.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt index 4343c587e63..10ffd530a5f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/downloader/DownloadObjects.kt @@ -10,7 +10,7 @@ import com.lagradost.cloudstream3.services.DownloadQueueService import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.serializer.UriSerializer +import com.lagradost.cloudstream3.utils.serializers.UriSerializer import com.lagradost.safefile.SafeFile import java.io.IOException import java.io.OutputStream From 5e052cc4b2b17619a2ffdd66fb5e0604668d0f4e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:15:25 -0600 Subject: [PATCH 057/192] - --- .../utils/ serializer/UriSerializer.kt | 22 ------------------- 1 file changed, 22 deletions(-) delete mode 100644 app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt deleted file mode 100644 index ec069af037a..00000000000 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/ serializer/UriSerializer.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializer - -import android.net.Uri -import kotlinx.serialization.KSerializer -import kotlinx.serialization.descriptors.PrimitiveKind -import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor -import kotlinx.serialization.descriptors.SerialDescriptor -import kotlinx.serialization.encoding.Decoder -import kotlinx.serialization.encoding.Encoder - -object UriSerializer : KSerializer { - override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("Uri", PrimitiveKind.STRING) - - override fun serialize(encoder: Encoder, value: Uri) { - encoder.encodeString(value.toString()) - } - - override fun deserialize(decoder: Decoder): Uri { - return Uri.parse(decoder.decodeString()) - } -} From 07a0231e98b286d23b8c1e71ee80e6041ed64384 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:19:50 -0600 Subject: [PATCH 058/192] - --- app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 0c3f239120e..02ee697911f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -7,7 +7,6 @@ import androidx.preference.PreferenceManager import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKeyClass import com.lagradost.cloudstream3.CloudStreamApp.Companion.removeKey import com.lagradost.cloudstream3.CloudStreamApp.Companion.setKeyClass -import com.lagradost.cloudstream3.InternalAPI import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJsonLiteral @@ -87,7 +86,6 @@ data class Editor( } } -@OptIn(ExperimentalSerializationApi::class, InternalSerializationApi::class) object DataStore { // Extensions shouldn't have really been using this version of it, but it seems // some have. Since there has always been a very easy alternative, we won't From d3e7e671bc18dc4b6b1f59150491c614a3a7b01a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Jun 2026 12:58:51 -0600 Subject: [PATCH 059/192] Fix --- .../main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt index f9787e57a71..1f5a08d40a1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt @@ -74,8 +74,8 @@ object SyncUtil { val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).text() val mapped = tryParseJson(response) - val overrideMal = response?.malId ?: response?.mal?.id ?: response?.anilist?.malId - val overrideAnilist = response?.aniId ?: response?.anilist?.id + val overrideMal = mapped?.malId ?: mapped?.mal?.id ?: mapped?.anilist?.malId + val overrideAnilist = mapped?.aniId ?: mapped?.anilist?.id if (overrideMal != null) { return overrideMal.toString() to overrideAnilist?.toString() From 15a3ce163f14f72a1674e81cb5bd4099a8b1f56d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:19:41 -0600 Subject: [PATCH 060/192] Update --- .../syncproviders/providers/AniListApi.kt | 64 ++++++++++--------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 9aed46a48b4..7e847ebd214 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -1,8 +1,6 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.ActorData import com.lagradost.cloudstream3.ActorRole @@ -29,6 +27,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.DataStoreHelper.toYear import com.lagradost.cloudstream3.utils.txt +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import java.net.URLEncoder import java.util.Locale @@ -271,7 +271,7 @@ class AniListApi : SyncAPI() { //headers = mapOf(), data = data,//(if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) timeout = 5000 // REASONABLE TIMEOUT - ).text().replace("\\", "") + ).text.replace("\\", "") return res.toKotlinObject() } catch (e: Exception) { logError(e) @@ -454,9 +454,9 @@ class AniListApi : SyncAPI() { "https://graphql.anilist.co", data = mapOf("query" to q), cacheTime = 0, - ).text() + ).text - return tryParseJson(data) ?: throw ErrorLoadingException("Error parsing $data") + return tryParseJson(data) ?: throw ErrorLoadingException("Error parsing $data") } } @@ -522,7 +522,7 @@ class AniListApi : SyncAPI() { ) ), //(if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) timeout = 5 // REASONABLE TIMEOUT - ).text().replace("\\/", "/") + ).text.replace("\\/", "/") } @@ -532,39 +532,39 @@ class AniListApi : SyncAPI() { @SerialName("title") val title: Title?, @SerialName("idMal") val idMal: Int?, @SerialName("coverImage") val coverImage: CoverImage?, - @SerialName("averageScore") val averageScore: Int? + @SerialName("averageScore") val averageScore: Int?, ) @Serializable data class FullAnilistList( - @SerialName("data") val data: Data? + @SerialName("data") val data: Data?, ) @Serializable data class CompletedAt( @SerialName("year") val year: Int, @SerialName("month") val month: Int, - @SerialName("day") val day: Int + @SerialName("day") val day: Int, ) @Serializable data class StartedAt( @SerialName("year") val year: String?, @SerialName("month") val month: String?, - @SerialName("day") val day: String? + @SerialName("day") val day: String?, ) @Serializable data class Title( @SerialName("english") val english: String?, - @SerialName("romaji") val romaji: String? + @SerialName("romaji") val romaji: String?, ) @Serializable data class CoverImage( @SerialName("medium") val medium: String?, @SerialName("large") val large: String?, - @SerialName("extraLarge") val extraLarge: String? + @SerialName("extraLarge") val extraLarge: String?, ) @Serializable @@ -574,7 +574,6 @@ class AniListApi : SyncAPI() { @SerialName("season") val season: String?, @SerialName("seasonYear") val seasonYear: Int, @SerialName("format") val format: String?, - //@SerialName("source") val source: String, @SerialName("episodes") val episodes: Int, @SerialName("title") val title: Title, @SerialName("description") val description: String?, @@ -592,7 +591,7 @@ class AniListApi : SyncAPI() { @SerialName("progress") val progress: Int, @SerialName("score") val score: Int, @SerialName("private") val private: Boolean, - @SerialName("media") val media: Media + @SerialName("media") val media: Media, ) { fun toLibraryItem(): SyncAPI.LibraryItem { return SyncAPI.LibraryItem( @@ -622,17 +621,17 @@ class AniListApi : SyncAPI() { @Serializable data class Lists( @SerialName("status") val status: String?, - @SerialName("entries") val entries: List + @SerialName("entries") val entries: List, ) @Serializable data class MediaListCollection( - @SerialName("lists") val lists: List + @SerialName("lists") val lists: List, ) @Serializable data class Data( - @SerialName("MediaListCollection") val mediaListCollection: MediaListCollection + @SerialName("MediaListCollection") val mediaListCollection: MediaListCollection, ) private suspend fun getAniListAnimeListSmart(auth: AuthData): Array? { @@ -745,11 +744,19 @@ class AniListApi : SyncAPI() { /** Used to query a saved MediaItem on the list to get the id for removal */ @Serializable - data class MediaListItemRoot(@SerialName("data") val data: MediaListItem? = null) + data class MediaListItemRoot( + @SerialName("data") val data: MediaListItem? = null, + ) + @Serializable - data class MediaListItem(@SerialName("MediaList") val mediaList: MediaListId? = null) + data class MediaListItem( + @SerialName("MediaList") val mediaList: MediaListId? = null, + ) + @Serializable - data class MediaListId(@SerialName("id") val id: Long? = null) + data class MediaListId( + @SerialName("id") val id: Long? = null, + ) private suspend fun postDataAboutId( auth : AuthData, @@ -886,18 +893,16 @@ class AniListApi : SyncAPI() { data class RecommendationConnection( @SerialName("edges") val edges: List = emptyList(), @SerialName("nodes") val nodes: List = emptyList(), - //@SerialName("pageInfo") val pageInfo: PageInfo, ) @Serializable data class RecommendationEdge( - //@SerialName("rating") val rating: Int, @SerialName("node") val node: Recommendation, ) @Serializable data class Recommendation( - val id: Long, + @SerialName("id") val id: Long, @SerialName("mediaRecommendation") val mediaRecommendation: SeasonMedia?, ) @@ -975,7 +980,6 @@ class AniListApi : SyncAPI() { data class CharacterConnection( @SerialName("edges") val edges: List?, @SerialName("nodes") val nodes: List?, - //@SerialName("pageInfo") pageInfo: PageInfo ) @Serializable @@ -1036,8 +1040,7 @@ class AniListApi : SyncAPI() { @SerialName("title") val title: Title?, @SerialName("idMal") val idMal: Int?, @SerialName("coverImage") val coverImage: CoverImage?, - @SerialName("averageScore") val averageScore: Int? -// @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @SerialName("averageScore") val averageScore: Int?, ) @Serializable @@ -1073,7 +1076,6 @@ class AniListApi : SyncAPI() { @Serializable data class LikeNode( @SerialName("id") val id: Int?, - //@SerialName("idMal") public int idMal; ) @Serializable @@ -1132,7 +1134,7 @@ class AniListApi : SyncAPI() { @Serializable data class Nodes( @SerialName("id") val id: Int?, - @SerialName("mediaRecommendation") val mediaRecommendation: MediaRecommendation? + @SerialName("mediaRecommendation") val mediaRecommendation: MediaRecommendation?, ) @Serializable @@ -1140,12 +1142,12 @@ class AniListApi : SyncAPI() { @SerialName("isFavourite") val isFavourite: Boolean?, @SerialName("episodes") val episodes: Int?, @SerialName("title") val title: Title?, - @SerialName("mediaListEntry") val mediaListEntry: GetDataMediaListEntry? + @SerialName("mediaListEntry") val mediaListEntry: GetDataMediaListEntry?, ) @Serializable data class Recommendations( - @SerialName("nodes") val nodes: List? + @SerialName("nodes") val nodes: List?, ) @Serializable @@ -1183,7 +1185,7 @@ class AniListApi : SyncAPI() { @SerialName("trailer") val trailer: TrailerObject?, @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, @SerialName("recommendations") val recommendations: Recommendations?, - @SerialName("relations") val relations: SeasonEdges? + @SerialName("relations") val relations: SeasonEdges?, ) @Serializable From 5ba22da792673889b1b1d87a9914871b65bf5239 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:37:45 -0600 Subject: [PATCH 061/192] Update --- .../syncproviders/providers/AniListApi.kt | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 7e847ebd214..a26739ee5f5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -258,12 +258,11 @@ class AniListApi : SyncAPI() { val data = mapOf( "query" to query, - "variables" to - mapOf( - "search" to name, - "page" to 1, - "type" to "ANIME" - ).toJson() + "variables" to Variables( + search = name, + page = 1, + type = "ANIME", + ).toJson() ) val res = app.post( @@ -272,7 +271,7 @@ class AniListApi : SyncAPI() { data = data,//(if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) timeout = 5000 // REASONABLE TIMEOUT ).text.replace("\\", "") - return res.toKotlinObject() + return parseJson(res) } catch (e: Exception) { logError(e) } @@ -525,6 +524,12 @@ class AniListApi : SyncAPI() { ).text.replace("\\/", "/") } + @Serializable + data class Variables( + @SerialName("search") val search: String, + @SerialName("page") val page: Int, + @SerialName("type") val type: String, + ) @Serializable data class MediaRecommendation( From d9617ac8489e354172efadaecd7e7dcaf180b58b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:42:46 -0600 Subject: [PATCH 062/192] Update --- .../cloudstream3/syncproviders/providers/AniListApi.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index a26739ee5f5..118e361b1cc 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -24,7 +24,6 @@ import com.lagradost.cloudstream3.ui.library.ListSorting import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson -import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.DataStoreHelper.toYear import com.lagradost.cloudstream3.utils.txt import kotlinx.serialization.SerialName @@ -727,7 +726,7 @@ class AniListApi : SyncAPI() { } """ val text = postApi(auth.token, query) - return text?.toKotlinObject() + return tryParseJson(text) } suspend fun toggleLike(auth : AuthData, id: Int): Boolean { From 03056dac4fa36413796d21f1d5916f9d7cf1a6f4 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 11:54:59 -0600 Subject: [PATCH 063/192] Test --- .../lagradost/cloudstream3/utils/AppUtils.kt | 53 ++++--------------- 1 file changed, 9 insertions(+), 44 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index 50e9cf791f5..bba4b5d5152 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -1,9 +1,7 @@ package com.lagradost.cloudstream3.utils -import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.InternalAPI import com.lagradost.cloudstream3.json -import com.lagradost.cloudstream3.mapper import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi @@ -24,56 +22,24 @@ object AppUtils { /** Sometimes we want to encode as JSON even if it is already a String. */ @InternalAPI fun Any.toJsonLiteral(): String { - // @Serializable generates a serializer at compile time; contextual serializers are - // registered manually in serializersModule, we need both to support all cases val serializer = this::class.serializerOrNull() ?: json.serializersModule.getContextual(this::class) - return if (serializer != null) { - try { - @Suppress("UNCHECKED_CAST") - json.encodeToString(serializer as KSerializer, this) - } catch (e: SerializationException) { - logError(e) - mapper.writeValueAsString(this) - } - } else { - mapper.writeValueAsString(this) - } + @Suppress("UNCHECKED_CAST") + return json.encodeToString(serializer as KSerializer, this) } @InternalAPI fun parseJson(value: String, kClass: KClass): T { val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) - if (serializer != null) { - try { - return json.decodeFromString(serializer, value) - } catch (e: SerializationException) { - logError(e) - } - } - - return mapper.readValue(value, kClass.java) + ?: error("No serializer found for ${kClass.simpleName}") + return json.decodeFromString(serializer, value) } - // This is inlined code and can easily cause breakage in extensions! - // Watch out when editing this to make sure stable also supports all inlined code! inline fun parseJson(value: String): T { - // @Serializable generates a serializer at compile time; contextual serializers are - // registered manually in serializersModule, we need both to support all cases - val serializer = runCatching { serializer() }.runCatching { - json.serializersModule.getContextual(T::class) - }.getOrNull() - - // Prefer Kotlin Serialization over Jackson - if (serializer != null) { - try { - return json.decodeFromString(serializer, value) - } catch (e: SerializationException) { - logError(e) - } - } - - return mapper.readValue(value) + val serializer = runCatching { serializer() }.getOrNull() + ?: json.serializersModule.getContextual(T::class) + ?: error("No serializer found for ${T::class.simpleName}") + return json.decodeFromString(serializer, value) } @Deprecated( @@ -83,8 +49,7 @@ object AppUtils { replaceWith = ReplaceWith("parseJson(reader.readText())") ) inline fun parseJson(reader: java.io.Reader, valueType: Class): T { - // Reader-based parsing has no kotlinx equivalent, fall back to Jackson - return mapper.readValue(reader, valueType) + throw UnsupportedOperationException("Jackson removed. Use parseJson(reader.readText()) instead.") } inline fun tryParseJson(value: String?): T? { From 593aca5ca872ed223613de0c4f7fc368106f173b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 12:06:15 -0600 Subject: [PATCH 064/192] Fix --- .../com/lagradost/cloudstream3/plugins/RepositoryManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt index 6eae658c099..b67d3800d5e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/plugins/RepositoryManager.kt @@ -137,7 +137,7 @@ object RepositoryManager { suspend fun parseRepository(url: String): Repository? { return safeAsync { // Take manifestVersion and such into account later - app.get(convertRawGitUrl(url)).parsedSafe() + app.get(convertRawGitUrl(url)).parsedSafe() } } From d8cb28aaffe69757cd0851bad66b6477fa968126 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 12:12:06 -0600 Subject: [PATCH 065/192] Update --- .../kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index bba4b5d5152..a7aefa37b09 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -55,7 +55,8 @@ object AppUtils { inline fun tryParseJson(value: String?): T? { return try { parseJson(value ?: return null) - } catch (_: Exception) { + } catch (e: Exception) { + logError(e) null } } From b2425bd1e130cca095088afa7c8e06a296ea8eb9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 12:22:45 -0600 Subject: [PATCH 066/192] Try --- .../kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index a7aefa37b09..1f3f2a3e652 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -24,8 +24,12 @@ object AppUtils { fun Any.toJsonLiteral(): String { val serializer = this::class.serializerOrNull() ?: json.serializersModule.getContextual(this::class) - @Suppress("UNCHECKED_CAST") - return json.encodeToString(serializer as KSerializer, this) + return if (serializer != null) { + @Suppress("UNCHECKED_CAST") + json.encodeToString(serializer as KSerializer, this) + } else { + json.encodeToString(kotlinx.serialization.json.JsonElement.serializer(), json.encodeToJsonElement(kotlinx.serialization.json.JsonElement.serializer(), this as kotlinx.serialization.json.JsonElement)) + } } @InternalAPI From 24b064daa65caaceddf12f88daae571b89c9d55b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 13:19:46 -0600 Subject: [PATCH 067/192] explicitNulls = false test --- .../src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 1751f4b4325..7f28d1d9684 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -90,6 +90,7 @@ class ErrorLoadingException(message: String? = null) : Exception(message) @Prerelease val json = Json { encodeDefaults = true + explicitNulls = false ignoreUnknownKeys = true } From 77890575afcef41af12c616cf6ddb4a359e2ed12 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 13:50:10 -0600 Subject: [PATCH 068/192] Try some changes --- .../lagradost/cloudstream3/utils/AppUtils.kt | 36 ++++++++++++++++--- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index 1f3f2a3e652..9ba6dd27dba 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -6,7 +6,10 @@ import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.KSerializer -import kotlinx.serialization.SerializationException +import kotlinx.serialization.builtins.ListSerializer +import kotlinx.serialization.builtins.MapSerializer +import kotlinx.serialization.builtins.SetSerializer +import kotlinx.serialization.builtins.serializer import kotlinx.serialization.serializer import kotlinx.serialization.serializerOrNull import kotlin.reflect.KClass @@ -24,12 +27,35 @@ object AppUtils { fun Any.toJsonLiteral(): String { val serializer = this::class.serializerOrNull() ?: json.serializersModule.getContextual(this::class) - return if (serializer != null) { + if (serializer != null) { @Suppress("UNCHECKED_CAST") - json.encodeToString(serializer as KSerializer, this) - } else { - json.encodeToString(kotlinx.serialization.json.JsonElement.serializer(), json.encodeToJsonElement(kotlinx.serialization.json.JsonElement.serializer(), this as kotlinx.serialization.json.JsonElement)) + return json.encodeToString(serializer as KSerializer, this) } + return when (this) { + is Set<*> -> json.encodeToString(SetSerializer(elementSerializer()), this as Set) + is List<*> -> json.encodeToString(ListSerializer(elementSerializer()), this as List) + is Collection<*> -> json.encodeToString(ListSerializer(elementSerializer()), this.toList() as List) + is Map<*, *> -> json.encodeToString(MapSerializer(String.serializer(), valueSerializer()), this as Map) + else -> error("No serializer found for ${this::class.simpleName}") + } + } + + @Suppress("UNCHECKED_CAST") + private fun elementSerializerForClass(kClass: KClass<*>): KSerializer { + val serializer = kClass.serializerOrNull() + ?: json.serializersModule.getContextual(kClass) + ?: error("No serializer found for element type ${kClass.simpleName}") + return serializer as KSerializer + } + + private fun Collection<*>.elementSerializer(): KSerializer { + val elementClass = this.firstOrNull()?.let { it::class } ?: String::class + return elementSerializerForClass(elementClass) + } + + private fun Map<*, *>.valueSerializer(): KSerializer { + val elementClass = this.values.firstOrNull()?.let { it::class } ?: String::class + return elementSerializerForClass(elementClass) } @InternalAPI From 8b9a62b0340911f6d709c726a7dce87f69dae883 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 13:58:47 -0600 Subject: [PATCH 069/192] Add Array --- .../kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index 9ba6dd27dba..ceda79d5bac 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -32,6 +32,7 @@ object AppUtils { return json.encodeToString(serializer as KSerializer, this) } return when (this) { + is Array<*> -> json.encodeToString(ListSerializer(elementSerializer()), this.toList() as List) is Set<*> -> json.encodeToString(SetSerializer(elementSerializer()), this as Set) is List<*> -> json.encodeToString(ListSerializer(elementSerializer()), this as List) is Collection<*> -> json.encodeToString(ListSerializer(elementSerializer()), this.toList() as List) @@ -53,6 +54,11 @@ object AppUtils { return elementSerializerForClass(elementClass) } + private fun Array<*>.elementSerializer(): KSerializer { + val elementClass = this.firstOrNull()?.let { it::class } ?: String::class + return elementSerializerForClass(elementClass) + } + private fun Map<*, *>.valueSerializer(): KSerializer { val elementClass = this.values.firstOrNull()?.let { it::class } ?: String::class return elementSerializerForClass(elementClass) From 6c46bce72d836abaddda58590beb90a5ecb6e799 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 14:50:24 -0600 Subject: [PATCH 070/192] Support mixed types --- .../lagradost/cloudstream3/utils/AppUtils.kt | 92 +++++++++++-------- 1 file changed, 54 insertions(+), 38 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index ceda79d5bac..1593dccba73 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -6,10 +6,12 @@ import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.ListSerializer -import kotlinx.serialization.builtins.MapSerializer -import kotlinx.serialization.builtins.SetSerializer -import kotlinx.serialization.builtins.serializer +import kotlinx.serialization.SerializationException +import kotlinx.serialization.json.JsonArray +import kotlinx.serialization.json.JsonElement +import kotlinx.serialization.json.JsonNull +import kotlinx.serialization.json.JsonObject +import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.serializer import kotlinx.serialization.serializerOrNull import kotlin.reflect.KClass @@ -25,56 +27,70 @@ object AppUtils { /** Sometimes we want to encode as JSON even if it is already a String. */ @InternalAPI fun Any.toJsonLiteral(): String { + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases val serializer = this::class.serializerOrNull() ?: json.serializersModule.getContextual(this::class) if (serializer != null) { - @Suppress("UNCHECKED_CAST") - return json.encodeToString(serializer as KSerializer, this) + try { + @Suppress("UNCHECKED_CAST") + return json.encodeToString(serializer as KSerializer, this) + } catch (e: SerializationException) { + logError(e) + } } - return when (this) { - is Array<*> -> json.encodeToString(ListSerializer(elementSerializer()), this.toList() as List) - is Set<*> -> json.encodeToString(SetSerializer(elementSerializer()), this as Set) - is List<*> -> json.encodeToString(ListSerializer(elementSerializer()), this as List) - is Collection<*> -> json.encodeToString(ListSerializer(elementSerializer()), this.toList() as List) - is Map<*, *> -> json.encodeToString(MapSerializer(String.serializer(), valueSerializer()), this as Map) - else -> error("No serializer found for ${this::class.simpleName}") - } - } - - @Suppress("UNCHECKED_CAST") - private fun elementSerializerForClass(kClass: KClass<*>): KSerializer { - val serializer = kClass.serializerOrNull() - ?: json.serializersModule.getContextual(kClass) - ?: error("No serializer found for element type ${kClass.simpleName}") - return serializer as KSerializer - } - - private fun Collection<*>.elementSerializer(): KSerializer { - val elementClass = this.firstOrNull()?.let { it::class } ?: String::class - return elementSerializerForClass(elementClass) + // Handle generic collection/map types where type params are erased at runtime. + // Convert to JsonElement to support mixed types within collections. + return json.encodeToString(JsonElement.serializer(), toJsonElement()) } - private fun Array<*>.elementSerializer(): KSerializer { - val elementClass = this.firstOrNull()?.let { it::class } ?: String::class - return elementSerializerForClass(elementClass) - } - - private fun Map<*, *>.valueSerializer(): KSerializer { - val elementClass = this.values.firstOrNull()?.let { it::class } ?: String::class - return elementSerializerForClass(elementClass) + /** + * Recursively converts any value to a [JsonElement], supporting mixed-type + * collections, nested maps, nulls, primitives, and @Serializable objects. + */ + fun Any?.toJsonElement(): JsonElement { + if (this == null) return JsonNull + // Try kotlinx serializer first (handles @Serializable and primitives) + val serializer = this::class.serializerOrNull() + ?: json.serializersModule.getContextual(this::class) + if (serializer != null) { + try { + @Suppress("UNCHECKED_CAST") + return json.encodeToJsonElement(serializer as KSerializer, this) + } catch (_: SerializationException) { + // fall through to manual handling + } + } + return when (this) { + is Boolean -> JsonPrimitive(this) + is Number -> JsonPrimitive(this) + is String -> JsonPrimitive(this) + is Enum<*> -> JsonPrimitive(this.name) + is Array<*> -> JsonArray(this.map { it.toJsonElement() }) + is Collection<*> -> JsonArray(this.map { it.toJsonElement() }) + is Map<*, *> -> JsonObject(this.entries.associate { (k, v) -> + k.toString() to v.toJsonElement() + }) + else -> throw SerializationException("No serializer found for ${this::class.simpleName}") + } } @InternalAPI fun parseJson(value: String, kClass: KClass): T { - val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) - ?: error("No serializer found for ${kClass.simpleName}") + val serializer = kClass.serializerOrNull() + ?: json.serializersModule.getContextual(kClass) + ?: throw SerializationException("No serializer found for ${kClass.simpleName}") return json.decodeFromString(serializer, value) } + // This is inlined code and can easily cause breakage in extensions! + // Watch out when editing this to make sure stable also supports all inlined code! inline fun parseJson(value: String): T { + // @Serializable generates a serializer at compile time; contextual serializers are + // registered manually in serializersModule, we need both to support all cases val serializer = runCatching { serializer() }.getOrNull() ?: json.serializersModule.getContextual(T::class) - ?: error("No serializer found for ${T::class.simpleName}") + ?: throw SerializationException("No serializer found for ${T::class.simpleName}") return json.decodeFromString(serializer, value) } From 9a3acdaa7404f898b037940f6e4fdd1bc6632363 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:00:20 -0600 Subject: [PATCH 071/192] Try fallback --- .../lagradost/cloudstream3/utils/AppUtils.kt | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt index 1593dccba73..a8a3ca47514 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/AppUtils.kt @@ -1,7 +1,9 @@ package com.lagradost.cloudstream3.utils +import com.fasterxml.jackson.module.kotlin.readValue import com.lagradost.cloudstream3.InternalAPI import com.lagradost.cloudstream3.json +import com.lagradost.cloudstream3.mapper import com.lagradost.cloudstream3.mvvm.logError import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.InternalSerializationApi @@ -37,18 +39,24 @@ object AppUtils { return json.encodeToString(serializer as KSerializer, this) } catch (e: SerializationException) { logError(e) + return mapper.writeValueAsString(this) } } // Handle generic collection/map types where type params are erased at runtime. // Convert to JsonElement to support mixed types within collections. - return json.encodeToString(JsonElement.serializer(), toJsonElement()) + return try { + json.encodeToString(JsonElement.serializer(), toJsonElement()) + } catch (e: SerializationException) { + logError(e) + mapper.writeValueAsString(this) + } } /** * Recursively converts any value to a [JsonElement], supporting mixed-type * collections, nested maps, nulls, primitives, and @Serializable objects. */ - fun Any?.toJsonElement(): JsonElement { + private fun Any?.toJsonElement(): JsonElement { if (this == null) return JsonNull // Try kotlinx serializer first (handles @Serializable and primitives) val serializer = this::class.serializerOrNull() @@ -77,10 +85,16 @@ object AppUtils { @InternalAPI fun parseJson(value: String, kClass: KClass): T { - val serializer = kClass.serializerOrNull() - ?: json.serializersModule.getContextual(kClass) - ?: throw SerializationException("No serializer found for ${kClass.simpleName}") - return json.decodeFromString(serializer, value) + val serializer = kClass.serializerOrNull() ?: json.serializersModule.getContextual(kClass) + if (serializer != null) { + try { + return json.decodeFromString(serializer, value) + } catch (e: SerializationException) { + logError(e) + } + } + + return mapper.readValue(value, kClass.java) } // This is inlined code and can easily cause breakage in extensions! @@ -90,8 +104,17 @@ object AppUtils { // registered manually in serializersModule, we need both to support all cases val serializer = runCatching { serializer() }.getOrNull() ?: json.serializersModule.getContextual(T::class) - ?: throw SerializationException("No serializer found for ${T::class.simpleName}") - return json.decodeFromString(serializer, value) + + // Prefer Kotlin Serialization over Jackson + if (serializer != null) { + try { + return json.decodeFromString(serializer, value) + } catch (e: SerializationException) { + logError(e) + } + } + + return mapper.readValue(value) } @Deprecated( @@ -101,14 +124,14 @@ object AppUtils { replaceWith = ReplaceWith("parseJson(reader.readText())") ) inline fun parseJson(reader: java.io.Reader, valueType: Class): T { - throw UnsupportedOperationException("Jackson removed. Use parseJson(reader.readText()) instead.") + // Reader-based parsing has no kotlinx equivalent, fall back to Jackson + return mapper.readValue(reader, valueType) } inline fun tryParseJson(value: String?): T? { return try { parseJson(value ?: return null) - } catch (e: Exception) { - logError(e) + } catch (_: Exception) { null } } From 6413d4ee70868663b9347e3253621b92d9b7ebbe Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:17:51 -0600 Subject: [PATCH 072/192] test --- .../src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 7f28d1d9684..04621e02825 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -90,7 +90,7 @@ class ErrorLoadingException(message: String? = null) : Exception(message) @Prerelease val json = Json { encodeDefaults = true - explicitNulls = false + // explicitNulls = false ignoreUnknownKeys = true } From 3b58609c1d8649c1e7f109733993932832c4dbb9 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:28:33 -0600 Subject: [PATCH 073/192] Test --- .../commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index 04621e02825..27e5cae9cec 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -89,8 +89,9 @@ class ErrorLoadingException(message: String? = null) : Exception(message) @Prerelease val json = Json { + coerceInputValues = true encodeDefaults = true - // explicitNulls = false + explicitNulls = false ignoreUnknownKeys = true } From 69afa64c0f5588fa927c8bbc8803df172acb1653 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:42:58 -0600 Subject: [PATCH 074/192] Try fixing transient --- .../cloudstream3/utils/DataStoreHelper.kt | 115 +++++++++--------- 1 file changed, 56 insertions(+), 59 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index 509e1bddac0..d408db4c5f6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -3,7 +3,6 @@ package com.lagradost.cloudstream3.utils import android.content.Context import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable -import kotlinx.serialization.Transient import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -256,24 +255,22 @@ object DataStoreHelper { /** * Used to display notifications on new episodes and posters in library. **/ - @Serializable abstract class LibrarySearchResponse( - @SerialName("id") override var id: Int?, - @SerialName("latestUpdatedTime") open val latestUpdatedTime: Long, - @SerialName("name") override val name: String, - @SerialName("url") override val url: String, - @SerialName("apiName") override val apiName: String, - @SerialName("type") override var type: TvType?, - @SerialName("posterUrl") override var posterUrl: String?, - @SerialName("year") open val year: Int?, - @SerialName("syncData") open val syncData: Map?, - @SerialName("quality") override var quality: SearchQuality?, - @SerialName("posterHeaders") override var posterHeaders: Map?, - @SerialName("plot") open val plot: String? = null, - @SerialName("score") override var score: Score? = null, - @SerialName("tags") open val tags: List? = null, + override var id: Int?, + open val latestUpdatedTime: Long, + override val name: String, + override val url: String, + override val apiName: String, + override var type: TvType?, + override var posterUrl: String?, + open val year: Int?, + open val syncData: Map?, + override var quality: SearchQuality?, + override var posterHeaders: Map?, + open val plot: String? = null, + override var score: Score? = null, + open val tags: List? = null, ) : SearchResponse { - @SerialName("rating") @Deprecated( "`rating` is the old scoring system, use score instead", replaceWith = ReplaceWith("score"), @@ -292,20 +289,20 @@ object DataStoreHelper { data class SubscribedData( @SerialName("subscribedTime") val subscribedTime: Long, @SerialName("lastSeenEpisodeCount") val lastSeenEpisodeCount: Map, - @Transient override var id: Int? = null, - @Transient override val latestUpdatedTime: Long = 0L, - @Transient override val name: String = "", - @Transient override val url: String = "", - @Transient override val apiName: String = "", - @Transient override var type: TvType? = null, - @Transient override var posterUrl: String? = null, - @Transient override val year: Int? = null, - @Transient override val syncData: Map? = null, - @Transient override var quality: SearchQuality? = null, - @Transient override var posterHeaders: Map? = null, - @Transient override val plot: String? = null, - @Transient override var score: Score? = null, - @Transient override val tags: List? = null, + @SerialName("id") override var id: Int? = null, + @SerialName("latestUpdatedTime") override val latestUpdatedTime: Long = 0L, + @SerialName("name") override val name: String = "", + @SerialName("url") override val url: String = "", + @SerialName("apiName") override val apiName: String = "", + @SerialName("type") override var type: TvType? = null, + @SerialName("posterUrl") override var posterUrl: String? = null, + @SerialName("year") override val year: Int? = null, + @SerialName("syncData") override val syncData: Map? = null, + @SerialName("quality") override var quality: SearchQuality? = null, + @SerialName("posterHeaders") override var posterHeaders: Map? = null, + @SerialName("plot") override val plot: String? = null, + @SerialName("score") override var score: Score? = null, + @SerialName("tags") override val tags: List? = null, ) : LibrarySearchResponse( id, latestUpdatedTime, @@ -348,20 +345,20 @@ object DataStoreHelper { @Serializable data class BookmarkedData( @SerialName("bookmarkedTime") val bookmarkedTime: Long, - @Transient override var id: Int? = null, - @Transient override val latestUpdatedTime: Long = 0L, - @Transient override val name: String = "", - @Transient override val url: String = "", - @Transient override val apiName: String = "", - @Transient override var type: TvType? = null, - @Transient override var posterUrl: String? = null, - @Transient override val year: Int? = null, - @Transient override val syncData: Map? = null, - @Transient override var quality: SearchQuality? = null, - @Transient override var posterHeaders: Map? = null, - @Transient override val plot: String? = null, - @Transient override var score: Score? = null, - @Transient override val tags: List? = null, + @SerialName("id") override var id: Int? = null, + @SerialName("latestUpdatedTime") override val latestUpdatedTime: Long = 0L, + @SerialName("name") override val name: String = "", + @SerialName("url") override val url: String = "", + @SerialName("apiName") override val apiName: String = "", + @SerialName("type") override var type: TvType? = null, + @SerialName("posterUrl") override var posterUrl: String? = null, + @SerialName("year") override val year: Int? = null, + @SerialName("syncData") override val syncData: Map? = null, + @SerialName("quality") override var quality: SearchQuality? = null, + @SerialName("posterHeaders") override var posterHeaders: Map? = null, + @SerialName("plot") override val plot: String? = null, + @SerialName("score") override var score: Score? = null, + @SerialName("tags") override val tags: List? = null, ) : LibrarySearchResponse( id, latestUpdatedTime, @@ -402,20 +399,20 @@ object DataStoreHelper { @Serializable data class FavoritesData( @SerialName("favoritesTime") val favoritesTime: Long, - @Transient override var id: Int? = null, - @Transient override val latestUpdatedTime: Long = 0L, - @Transient override val name: String = "", - @Transient override val url: String = "", - @Transient override val apiName: String = "", - @Transient override var type: TvType? = null, - @Transient override var posterUrl: String? = null, - @Transient override val year: Int? = null, - @Transient override val syncData: Map? = null, - @Transient override var quality: SearchQuality? = null, - @Transient override var posterHeaders: Map? = null, - @Transient override val plot: String? = null, - @Transient override var score: Score? = null, - @Transient override val tags: List? = null, + @SerialName("id") override var id: Int? = null, + @SerialName("latestUpdatedTime") override val latestUpdatedTime: Long = 0L, + @SerialName("name") override val name: String = "", + @SerialName("url") override val url: String = "", + @SerialName("apiName") override val apiName: String = "", + @SerialName("type") override var type: TvType? = null, + @SerialName("posterUrl") override var posterUrl: String? = null, + @SerialName("year") override val year: Int? = null, + @SerialName("syncData") override val syncData: Map? = null, + @SerialName("quality") override var quality: SearchQuality? = null, + @SerialName("posterHeaders") override var posterHeaders: Map? = null, + @SerialName("plot") override val plot: String? = null, + @SerialName("score") override var score: Score? = null, + @SerialName("tags") override val tags: List? = null, ) : LibrarySearchResponse( id, latestUpdatedTime, From 25daec34408406f005241d15155d6a47ef56753a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sat, 6 Jun 2026 15:48:42 -0600 Subject: [PATCH 075/192] Fix parent --- .../cloudstream3/utils/DataStoreHelper.kt | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt index d408db4c5f6..60cbec64e9a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStoreHelper.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.utils import android.content.Context import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.CloudStreamApp.Companion.context import com.lagradost.cloudstream3.CloudStreamApp.Companion.getKey @@ -255,22 +256,24 @@ object DataStoreHelper { /** * Used to display notifications on new episodes and posters in library. **/ + @Serializable abstract class LibrarySearchResponse( - override var id: Int?, - open val latestUpdatedTime: Long, - override val name: String, - override val url: String, - override val apiName: String, - override var type: TvType?, - override var posterUrl: String?, - open val year: Int?, - open val syncData: Map?, - override var quality: SearchQuality?, - override var posterHeaders: Map?, - open val plot: String? = null, - override var score: Score? = null, - open val tags: List? = null, + @Transient override var id: Int? = null, + @Transient open val latestUpdatedTime: Long = 0L, + @Transient override val name: String = "", + @Transient override val url: String = "", + @Transient override val apiName: String = "", + @Transient override var type: TvType? = null, + @Transient override var posterUrl: String? = null, + @Transient open val year: Int? = null, + @Transient open val syncData: Map? = null, + @Transient override var quality: SearchQuality? = null, + @Transient override var posterHeaders: Map? = null, + @Transient open val plot: String? = null, + @Transient override var score: Score? = null, + @Transient open val tags: List? = null, ) : SearchResponse { + @SerialName("rating") @Deprecated( "`rating` is the old scoring system, use score instead", replaceWith = ReplaceWith("score"), From 019b877d3405f5b4b7b81589824f38b367d48d96 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Sun, 21 Jun 2026 14:42:30 -0600 Subject: [PATCH 076/192] Fix --- .../lagradost/cloudstream3/syncproviders/providers/Subdl.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt index f29023a2f72..19bd3b1a710 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/Subdl.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.syncproviders.providers -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.subtitles.AbstractSubtitleEntities From 3deb498628d0217cdf2ef1f8e289d56dde5539c6 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:09:36 -0600 Subject: [PATCH 077/192] Update anilist --- .../syncproviders/providers/AniListApi.kt | 409 +++++++++--------- 1 file changed, 200 insertions(+), 209 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 122caf43281..fb7173ff83b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -1,6 +1,7 @@ package com.lagradost.cloudstream3.syncproviders.providers import androidx.annotation.StringRes +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.Actor import com.lagradost.cloudstream3.ActorData import com.lagradost.cloudstream3.ActorRole @@ -81,7 +82,6 @@ class AniListApi : SyncAPI() { override fun urlToId(url: String): String? = url.removePrefix("$mainUrl/anime/").removeSuffix("/") - private fun getUrlFromId(id: Int): String { return "$mainUrl/anime/$id" } @@ -103,7 +103,6 @@ class AniListApi : SyncAPI() { val internalId = (Regex("anilist\\.co/anime/(\\d*)").find(id)?.groupValues?.getOrNull(1) ?: id).toIntOrNull() ?: throw ErrorLoadingException("Invalid internalId") val season = getSeason(internalId).data.media - return SyncAPI.SyncResult( season.id.toString(), nextAiring = season.nextAiringEpisode?.let { @@ -157,14 +156,13 @@ class AniListApi : SyncAPI() { "youtube" -> listOf("https://www.youtube.com/watch?v=${season.trailer.id}") else -> null } - //TODO REST + // TODO REST ) } override suspend fun status(auth: AuthData?, id: String): SyncAPI.AbstractSyncStatus? { val internalId = id.toIntOrNull() ?: return null val data = getDataAboutId(auth ?: return null, internalId) ?: return null - return SyncAPI.SyncStatus( score = Score.from100(data.score), watchedEpisodes = data.progress, @@ -269,14 +267,15 @@ class AniListApi : SyncAPI() { val res = app.post( "https://graphql.anilist.co/", - //headers = mapOf(), - data = data,//(if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) + // headers = mapOf(), + data = data,// (if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) timeout = 5000 // REASONABLE TIMEOUT ).text.replace("\\", "") return parseJson(res) } catch (e: Exception) { logError(e) } + return null } @@ -299,7 +298,7 @@ class AniListApi : SyncAPI() { .replace(")", "\\)") })""" ) - //println("NAME $name NEW NAME ${name.replace(blackListRegex, "")}") + // println("NAME $name NEW NAME ${name.replace(blackListRegex, "")}") val shows = searchShows(name.replace(blackListRegex, "")) shows?.data?.page?.media?.find { @@ -505,7 +504,6 @@ class AniListApi : SyncAPI() { type = AniListStatusType.None, ) } - } private suspend fun postApi(token: AuthToken, q: String, cache: Boolean = false): String? { @@ -521,84 +519,84 @@ class AniListApi : SyncAPI() { q, "UTF-8" ) - ), //(if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) + ), // (if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) timeout = 5 // REASONABLE TIMEOUT ).text.replace("\\/", "/") } @Serializable data class Variables( - @SerialName("search") val search: String, - @SerialName("page") val page: Int, - @SerialName("type") val type: String, + @JsonProperty("search") @SerialName("search") val search: String, + @JsonProperty("page") @SerialName("page") val page: Int, + @JsonProperty("type") @SerialName("type") val type: String, ) @Serializable data class MediaRecommendation( - @SerialName("id") val id: Int, - @SerialName("title") val title: Title?, - @SerialName("idMal") val idMal: Int?, - @SerialName("coverImage") val coverImage: CoverImage?, - @SerialName("averageScore") val averageScore: Int?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("title") @SerialName("title") val title: Title?, + @JsonProperty("idMal") @SerialName("idMal") val idMal: Int?, + @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: CoverImage?, + @JsonProperty("averageScore") @SerialName("averageScore") val averageScore: Int?, ) @Serializable data class FullAnilistList( - @SerialName("data") val data: Data?, + @JsonProperty("data") @SerialName("data") val data: Data?, ) @Serializable data class CompletedAt( - @SerialName("year") val year: Int, - @SerialName("month") val month: Int, - @SerialName("day") val day: Int, + @JsonProperty("year") @SerialName("year") val year: Int, + @JsonProperty("month") @SerialName("month") val month: Int, + @JsonProperty("day") @SerialName("day") val day: Int, ) @Serializable data class StartedAt( - @SerialName("year") val year: String?, - @SerialName("month") val month: String?, - @SerialName("day") val day: String?, + @JsonProperty("year") @SerialName("year") val year: String?, + @JsonProperty("month") @SerialName("month") val month: String?, + @JsonProperty("day") @SerialName("day") val day: String?, ) @Serializable data class Title( - @SerialName("english") val english: String?, - @SerialName("romaji") val romaji: String?, + @JsonProperty("english") @SerialName("english") val english: String?, + @JsonProperty("romaji") @SerialName("romaji") val romaji: String?, ) @Serializable data class CoverImage( - @SerialName("medium") val medium: String?, - @SerialName("large") val large: String?, - @SerialName("extraLarge") val extraLarge: String?, + @JsonProperty("medium") @SerialName("medium") val medium: String?, + @JsonProperty("large") @SerialName("large") val large: String?, + @JsonProperty("extraLarge") @SerialName("extraLarge") val extraLarge: String?, ) @Serializable data class Media( - @SerialName("id") val id: Int, - @SerialName("idMal") val idMal: Int?, - @SerialName("season") val season: String?, - @SerialName("seasonYear") val seasonYear: Int, - @SerialName("format") val format: String?, - @SerialName("episodes") val episodes: Int, - @SerialName("title") val title: Title, - @SerialName("description") val description: String?, - @SerialName("coverImage") val coverImage: CoverImage, - @SerialName("synonyms") val synonyms: List, - @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("idMal") @SerialName("idMal") val idMal: Int?, + @JsonProperty("season") @SerialName("season") val season: String?, + @JsonProperty("seasonYear") @SerialName("seasonYear") val seasonYear: Int, + @JsonProperty("format") @SerialName("format") val format: String?, + @JsonProperty("episodes") @SerialName("episodes") val episodes: Int, + @JsonProperty("title") @SerialName("title") val title: Title, + @JsonProperty("description") @SerialName("description") val description: String?, + @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: CoverImage, + @JsonProperty("synonyms") @SerialName("synonyms") val synonyms: List, + @JsonProperty("nextAiringEpisode") @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, ) @Serializable data class Entries( - @SerialName("status") val status: String?, - @SerialName("completedAt") val completedAt: CompletedAt, - @SerialName("startedAt") val startedAt: StartedAt, - @SerialName("updatedAt") val updatedAt: Int, - @SerialName("progress") val progress: Int, - @SerialName("score") val score: Int, - @SerialName("private") val private: Boolean, - @SerialName("media") val media: Media, + @JsonProperty("status") @SerialName("status") val status: String?, + @JsonProperty("completedAt") @SerialName("completedAt") val completedAt: CompletedAt, + @JsonProperty("startedAt") @SerialName("startedAt") val startedAt: StartedAt, + @JsonProperty("updatedAt") @SerialName("updatedAt") val updatedAt: Int, + @JsonProperty("progress") @SerialName("progress") val progress: Int, + @JsonProperty("score") @SerialName("score") val score: Int, + @JsonProperty("private") @SerialName("private") val private: Boolean, + @JsonProperty("media") @SerialName("media") val media: Media, ) { fun toLibraryItem(): SyncAPI.LibraryItem { return SyncAPI.LibraryItem( @@ -627,18 +625,18 @@ class AniListApi : SyncAPI() { @Serializable data class Lists( - @SerialName("status") val status: String?, - @SerialName("entries") val entries: List, + @JsonProperty("status") @SerialName("status") val status: String?, + @JsonProperty("entries") @SerialName("entries") val entries: List, ) @Serializable data class MediaListCollection( - @SerialName("lists") val lists: List, + @JsonProperty("lists") @SerialName("lists") val lists: List, ) @Serializable data class Data( - @SerialName("MediaListCollection") val mediaListCollection: MediaListCollection, + @JsonProperty("MediaListCollection") @SerialName("MediaListCollection") val mediaListCollection: MediaListCollection, ) private suspend fun getAniListAnimeListSmart(auth: AuthData): Array? { @@ -687,7 +685,6 @@ class AniListApi : SyncAPI() { private suspend fun getFullAniListList(auth: AuthData): FullAnilistList? { val userID = auth.user.id val mediaType = "ANIME" - val query = """ query (${'$'}userID: Int = $userID, ${'$'}MEDIA: MediaType = $mediaType) { MediaListCollection (userId: ${'$'}userID, type: ${'$'}MEDIA) { @@ -726,7 +723,7 @@ class AniListApi : SyncAPI() { } } } - } + } """ val text = postApi(auth.token, query) return tryParseJson(text) @@ -752,17 +749,17 @@ class AniListApi : SyncAPI() { /** Used to query a saved MediaItem on the list to get the id for removal */ @Serializable data class MediaListItemRoot( - @SerialName("data") val data: MediaListItem? = null, + @JsonProperty("data") @SerialName("data") val data: MediaListItem? = null, ) @Serializable data class MediaListItem( - @SerialName("MediaList") val mediaList: MediaListId? = null, + @JsonProperty("MediaList") @SerialName("MediaList") val mediaList: MediaListId? = null, ) @Serializable data class MediaListId( - @SerialName("id") val id: Long? = null, + @JsonProperty("id") @SerialName("id") val id: Long? = null, ) private suspend fun postDataAboutId( @@ -773,7 +770,6 @@ class AniListApi : SyncAPI() { progress: Int? ): Boolean { val userID = auth.user.id - val q = // Delete item if status type is None if (type == AniListStatusType.None) { @@ -867,346 +863,341 @@ class AniListApi : SyncAPI() { @Serializable data class SeasonResponse( - @SerialName("data") val data: SeasonData, + @JsonProperty("data") @SerialName("data") val data: SeasonData, ) @Serializable data class SeasonData( - @SerialName("Media") val media: SeasonMedia, + @JsonProperty("Media") @SerialName("Media") val media: SeasonMedia, ) @Serializable data class SeasonMedia( - @SerialName("id") val id: Int?, - @SerialName("title") val title: MediaTitle?, - @SerialName("idMal") val idMal: Int?, - @SerialName("format") val format: String?, - @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, - @SerialName("relations") val relations: SeasonEdges?, - @SerialName("coverImage") val coverImage: MediaCoverImage?, - @SerialName("duration") val duration: Int?, - @SerialName("episodes") val episodes: Int?, - @SerialName("genres") val genres: List?, - @SerialName("synonyms") val synonyms: List?, - @SerialName("averageScore") val averageScore: Int?, - @SerialName("isAdult") val isAdult: Boolean?, - @SerialName("trailer") val trailer: MediaTrailer?, - @SerialName("description") val description: String?, - @SerialName("characters") val characters: CharacterConnection?, - @SerialName("recommendations") val recommendations: RecommendationConnection?, + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("title") @SerialName("title") val title: MediaTitle?, + @JsonProperty("idMal") @SerialName("idMal") val idMal: Int?, + @JsonProperty("format") @SerialName("format") val format: String?, + @JsonProperty("nextAiringEpisode") @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @JsonProperty("relations") @SerialName("relations") val relations: SeasonEdges?, + @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: MediaCoverImage?, + @JsonProperty("duration") @SerialName("duration") val duration: Int?, + @JsonProperty("episodes") @SerialName("episodes") val episodes: Int?, + @JsonProperty("genres") @SerialName("genres") val genres: List?, + @JsonProperty("synonyms") @SerialName("synonyms") val synonyms: List?, + @JsonProperty("averageScore") @SerialName("averageScore") val averageScore: Int?, + @JsonProperty("isAdult") @SerialName("isAdult") val isAdult: Boolean?, + @JsonProperty("trailer") @SerialName("trailer") val trailer: MediaTrailer?, + @JsonProperty("description") @SerialName("description") val description: String?, + @JsonProperty("characters") @SerialName("characters") val characters: CharacterConnection?, + @JsonProperty("recommendations") @SerialName("recommendations") val recommendations: RecommendationConnection?, ) @Serializable data class RecommendationConnection( - @SerialName("edges") val edges: List = emptyList(), - @SerialName("nodes") val nodes: List = emptyList(), + @JsonProperty("edges") @SerialName("edges") val edges: List = emptyList(), + @JsonProperty("nodes") @SerialName("nodes") val nodes: List = emptyList(), ) @Serializable data class RecommendationEdge( - @SerialName("node") val node: Recommendation, + @JsonProperty("node") @SerialName("node") val node: Recommendation, ) @Serializable data class Recommendation( - @SerialName("id") val id: Long, - @SerialName("mediaRecommendation") val mediaRecommendation: SeasonMedia?, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("mediaRecommendation") @SerialName("mediaRecommendation") val mediaRecommendation: SeasonMedia?, ) @Serializable data class CharacterName( - @SerialName("name") val first: String?, - @SerialName("middle") val middle: String?, - @SerialName("last") val last: String?, - @SerialName("full") val full: String?, - @SerialName("native") val native: String?, - @SerialName("alternative") val alternative: List?, - @SerialName("alternativeSpoiler") val alternativeSpoiler: List?, - @SerialName("userPreferred") val userPreferred: String?, + @JsonProperty("name") @SerialName("name") val first: String?, + @JsonProperty("middle") @SerialName("middle") val middle: String?, + @JsonProperty("last") @SerialName("last") val last: String?, + @JsonProperty("full") @SerialName("full") val full: String?, + @JsonProperty("native") @SerialName("native") val native: String?, + @JsonProperty("alternative") @SerialName("alternative") val alternative: List?, + @JsonProperty("alternativeSpoiler") @SerialName("alternativeSpoiler") val alternativeSpoiler: List?, + @JsonProperty("userPreferred") @SerialName("userPreferred") val userPreferred: String?, ) @Serializable data class CharacterImage( - @SerialName("large") val large: String?, - @SerialName("medium") val medium: String?, + @JsonProperty("large") @SerialName("large") val large: String?, + @JsonProperty("medium") @SerialName("medium") val medium: String?, ) @Serializable data class Character( - @SerialName("name") val name: CharacterName?, - @SerialName("age") val age: String?, - @SerialName("image") val image: CharacterImage?, + @JsonProperty("name") @SerialName("name") val name: CharacterName?, + @JsonProperty("age") @SerialName("age") val age: String?, + @JsonProperty("image") @SerialName("image") val image: CharacterImage?, ) @Serializable data class CharacterEdge( - @SerialName("id") val id: Int?, + @JsonProperty("id") @SerialName("id") val id: Int?, /** - MAIN - A primary character role in the media - - SUPPORTING - A supporting character role in the media - - BACKGROUND - A background character in the media + * MAIN - A primary character role in the media + * SUPPORTING - A supporting character role in the media + * BACKGROUND - A background character in the media */ - @SerialName("role") val role: String?, - @SerialName("name") val name: String?, - @SerialName("voiceActors") val voiceActors: List?, - @SerialName("favouriteOrder") val favouriteOrder: Int?, - @SerialName("media") val media: List?, - @SerialName("node") val node: Character?, + @JsonProperty("role") @SerialName("role") val role: String?, + @JsonProperty("name") @SerialName("name") val name: String?, + @JsonProperty("voiceActors") @SerialName("voiceActors") val voiceActors: List?, + @JsonProperty("favouriteOrder") @SerialName("favouriteOrder") val favouriteOrder: Int?, + @JsonProperty("media") @SerialName("media") val media: List?, + @JsonProperty("node") @SerialName("node") val node: Character?, ) @Serializable data class StaffImage( - @SerialName("large") val large: String?, - @SerialName("medium") val medium: String?, + @JsonProperty("large") @SerialName("large") val large: String?, + @JsonProperty("medium") @SerialName("medium") val medium: String?, ) @Serializable data class StaffName( - @SerialName("name") val first: String?, - @SerialName("middle") val middle: String?, - @SerialName("last") val last: String?, - @SerialName("full") val full: String?, - @SerialName("native") val native: String?, - @SerialName("alternative") val alternative: List?, - @SerialName("userPreferred") val userPreferred: String?, + @JsonProperty("name") @SerialName("name") val first: String?, + @JsonProperty("middle") @SerialName("middle") val middle: String?, + @JsonProperty("last") @SerialName("last") val last: String?, + @JsonProperty("full") @SerialName("full") val full: String?, + @JsonProperty("native") @SerialName("native") val native: String?, + @JsonProperty("alternative") @SerialName("alternative") val alternative: List?, + @JsonProperty("userPreferred") @SerialName("userPreferred") val userPreferred: String?, ) @Serializable data class Staff( - @SerialName("image") val image: StaffImage?, - @SerialName("name") val name: StaffName?, - @SerialName("age") val age: Int?, + @JsonProperty("image") @SerialName("image") val image: StaffImage?, + @JsonProperty("name") @SerialName("name") val name: StaffName?, + @JsonProperty("age") @SerialName("age") val age: Int?, ) @Serializable data class CharacterConnection( - @SerialName("edges") val edges: List?, - @SerialName("nodes") val nodes: List?, + @JsonProperty("edges") @SerialName("edges") val edges: List?, + @JsonProperty("nodes") @SerialName("nodes") val nodes: List?, ) @Serializable data class MediaTrailer( - @SerialName("id") val id: String?, - @SerialName("site") val site: String?, - @SerialName("thumbnail") val thumbnail: String?, + @JsonProperty("id") @SerialName("id") val id: String?, + @JsonProperty("site") @SerialName("site") val site: String?, + @JsonProperty("thumbnail") @SerialName("thumbnail") val thumbnail: String?, ) @Serializable data class MediaCoverImage( - @SerialName("extraLarge") val extraLarge: String?, - @SerialName("large") val large: String?, - @SerialName("medium") val medium: String?, - @SerialName("color") val color: String?, + @JsonProperty("extraLarge") @SerialName("extraLarge") val extraLarge: String?, + @JsonProperty("large") @SerialName("large") val large: String?, + @JsonProperty("medium") @SerialName("medium") val medium: String?, + @JsonProperty("color") @SerialName("color") val color: String?, ) @Serializable data class SeasonNextAiringEpisode( - @SerialName("episode") val episode: Int?, - @SerialName("timeUntilAiring") val timeUntilAiring: Int?, + @JsonProperty("episode") @SerialName("episode") val episode: Int?, + @JsonProperty("timeUntilAiring") @SerialName("timeUntilAiring") val timeUntilAiring: Int?, ) @Serializable data class SeasonEdges( - @SerialName("edges") val edges: List?, + @JsonProperty("edges") @SerialName("edges") val edges: List?, ) @Serializable data class SeasonEdge( - @SerialName("id") val id: Int?, - @SerialName("relationType") val relationType: String?, - @SerialName("node") val node: SeasonNode?, + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("relationType") @SerialName("relationType") val relationType: String?, + @JsonProperty("node") @SerialName("node") val node: SeasonNode?, ) @Serializable data class AniListFavoritesMediaConnection( - @SerialName("nodes") val nodes: List, + @JsonProperty("nodes") @SerialName("nodes") val nodes: List, ) @Serializable data class AniListFavourites( - @SerialName("anime") val anime: AniListFavoritesMediaConnection, + @JsonProperty("anime") @SerialName("anime") val anime: AniListFavoritesMediaConnection, ) @Serializable data class MediaTitle( - @SerialName("romaji") val romaji: String?, - @SerialName("english") val english: String?, - @SerialName("native") val native: String?, - @SerialName("userPreferred") val userPreferred: String?, + @JsonProperty("romaji") @SerialName("romaji") val romaji: String?, + @JsonProperty("english") @SerialName("english") val english: String?, + @JsonProperty("native") @SerialName("native") val native: String?, + @JsonProperty("userPreferred") @SerialName("userPreferred") val userPreferred: String?, ) @Serializable data class SeasonNode( - @SerialName("id") val id: Int, - @SerialName("format") val format: String?, - @SerialName("title") val title: Title?, - @SerialName("idMal") val idMal: Int?, - @SerialName("coverImage") val coverImage: CoverImage?, - @SerialName("averageScore") val averageScore: Int?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("format") @SerialName("format") val format: String?, + @JsonProperty("title") @SerialName("title") val title: Title?, + @JsonProperty("idMal") @SerialName("idMal") val idMal: Int?, + @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: CoverImage?, + @JsonProperty("averageScore") @SerialName("averageScore") val averageScore: Int?, ) @Serializable data class AniListAvatar( - @SerialName("large") val large: String?, + @JsonProperty("large") @SerialName("large") val large: String?, ) @Serializable data class AniListViewer( - @SerialName("id") val id: Int, - @SerialName("name") val name: String, - @SerialName("avatar") val avatar: AniListAvatar?, - @SerialName("favourites") val favourites: AniListFavourites?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("avatar") @SerialName("avatar") val avatar: AniListAvatar?, + @JsonProperty("favourites") @SerialName("favourites") val favourites: AniListFavourites?, ) @Serializable data class AniListData( - @SerialName("Viewer") val viewer: AniListViewer?, + @JsonProperty("Viewer") @SerialName("Viewer") val viewer: AniListViewer?, ) @Serializable data class AniListRoot( - @SerialName("data") val data: AniListData?, + @JsonProperty("data") @SerialName("data") val data: AniListData?, ) @Serializable data class AniListUser( - @SerialName("id") val id: Int, - @SerialName("name") val name: String, - @SerialName("picture") val picture: String?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("picture") @SerialName("picture") val picture: String?, ) @Serializable data class LikeNode( - @SerialName("id") val id: Int?, + @JsonProperty("id") @SerialName("id") val id: Int?, ) @Serializable data class LikePageInfo( - @SerialName("total") val total: Int?, - @SerialName("currentPage") val currentPage: Int?, - @SerialName("lastPage") val lastPage: Int?, - @SerialName("perPage") val perPage: Int?, - @SerialName("hasNextPage") val hasNextPage: Boolean?, + @JsonProperty("total") @SerialName("total") val total: Int?, + @JsonProperty("currentPage") @SerialName("currentPage") val currentPage: Int?, + @JsonProperty("lastPage") @SerialName("lastPage") val lastPage: Int?, + @JsonProperty("perPage") @SerialName("perPage") val perPage: Int?, + @JsonProperty("hasNextPage") @SerialName("hasNextPage") val hasNextPage: Boolean?, ) @Serializable data class LikeAnime( - @SerialName("nodes") val nodes: List?, - @SerialName("pageInfo") val pageInfo: LikePageInfo?, + @JsonProperty("nodes") @SerialName("nodes") val nodes: List?, + @JsonProperty("pageInfo") @SerialName("pageInfo") val pageInfo: LikePageInfo?, ) @Serializable data class LikeFavourites( - @SerialName("anime") val anime: LikeAnime?, + @JsonProperty("anime") @SerialName("anime") val anime: LikeAnime?, ) @Serializable data class LikeViewer( - @SerialName("favourites") val favourites: LikeFavourites?, + @JsonProperty("favourites") @SerialName("favourites") val favourites: LikeFavourites?, ) @Serializable data class LikeData( - @SerialName("Viewer") val viewer: LikeViewer?, + @JsonProperty("Viewer") @SerialName("Viewer") val viewer: LikeViewer?, ) @Serializable data class LikeRoot( - @SerialName("data") val data: LikeData?, + @JsonProperty("data") @SerialName("data") val data: LikeData?, ) @Serializable data class AniListTitleHolder( - @SerialName("title") val title: Title?, - @SerialName("isFavourite") val isFavourite: Boolean?, - @SerialName("id") val id: Int?, - @SerialName("progress") val progress: Int?, - @SerialName("episodes") val episodes: Int?, - @SerialName("score") val score: Int?, - @SerialName("type") val type: AniListStatusType?, + @JsonProperty("title") @SerialName("title") val title: Title?, + @JsonProperty("isFavourite") @SerialName("isFavourite") val isFavourite: Boolean?, + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("progress") @SerialName("progress") val progress: Int?, + @JsonProperty("episodes") @SerialName("episodes") val episodes: Int?, + @JsonProperty("score") @SerialName("score") val score: Int?, + @JsonProperty("type") @SerialName("type") val type: AniListStatusType?, ) @Serializable data class GetDataMediaListEntry( - @SerialName("progress") val progress: Int?, - @SerialName("status") val status: String?, - @SerialName("score") val score: Int?, + @JsonProperty("progress") @SerialName("progress") val progress: Int?, + @JsonProperty("status") @SerialName("status") val status: String?, + @JsonProperty("score") @SerialName("score") val score: Int?, ) @Serializable data class Nodes( - @SerialName("id") val id: Int?, - @SerialName("mediaRecommendation") val mediaRecommendation: MediaRecommendation?, + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("mediaRecommendation") @SerialName("mediaRecommendation") val mediaRecommendation: MediaRecommendation?, ) @Serializable data class GetDataMedia( - @SerialName("isFavourite") val isFavourite: Boolean?, - @SerialName("episodes") val episodes: Int?, - @SerialName("title") val title: Title?, - @SerialName("mediaListEntry") val mediaListEntry: GetDataMediaListEntry?, + @JsonProperty("isFavourite") @SerialName("isFavourite") val isFavourite: Boolean?, + @JsonProperty("episodes") @SerialName("episodes") val episodes: Int?, + @JsonProperty("title") @SerialName("title") val title: Title?, + @JsonProperty("mediaListEntry") @SerialName("mediaListEntry") val mediaListEntry: GetDataMediaListEntry?, ) @Serializable data class Recommendations( - @SerialName("nodes") val nodes: List?, + @JsonProperty("nodes") @SerialName("nodes") val nodes: List?, ) @Serializable data class GetDataData( - @SerialName("Media") val media: GetDataMedia?, + @JsonProperty("Media") @SerialName("Media") val media: GetDataMedia?, ) @Serializable data class GetDataRoot( - @SerialName("data") val data: GetDataData?, + @JsonProperty("data") @SerialName("data") val data: GetDataData?, ) @Serializable data class GetSearchTitle( - @SerialName("romaji") val romaji: String?, + @JsonProperty("romaji") @SerialName("romaji") val romaji: String?, ) @Serializable data class TrailerObject( - @SerialName("id") val id: String?, - @SerialName("thumbnail") val thumbnail: String?, - @SerialName("site") val site: String?, + @JsonProperty("id") @SerialName("id") val id: String?, + @JsonProperty("thumbnail") @SerialName("thumbnail") val thumbnail: String?, + @JsonProperty("site") @SerialName("site") val site: String?, ) @Serializable data class GetSearchMedia( - @SerialName("id") val id: Int, - @SerialName("idMal") val idMal: Int?, - @SerialName("seasonYear") val seasonYear: Int, - @SerialName("title") val title: GetSearchTitle, - @SerialName("startDate") val startDate: StartedAt, - @SerialName("averageScore") val averageScore: Int?, - @SerialName("meanScore") val meanScore: Int?, - @SerialName("bannerImage") val bannerImage: String?, - @SerialName("trailer") val trailer: TrailerObject?, - @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, - @SerialName("recommendations") val recommendations: Recommendations?, - @SerialName("relations") val relations: SeasonEdges?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("idMal") @SerialName("idMal") val idMal: Int?, + @JsonProperty("seasonYear") @SerialName("seasonYear") val seasonYear: Int, + @JsonProperty("title") @SerialName("title") val title: GetSearchTitle, + @JsonProperty("startDate") @SerialName("startDate") val startDate: StartedAt, + @JsonProperty("averageScore") @SerialName("averageScore") val averageScore: Int?, + @JsonProperty("meanScore") @SerialName("meanScore") val meanScore: Int?, + @JsonProperty("bannerImage") @SerialName("bannerImage") val bannerImage: String?, + @JsonProperty("trailer") @SerialName("trailer") val trailer: TrailerObject?, + @JsonProperty("nextAiringEpisode") @SerialName("nextAiringEpisode") val nextAiringEpisode: SeasonNextAiringEpisode?, + @JsonProperty("recommendations") @SerialName("recommendations") val recommendations: Recommendations?, + @JsonProperty("relations") @SerialName("relations") val relations: SeasonEdges?, ) @Serializable data class GetSearchPage( - @SerialName("Page") val page: GetSearchData?, + @JsonProperty("Page") @SerialName("Page") val page: GetSearchData?, ) @Serializable data class GetSearchData( - @SerialName("media") val media: List?, + @JsonProperty("media") @SerialName("media") val media: List?, ) @Serializable data class GetSearchRoot( - @SerialName("data") val data: GetSearchPage?, + @JsonProperty("data") @SerialName("data") val data: GetSearchPage?, ) } From 3d30b97a5f9d8110769d1a9d40cc319ba8908e12 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:20:31 -0600 Subject: [PATCH 078/192] Update --- .../syncproviders/providers/AniListApi.kt | 88 +++++++++---------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index fb7173ff83b..aabbd38c164 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -259,16 +259,16 @@ class AniListApi : SyncAPI() { mapOf( "query" to query, "variables" to Variables( - search = name, - page = 1, - type = "ANIME", - ).toJson() + search = name, + page = 1, + type = "ANIME", + ).toJson() ) val res = app.post( "https://graphql.anilist.co/", // headers = mapOf(), - data = data,// (if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) + data = data, // (if (vars == null) mapOf("query" to q) else mapOf("query" to q, "variables" to vars)) timeout = 5000 // REASONABLE TIMEOUT ).text.replace("\\", "") return parseJson(res) @@ -524,12 +524,12 @@ class AniListApi : SyncAPI() { ).text.replace("\\/", "/") } - @Serializable - data class Variables( - @JsonProperty("search") @SerialName("search") val search: String, - @JsonProperty("page") @SerialName("page") val page: Int, - @JsonProperty("type") @SerialName("type") val type: String, - ) + @Serializable + data class Variables( + @JsonProperty("search") @SerialName("search") val search: String, + @JsonProperty("page") @SerialName("page") val page: Int, + @JsonProperty("type") @SerialName("type") val type: String, + ) @Serializable data class MediaRecommendation( @@ -731,17 +731,17 @@ class AniListApi : SyncAPI() { suspend fun toggleLike(auth: AuthData, id: Int): Boolean { val q = """mutation (${'$'}animeId: Int = $id) { - ToggleFavourite (animeId: ${'$'}animeId) { - anime { - nodes { - id - title { - romaji - } - } - } - } - }""" + ToggleFavourite (animeId: ${'$'}animeId) { + anime { + nodes { + id + title { + romaji + } + } + } + } + }""" val data = postApi(auth.token, q) return data != "" } @@ -749,18 +749,18 @@ class AniListApi : SyncAPI() { /** Used to query a saved MediaItem on the list to get the id for removal */ @Serializable data class MediaListItemRoot( - @JsonProperty("data") @SerialName("data") val data: MediaListItem? = null, - ) + @JsonProperty("data") @SerialName("data") val data: MediaListItem? = null, + ) @Serializable data class MediaListItem( - @JsonProperty("MediaList") @SerialName("MediaList") val mediaList: MediaListId? = null, - ) + @JsonProperty("MediaList") @SerialName("MediaList") val mediaList: MediaListId? = null, + ) @Serializable data class MediaListId( - @JsonProperty("id") @SerialName("id") val id: Long? = null, - ) + @JsonProperty("id") @SerialName("id") val id: Long? = null, + ) private suspend fun postDataAboutId( auth: AuthData, @@ -813,22 +813,22 @@ class AniListApi : SyncAPI() { private suspend fun getUser(token: AuthToken): AniListUser? { val q = """ - { - Viewer { - id - name - avatar { - large - } - favourites { - anime { - nodes { - id - } + { + Viewer { + id + name + avatar { + large + } + favourites { + anime { + nodes { + id } } - } - }""" + } + } + }""" val data = postApi(token, q) if (data.isNullOrBlank()) return null val userData = parseJson(data) @@ -939,8 +939,8 @@ class AniListApi : SyncAPI() { @JsonProperty("id") @SerialName("id") val id: Int?, /** * MAIN - A primary character role in the media - * SUPPORTING - A supporting character role in the media - * BACKGROUND - A background character in the media + * SUPPORTING - A supporting character role in the media + * BACKGROUND - A background character in the media */ @JsonProperty("role") @SerialName("role") val role: String?, @JsonProperty("name") @SerialName("name") val name: String?, From 08a523b0fbf9b9479cb7ab719524938492e99d36 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:25:01 -0600 Subject: [PATCH 079/192] -test --- .../com/lagradost/cloudstream3/ExampleInstrumentedTest.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt index 4c5cdea5bee..e854356a021 100644 --- a/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt +++ b/app/src/androidTest/java/com/lagradost/cloudstream3/ExampleInstrumentedTest.kt @@ -55,12 +55,6 @@ class ExampleInstrumentedTest { return APIHolder.allProviders.toTypedArray() //.filter { !it.usesWebView } } - @Test - fun providersExist() { - Assert.assertTrue(getAllProviders().isNotEmpty()) - println("Done providersExist") - } - @Throws private inline fun testAllLayouts( activity: Activity, From ac9b1af755cb4d0d786f63e167aff693fce7e038 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:25:42 -0600 Subject: [PATCH 080/192] run tests --- .github/workflows/pull_request.yml | 49 +++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index bf499d2a77e..c4b432fbb7e 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -27,10 +27,57 @@ jobs: cache-read-only: false - name: Run Gradle - run: ./gradlew assemblePrereleaseDebug + run: ./gradlew assemblePrereleaseDebug lint check - name: Upload Artifact uses: actions/upload-artifact@v7 with: name: pull-request-build path: "app/build/outputs/apk/prerelease/debug/*.apk" + + instrumented-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: 17 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + cache-read-only: false + + - name: Get target SDK + id: sdk + run: | + TARGET_SDK=$(grep 'targetSdk' gradle/libs.versions.toml | grep -o '[0-9]\+' | head -1) + echo "version=$TARGET_SDK" >> $GITHUB_OUTPUT + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Run Instrumented Tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ steps.sdk.outputs.version }} + arch: x86_64 + profile: Nexus 6 + script: ./gradlew connectedPrereleaseDebugAndroidTest + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v7 + with: + name: instrumented-test-results + path: '**/build/reports/androidTests/' From 3beff903993bd4a9f9cbe62086bd2d80a549b6f8 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:41:15 -0600 Subject: [PATCH 081/192] Update MainAPI --- .../com/lagradost/cloudstream3/MainAPI.kt | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt index bca1a3556fe..c040f41962d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/MainAPI.kt @@ -6,8 +6,8 @@ package com.lagradost.cloudstream3 -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonAutoDetect +import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.databind.DeserializationFeature import com.fasterxml.jackson.databind.json.JsonMapper import com.fasterxml.jackson.module.kotlin.kotlinModule @@ -39,6 +39,8 @@ import kotlinx.datetime.format.byUnicodePattern import kotlinx.datetime.format.char import kotlinx.datetime.format.parse import kotlinx.datetime.toInstant +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import kotlinx.serialization.json.Json import kotlin.io.encoding.Base64 import kotlin.math.absoluteValue @@ -90,7 +92,6 @@ class ErrorLoadingException(message: String? = null) : Exception(message) @Prerelease val json = Json { - coerceInputValues = true encodeDefaults = true explicitNulls = false ignoreUnknownKeys = true @@ -190,12 +191,12 @@ object APIHolder { referer = referer, cacheTime = 0 ) - .text() + .text .substringAfter("releases/") .substringBefore("/") val recapToken = app.get("https://www.google.com/recaptcha/api2/anchor?ar=1&hl=en&size=invisible&cb=cs3&k=$key&co=$domain&v=$vToken") - .document() + .document .selectFirst("#recaptcha-token")?.attr("value") if (recapToken != null) { return app.post( @@ -208,7 +209,7 @@ object APIHolder { "sa" to "", "reason" to "q" ), cacheTime = 0 - ).text() + ).text .substringAfter("rresp\",\"") .substringBefore("\"") } @@ -389,18 +390,17 @@ const val PROVIDER_STATUS_DOWN = 0 @Serializable data class ProvidersInfoJson( - @SerialName("name") var name: String, - @SerialName("url") var url: String, - @SerialName("credentials") var credentials: String? = null, - @SerialName("status") var status: Int, + @JsonProperty("name") @SerialName("name") var name: String, + @JsonProperty("url") @SerialName("url") var url: String, + @JsonProperty("credentials") @SerialName("credentials") var credentials: String? = null, + @JsonProperty("status") @SerialName("status") var status: Int, ) @Serializable data class SettingsJson( - @SerialName("enableAdult") var enableAdult: Boolean = false, + @JsonProperty("enableAdult") @SerialName("enableAdult") var enableAdult: Boolean = false, ) - data class MainPageData( val name: String, val data: String, @@ -865,11 +865,11 @@ enum class DubStatus(val id: Int) { * Internally it stores it as an int up to 10^9 to represent up to 10 significant digits. So think * of this as a decimal class specifically for ratings. * */ +@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY) @Serializable class Score private constructor( /** Decimal between [0, 10^9] representing the min score and max score respectively */ - @SerialName("data") - private val data: Int, + @JsonProperty("data") @SerialName("data") private val data: Int, ) { override fun hashCode(): Int = this.data.hashCode() override fun equals(other: Any?): Boolean = other is Score && this.data == other.data @@ -1197,8 +1197,8 @@ suspend fun newSubtitleFile( @ConsistentCopyVisibility @Serializable data class AudioFile internal constructor( - var url: String, - var headers: Map? = null + @JsonProperty("url") @SerialName("url") var url: String, + @JsonProperty("headers") @SerialName("headers") var headers: Map? = null, ) /** Creates an AudioFile with optional initializer for setting additional properties. @@ -2177,9 +2177,9 @@ data class NextAiring( * */ @Serializable data class SeasonData( - val season: Int, - val name: String? = null, - val displaySeason: Int? = null, // will use season if null + @JsonProperty("season") @SerialName("season") val season: Int, + @JsonProperty("name") @SerialName("name") val name: String? = null, + @JsonProperty("displaySeason") @SerialName("displaySeason") val displaySeason: Int? = null, // will use season if null ) /** Abstract interface of EpisodeResponse */ @@ -2739,36 +2739,36 @@ data class Tracker( @Serializable data class AniSearch( - @SerialName("data") var data: Data? = Data() + @JsonProperty("data") @SerialName("data") var data: Data? = Data(), ) { @Serializable data class Data( - @SerialName("Page") var page: Page? = Page() + @JsonProperty("Page") @SerialName("Page") var page: Page? = Page(), ) { @Serializable data class Page( - @SerialName("media") var media: ArrayList = arrayListOf() + @JsonProperty("media") @SerialName("media") var media: ArrayList = arrayListOf(), ) { @Serializable data class Media( - @SerialName("title") var title: Title? = null, - @SerialName("id") var id: Int? = null, - @SerialName("idMal") var idMal: Int? = null, - @SerialName("seasonYear") var seasonYear: Int? = null, - @SerialName("format") var format: String? = null, - @SerialName("coverImage") var coverImage: CoverImage? = null, - @SerialName("bannerImage") var bannerImage: String? = null, + @JsonProperty("title") @SerialName("title") var title: Title? = null, + @JsonProperty("id") @SerialName("id") var id: Int? = null, + @JsonProperty("idMal") @SerialName("idMal") var idMal: Int? = null, + @JsonProperty("seasonYear") @SerialName("seasonYear") var seasonYear: Int? = null, + @JsonProperty("format") @SerialName("format") var format: String? = null, + @JsonProperty("coverImage") @SerialName("coverImage") var coverImage: CoverImage? = null, + @JsonProperty("bannerImage") @SerialName("bannerImage") var bannerImage: String? = null, ) { @Serializable data class CoverImage( - @SerialName("extraLarge") var extraLarge: String? = null, - @SerialName("large") var large: String? = null, + @JsonProperty("extraLarge") @SerialName("extraLarge") var extraLarge: String? = null, + @JsonProperty("large") @SerialName("large") var large: String? = null, ) @Serializable data class Title( - @SerialName("romaji") var romaji: String? = null, - @SerialName("english") var english: String? = null, + @JsonProperty("romaji") @SerialName("romaji") var romaji: String? = null, + @JsonProperty("english") @SerialName("english") var english: String? = null, ) { fun isMatchingTitles(title: String?): Boolean { if (title == null) return false From b3739c3b42e1d2b90a5c6ca5a6ce79894e438373 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 14:56:39 -0600 Subject: [PATCH 082/192] Try all tests at once --- .../cloudstream3/SerializationClassTester.kt | 90 +++++++++++-------- 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/app/src/androidTest/java/com/lagradost/cloudstream3/SerializationClassTester.kt b/app/src/androidTest/java/com/lagradost/cloudstream3/SerializationClassTester.kt index 03308d9de20..61cf58c67d0 100644 --- a/app/src/androidTest/java/com/lagradost/cloudstream3/SerializationClassTester.kt +++ b/app/src/androidTest/java/com/lagradost/cloudstream3/SerializationClassTester.kt @@ -29,16 +29,19 @@ class SerializationClassTester { val serializableClasses = findSerializableClasses("com.lagradost") println("Number of serializable classes: ${serializableClasses.size}") + val failures = mutableListOf() + serializableClasses.forEach { kClass -> - val instance = Instancio.of(kClass.java).withMaxDepth(10).create() + runCatching { + val instance = Instancio.of(kClass.java).withMaxDepth(10).create() - val jacksonJson = jacksonMapper.writeValueAsString(instance) - val kotlinxJson = serializeWithKotlinx(kClass, instance) + val jacksonJson = jacksonMapper.writeValueAsString(instance) + val kotlinxJson = serializeWithKotlinx(kClass, instance) - assertEquals( - jacksonJson, - kotlinxJson, - """ + assertEquals( + jacksonJson, + kotlinxJson, + """ Serialization mismatch for: ${kClass.qualifiedName} @@ -49,8 +52,15 @@ class SerializationClassTester { $kotlinxJson """.trimIndent() - ) - println("Identical serialization for: ${kClass.jvmName}") + ) + println("Identical serialization for: ${kClass.jvmName}") + }.onFailure { e -> + failures.add("FAILED ${kClass.qualifiedName}: ${e.message}") + } + } + + if (failures.isNotEmpty()) { + throw AssertionError("${failures.size} class(es) failed:\n${failures.joinToString("\n")}") } } @@ -60,31 +70,34 @@ class SerializationClassTester { val serializableClasses = findSerializableClasses("com.lagradost") println("Number of serializable classes: ${serializableClasses.size}") + val failures = mutableListOf() + serializableClasses.forEach { kClass -> - val instance = Instancio.of(kClass.java).withMaxDepth(10).create() - // Convert to JSON to get example JSON object - // We prefer jackson here because the app may have many jackson JSON strings in local storage - val originalJson = jacksonMapper.writeValueAsString(instance) - - // Create an object from the JSON using kotlinx - val serializer = - kClass.serializerOrNull() ?: kotlinxMapper.serializersModule.getContextual(kClass) - assertNotNull(serializer, "The class: ${kClass.jvmName} must be serializable!") - val kotlinxDecoded = kotlinxMapper.decodeFromString(serializer, originalJson) - - // Create an object from the JSON using jackson - val mapperDecoded = jacksonMapper.readValue(originalJson, kClass.java) - - - // Deep inspect both object using the mapper toJson function. - // This deep equality check can be performed using other methods, but this just works. - val jacksonJson = mapperDecoded.toJson() - val kotlinxJson = kotlinxDecoded.toJson() - - assertEquals( - jacksonJson, - kotlinxJson, - """ + runCatching { + val instance = Instancio.of(kClass.java).withMaxDepth(10).create() + // Convert to JSON to get example JSON object + // We prefer jackson here because the app may have many jackson JSON strings in local storage + val originalJson = jacksonMapper.writeValueAsString(instance) + + // Create an object from the JSON using kotlinx + val serializer = + kClass.serializerOrNull() ?: kotlinxMapper.serializersModule.getContextual(kClass) + assertNotNull(serializer, "The class: ${kClass.jvmName} must be serializable!") + val kotlinxDecoded = kotlinxMapper.decodeFromString(serializer, originalJson) + + // Create an object from the JSON using jackson + val mapperDecoded = jacksonMapper.readValue(originalJson, kClass.java) + + + // Deep inspect both object using the mapper toJson function. + // This deep equality check can be performed using other methods, but this just works. + val jacksonJson = mapperDecoded.toJson() + val kotlinxJson = kotlinxDecoded.toJson() + + assertEquals( + jacksonJson, + kotlinxJson, + """ Serialization mismatch for: ${kClass.qualifiedName} @@ -95,8 +108,15 @@ class SerializationClassTester { $kotlinxJson """.trimIndent() - ) - println("Identical deserialization for: ${kClass.jvmName}") + ) + println("Identical deserialization for: ${kClass.jvmName}") + }.onFailure { e -> + failures.add("FAILED ${kClass.qualifiedName}: ${e.message}") + } + } + + if (failures.isNotEmpty()) { + throw AssertionError("${failures.size} class(es) failed:\n${failures.joinToString("\n")}") } } From 7ac2d5f53655d35f8f949972d645200d7a0f67c5 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:04:24 -0600 Subject: [PATCH 083/192] Update --- .../metaproviders/TraktProvider.kt | 248 +++++++++--------- 1 file changed, 120 insertions(+), 128 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt index c7e690bdb3a..04fb6174c7c 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -1,8 +1,7 @@ package com.lagradost.cloudstream3.metaproviders -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonNames +import com.fasterxml.jackson.annotation.JsonAlias +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.api.BuildConfig import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.Actor @@ -35,6 +34,10 @@ import com.lagradost.cloudstream3.newTvSeriesLoadResponse import com.lagradost.cloudstream3.newTvSeriesSearchResponse import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonNames open class TraktProvider : MainAPI() { override var name = "Trakt" @@ -47,7 +50,6 @@ open class TraktProvider : MainAPI() { ) private val traktApiUrl = "https://api.trakt.tv" - private val traktClientId: String = BuildConfig.TRAKT_CLIENT_ID override val mainPage = mainPageOf( @@ -59,15 +61,14 @@ open class TraktProvider : MainAPI() { override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { val apiResponse = getApi("${request.data}?extended=full,images&page=$page") - val results = parseJson>(apiResponse).map { element -> element.toSearchResponse() } + return newHomePageResponse(request.name, results) } private fun MediaDetails.toSearchResponse(): SearchResponse { - val media = this.media ?: this val mediaType = if (media.ids?.tvdb == null) TvType.Movie else TvType.TvSeries val poster = media.images?.poster?.firstOrNull() @@ -99,9 +100,7 @@ open class TraktProvider : MainAPI() { } override suspend fun search(query: String, page: Int): SearchResponseList? { - val apiResponse = - getApi("$traktApiUrl/search/movie,show?extended=full,images&limit=20&page=$page&query=$query") - + val apiResponse = getApi("$traktApiUrl/search/movie,show?extended=full,images&limit=20&page=$page&query=$query") return newSearchResponseList(parseJson>(apiResponse).map { element -> element.toSearchResponse() }) @@ -116,9 +115,7 @@ open class TraktProvider : MainAPI() { val backDropUrl = fixPath(mediaDetails?.images?.fanart?.firstOrNull()) val logoUrl = fixPath(mediaDetails?.images?.logo?.firstOrNull()) - val resActor = - getApi("$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/people?extended=full,images") - + val resActor = getApi("$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/people?extended=full,images") val actors = parseJson(resActor).cast?.map { ActorData( Actor( @@ -129,9 +126,7 @@ open class TraktProvider : MainAPI() { ) } - val resRelated = - getApi("$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/related?extended=full,images&limit=20") - + val resRelated = getApi("$traktApiUrl/$moviesOrShows/${mediaDetails?.ids?.trakt}/related?extended=full,images&limit=20") val relatedMedia = parseJson>(resRelated).map { it.toSearchResponse() } val isCartoon = @@ -143,7 +138,6 @@ open class TraktProvider : MainAPI() { val uniqueUrl = data.mediaDetails?.ids?.trakt?.toJson() ?: data.toJson() if (data.type == TvType.Movie) { - val linkData = LinkData( id = mediaDetails?.ids?.tmdb, traktId = mediaDetails?.ids?.trakt, @@ -157,7 +151,7 @@ open class TraktProvider : MainAPI() { year = mediaDetails?.year, orgTitle = mediaDetails?.title, isAnime = isAnime, - //jpTitle = later if needed as it requires another network request, + // jpTitle = later if needed as it requires another network request, airedDate = mediaDetails?.released ?: mediaDetails?.firstAired, isAsian = isAsian, @@ -191,7 +185,6 @@ open class TraktProvider : MainAPI() { addTMDbId(mediaDetails.ids?.tmdb.toString()) } } else { - val resSeasons = getApi("$traktApiUrl/shows/${mediaDetails?.ids?.trakt.toString()}/seasons?extended=full,images,episodes") val episodes = mutableListOf() @@ -199,9 +192,7 @@ open class TraktProvider : MainAPI() { var nextAir: NextAiring? = null seasons.forEach { season -> - season.episodes?.map { episode -> - val linkData = LinkData( id = mediaDetails?.ids?.tmdb, traktId = mediaDetails?.ids?.trakt, @@ -236,7 +227,6 @@ open class TraktProvider : MainAPI() { this.description = episode.overview this.runTime = episode.runtime this.posterUrl = fixPath( episode.images?.screenshot?.firstOrNull()) - //this.rating = episode.rating?.times(10)?.roundToInt() this.score = Score.from10(episode.rating) this.addDate(episode.firstAired, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") @@ -308,153 +298,155 @@ open class TraktProvider : MainAPI() { return "https://$url" } + @Serializable data class Data( - val type: TvType? = null, - val mediaDetails: MediaDetails? = null, + @JsonProperty("type") @SerialName("type") val type: TvType? = null, + @JsonProperty("mediaDetails") @SerialName("mediaDetails") val mediaDetails: MediaDetails? = null, ) + @OptIn(ExperimentalSerializationApi::class) // JsonNames is an experimental annotation for now @Serializable data class MediaDetails( - @SerialName("title") val title: String? = null, - @SerialName("year") val year: Int? = null, - @SerialName("ids") val ids: Ids? = null, - @SerialName("tagline") val tagline: String? = null, - @SerialName("overview") val overview: String? = null, - @SerialName("released") val released: String? = null, - @SerialName("runtime") val runtime: Int? = null, - @SerialName("country") val country: String? = null, - @SerialName("updatedAt") val updatedAt: String? = null, - @SerialName("trailer") val trailer: String? = null, - @SerialName("homepage") val homepage: String? = null, - @SerialName("status") val status: String? = null, - @SerialName("rating") val rating: Double? = null, - @SerialName("votes") val votes: Long? = null, - @SerialName("comment_count") val commentCount: Long? = null, - @SerialName("language") val language: String? = null, - @SerialName("languages") val languages: List? = null, - @SerialName("available_translations") val availableTranslations: List? = null, - @SerialName("genres") val genres: List? = null, - @SerialName("certification") val certification: String? = null, - @SerialName("aired_episodes") val airedEpisodes: Int? = null, - @SerialName("first_aired") val firstAired: String? = null, - @SerialName("airs") val airs: Airs? = null, - @SerialName("network") val network: String? = null, - @SerialName("images") val images: Images? = null, - @SerialName("movie") @JsonNames("show") val media: MediaDetails? = null + @JsonProperty("title") @SerialName("title") val title: String? = null, + @JsonProperty("year") @SerialName("year") val year: Int? = null, + @JsonProperty("ids") @SerialName("ids") val ids: Ids? = null, + @JsonProperty("tagline") @SerialName("tagline") val tagline: String? = null, + @JsonProperty("overview") @SerialName("overview") val overview: String? = null, + @JsonProperty("released") @SerialName("released") val released: String? = null, + @JsonProperty("runtime") @SerialName("runtime") val runtime: Int? = null, + @JsonProperty("country") @SerialName("country") val country: String? = null, + @JsonProperty("updatedAt") @SerialName("updatedAt") val updatedAt: String? = null, + @JsonProperty("trailer") @SerialName("trailer") val trailer: String? = null, + @JsonProperty("homepage") @SerialName("homepage") val homepage: String? = null, + @JsonProperty("status") @SerialName("status") val status: String? = null, + @JsonProperty("rating") @SerialName("rating") val rating: Double? = null, + @JsonProperty("votes") @SerialName("votes") val votes: Long? = null, + @JsonProperty("comment_count") @SerialName("comment_count") val commentCount: Long? = null, + @JsonProperty("language") @SerialName("language") val language: String? = null, + @JsonProperty("languages") @SerialName("languages") val languages: List? = null, + @JsonProperty("available_translations") @SerialName("available_translations") val availableTranslations: List? = null, + @JsonProperty("genres") @SerialName("genres") val genres: List? = null, + @JsonProperty("certification") @SerialName("certification") val certification: String? = null, + @JsonProperty("aired_episodes") @SerialName("aired_episodes") val airedEpisodes: Int? = null, + @JsonProperty("first_aired") @SerialName("first_aired") val firstAired: String? = null, + @JsonProperty("airs") @SerialName("airs") val airs: Airs? = null, + @JsonProperty("network") @SerialName("network") val network: String? = null, + @JsonProperty("images") @SerialName("images") val images: Images? = null, + @JsonProperty("movie") @JsonAlias("show") @SerialName("media") @JsonNames("movie", "show") val media: MediaDetails? = null, ) @Serializable data class Airs( - @SerialName("day") val day: String? = null, - @SerialName("time") val time: String? = null, - @SerialName("timezone") val timezone: String? = null, + @JsonProperty("day") @SerialName("day") val day: String? = null, + @JsonProperty("time") @SerialName("time") val time: String? = null, + @JsonProperty("timezone") @SerialName("timezone") val timezone: String? = null, ) @Serializable data class Ids( - @SerialName("trakt") val trakt: Int? = null, - @SerialName("slug") val slug: String? = null, - @SerialName("tvdb") val tvdb: Int? = null, - @SerialName("imdb") val imdb: String? = null, - @SerialName("tmdb") val tmdb: Int? = null, - @SerialName("tvrage") val tvrage: String? = null, + @JsonProperty("trakt") @SerialName("trakt") val trakt: Int? = null, + @JsonProperty("slug") @SerialName("slug") val slug: String? = null, + @JsonProperty("tvdb") @SerialName("tvdb") val tvdb: Int? = null, + @JsonProperty("imdb") @SerialName("imdb") val imdb: String? = null, + @JsonProperty("tmdb") @SerialName("tmdb") val tmdb: Int? = null, + @JsonProperty("tvrage") @SerialName("tvrage") val tvrage: String? = null, ) @Serializable data class Images( - @SerialName("poster") val poster: List? = null, - @SerialName("fanart") val fanart: List? = null, - @SerialName("logo") val logo: List? = null, - @SerialName("clearart") val clearArt: List? = null, - @SerialName("banner") val banner: List? = null, - @SerialName("thumb") val thumb: List? = null, - @SerialName("screenshot") val screenshot: List? = null, - @SerialName("headshot") val headshot: List? = null, + @JsonProperty("poster") @SerialName("poster") val poster: List? = null, + @JsonProperty("fanart") @SerialName("fanart") val fanart: List? = null, + @JsonProperty("logo") @SerialName("logo") val logo: List? = null, + @JsonProperty("clearart") @SerialName("clearart") val clearArt: List? = null, + @JsonProperty("banner") @SerialName("banner") val banner: List? = null, + @JsonProperty("thumb") @SerialName("thumb") val thumb: List? = null, + @JsonProperty("screenshot") @SerialName("screenshot") val screenshot: List? = null, + @JsonProperty("headshot") @SerialName("headshot") val headshot: List? = null, ) @Serializable data class People( - @SerialName("cast") val cast: List? = null, + @JsonProperty("cast") @SerialName("cast") val cast: List? = null, ) @Serializable data class Cast( - @SerialName("character") val character: String? = null, - @SerialName("characters") val characters: List? = null, - @SerialName("episode_count") val episodeCount: Long? = null, - @SerialName("person") val person: Person? = null, - @SerialName("images") val images: Images? = null, + @JsonProperty("character") @SerialName("character") val character: String? = null, + @JsonProperty("characters") @SerialName("characters") val characters: List? = null, + @JsonProperty("episode_count") @SerialName("episode_count") val episodeCount: Long? = null, + @JsonProperty("person") @SerialName("person") val person: Person? = null, + @JsonProperty("images") @SerialName("images") val images: Images? = null, ) @Serializable data class Person( - @SerialName("name") val name: String? = null, - @SerialName("ids") val ids: Ids? = null, - @SerialName("images") val images: Images? = null, + @JsonProperty("name") @SerialName("name") val name: String? = null, + @JsonProperty("ids") @SerialName("ids") val ids: Ids? = null, + @JsonProperty("images") @SerialName("images") val images: Images? = null, ) @Serializable data class Seasons( - @SerialName("aired_episodes") val airedEpisodes: Int? = null, - @SerialName("episode_count") val episodeCount: Int? = null, - @SerialName("episodes") val episodes: List? = null, - @SerialName("first_aired") val firstAired: String? = null, - @SerialName("ids") val ids: Ids? = null, - @SerialName("images") val images: Images? = null, - @SerialName("network") val network: String? = null, - @SerialName("number") val number: Int? = null, - @SerialName("overview") val overview: String? = null, - @SerialName("rating") val rating: Double? = null, - @SerialName("title") val title: String? = null, - @SerialName("updated_at") val updatedAt: String? = null, - @SerialName("votes") val votes: Int? = null, + @JsonProperty("aired_episodes") @SerialName("aired_episodes") val airedEpisodes: Int? = null, + @JsonProperty("episode_count") @SerialName("episode_count") val episodeCount: Int? = null, + @JsonProperty("episodes") @SerialName("episodes") val episodes: List? = null, + @JsonProperty("first_aired") @SerialName("first_aired") val firstAired: String? = null, + @JsonProperty("ids") @SerialName("ids") val ids: Ids? = null, + @JsonProperty("images") @SerialName("images") val images: Images? = null, + @JsonProperty("network") @SerialName("network") val network: String? = null, + @JsonProperty("number") @SerialName("number") val number: Int? = null, + @JsonProperty("overview") @SerialName("overview") val overview: String? = null, + @JsonProperty("rating") @SerialName("rating") val rating: Double? = null, + @JsonProperty("title") @SerialName("title") val title: String? = null, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String? = null, + @JsonProperty("votes") @SerialName("votes") val votes: Int? = null, ) @Serializable data class TraktEpisode( - @SerialName("available_translations") val availableTranslations: List? = null, - @SerialName("comment_count") val commentCount: Int? = null, - @SerialName("episode_type") val episodeType: String? = null, - @SerialName("first_aired") val firstAired: String? = null, - @SerialName("ids") val ids: Ids? = null, - @SerialName("images") val images: Images? = null, - @SerialName("number") val number: Int? = null, - @SerialName("number_abs") val numberAbs: Int? = null, - @SerialName("overview") val overview: String? = null, - @SerialName("rating") val rating: Double? = null, - @SerialName("runtime") val runtime: Int? = null, - @SerialName("season") val season: Int? = null, - @SerialName("title") val title: String? = null, - @SerialName("updated_at") val updatedAt: String? = null, - @SerialName("votes") val votes: Int? = null, + @JsonProperty("available_translations") @SerialName("available_translations") val availableTranslations: List? = null, + @JsonProperty("comment_count") @SerialName("comment_count") val commentCount: Int? = null, + @JsonProperty("episode_type") @SerialName("episode_type") val episodeType: String? = null, + @JsonProperty("first_aired") @SerialName("first_aired") val firstAired: String? = null, + @JsonProperty("ids") @SerialName("ids") val ids: Ids? = null, + @JsonProperty("images") @SerialName("images") val images: Images? = null, + @JsonProperty("number") @SerialName("number") val number: Int? = null, + @JsonProperty("number_abs") @SerialName("number_abs") val numberAbs: Int? = null, + @JsonProperty("overview") @SerialName("overview") val overview: String? = null, + @JsonProperty("rating") @SerialName("rating") val rating: Double? = null, + @JsonProperty("runtime") @SerialName("runtime") val runtime: Int? = null, + @JsonProperty("season") @SerialName("season") val season: Int? = null, + @JsonProperty("title") @SerialName("title") val title: String? = null, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String? = null, + @JsonProperty("votes") @SerialName("votes") val votes: Int? = null, ) @Serializable data class LinkData( - @SerialName("id") val id: Int? = null, - @SerialName("trakt_id") val traktId: Int? = null, - @SerialName("trakt_slug") val traktSlug: String? = null, - @SerialName("tmdb_id") val tmdbId: Int? = null, - @SerialName("imdb_id") val imdbId: String? = null, - @SerialName("tvdb_id") val tvdbId: Int? = null, - @SerialName("tvrage_id") val tvrageId: String? = null, - @SerialName("type") val type: String? = null, - @SerialName("season") val season: Int? = null, - @SerialName("episode") val episode: Int? = null, - @SerialName("ani_id") val aniId: String? = null, - @SerialName("anime_id") val animeId: String? = null, - @SerialName("title") val title: String? = null, - @SerialName("year") val year: Int? = null, - @SerialName("org_title") val orgTitle: String? = null, - @SerialName("is_anime") val isAnime: Boolean = false, - @SerialName("aired_year") val airedYear: Int? = null, - @SerialName("last_season") val lastSeason: Int? = null, - @SerialName("eps_title") val epsTitle: String? = null, - @SerialName("jp_title") val jpTitle: String? = null, - @SerialName("date") val date: String? = null, - @SerialName("aired_date") val airedDate: String? = null, - @SerialName("is_asian") val isAsian: Boolean = false, - @SerialName("is_bollywood") val isBollywood: Boolean = false, - @SerialName("is_cartoon") val isCartoon: Boolean = false, + @JsonProperty("id") @SerialName("id") val id: Int? = null, + @JsonProperty("trakt_id") @SerialName("trakt_id") val traktId: Int? = null, + @JsonProperty("trakt_slug") @SerialName("trakt_slug") val traktSlug: String? = null, + @JsonProperty("tmdb_id") @SerialName("tmdb_id") val tmdbId: Int? = null, + @JsonProperty("imdb_id") @SerialName("imdb_id") val imdbId: String? = null, + @JsonProperty("tvdb_id") @SerialName("tvdb_id") val tvdbId: Int? = null, + @JsonProperty("tvrage_id") @SerialName("tvrage_id") val tvrageId: String? = null, + @JsonProperty("type") @SerialName("type") val type: String? = null, + @JsonProperty("season") @SerialName("season") val season: Int? = null, + @JsonProperty("episode") @SerialName("episode") val episode: Int? = null, + @JsonProperty("ani_id") @SerialName("ani_id") val aniId: String? = null, + @JsonProperty("anime_id") @SerialName("anime_id") val animeId: String? = null, + @JsonProperty("title") @SerialName("title") val title: String? = null, + @JsonProperty("year") @SerialName("year") val year: Int? = null, + @JsonProperty("org_title") @SerialName("org_title") val orgTitle: String? = null, + @JsonProperty("is_anime") @SerialName("is_anime") val isAnime: Boolean = false, + @JsonProperty("aired_year") @SerialName("aired_year") val airedYear: Int? = null, + @JsonProperty("last_season") @SerialName("last_season") val lastSeason: Int? = null, + @JsonProperty("eps_title") @SerialName("eps_title") val epsTitle: String? = null, + @JsonProperty("jp_title") @SerialName("jp_title") val jpTitle: String? = null, + @JsonProperty("date") @SerialName("date") val date: String? = null, + @JsonProperty("aired_date") @SerialName("aired_date") val airedDate: String? = null, + @JsonProperty("is_asian") @SerialName("is_asian") val isAsian: Boolean = false, + @JsonProperty("is_bollywood") @SerialName("is_bollywood") val isBollywood: Boolean = false, + @JsonProperty("is_cartoon") @SerialName("is_cartoon") val isCartoon: Boolean = false, ) } From 76fde002e644e43234eb4d955811e3c4f5945c25 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:06:11 -0600 Subject: [PATCH 084/192] Update MDL --- .../cloudstream3/metaproviders/MyDramaList.kt | 270 ++++++++++-------- 1 file changed, 146 insertions(+), 124 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt index 4d143b7df13..b50a548fadf 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt @@ -1,8 +1,6 @@ package com.lagradost.cloudstream3.metaproviders -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlinx.serialization.json.JsonElement +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.api.BuildConfig import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.Actor @@ -31,10 +29,13 @@ import com.lagradost.cloudstream3.newTvSeriesLoadResponse import com.lagradost.cloudstream3.newTvSeriesSearchResponse import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson -import com.lagradost.nicehttp.HeadersInterceptor -import io.ktor.http.HttpHeaders +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement +import okhttp3.Interceptor +import okhttp3.Response -//Reference: https://mydramalist.github.io/MDL-API/ +// Reference: https://mydramalist.github.io/MDL-API/ abstract class MyDramaListAPI : MainAPI() { override var name = "MyDramaList" override val hasMainPage = true @@ -50,9 +51,19 @@ abstract class MyDramaListAPI : MainAPI() { val API_KEY: String = BuildConfig.MDL_API_KEY const val API_HOST = "https://api.mydramalist.com/v1" const val SITE_HOST = "https://mydramalist.com" - private val headerInterceptor = HeadersInterceptor { - header(HttpHeaders.UserAgent, "Dart/3.6 (dart:io)") - header("mdl-api-key", API_KEY) + private val headerInterceptor = MyDramaListInterceptor() + } + + /** Automatically adds required api headers */ + private class MyDramaListInterceptor : Interceptor { + override fun intercept(chain: Interceptor.Chain): Response { + return chain.proceed( + chain.request().newBuilder() + .removeHeader("user-agent") + .addHeader("user-agent", "Dart/3.6 (dart:io)") + .addHeader("mdl-api-key", API_KEY) + .build() + ) } } @@ -66,19 +77,21 @@ abstract class MyDramaListAPI : MainAPI() { ) override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse { - val list = app.get("${request.data}&limit=20&page=$page&lang=en-US") { + val list = app.get( + url = "${request.data}&limit=20&page=$page&lang=en-US", interceptor = headerInterceptor - }.parsed().map { element -> + ).parsed().map { element -> element.toSearchResponse() } return newHomePageResponse(request.name, list) } override suspend fun search(query: String): List? { - return app.post("$API_HOST/search/titles") { - data = mapOf("q" to query) + return app.post( + url = "$API_HOST/search/titles", + data = mapOf("q" to query), interceptor = headerInterceptor - }.parsed().map { element -> + ).parsed().map { element -> element.toSearchResponse() } } @@ -115,9 +128,10 @@ abstract class MyDramaListAPI : MainAPI() { override suspend fun load(url: String): LoadResponse { val data = parseJson(url) - return app.get("$API_HOST/titles/${data.media?.id}") { + return app.get( + url = "$API_HOST/titles/${data.media?.id}", interceptor = headerInterceptor - }.parsed().toLoadResponse(data) + ).parsed().toLoadResponse(data) } private suspend fun Media.toLoadResponse(data: Data): LoadResponse { @@ -199,77 +213,81 @@ abstract class MyDramaListAPI : MainAPI() { } } + @Serializable data class Data( - val type: TvType? = null, - val media: MediaSummary? = null, + @JsonProperty("type") @SerialName("type") val type: TvType? = null, + @JsonProperty("media") @SerialName("media") val media: MediaSummary? = null, ) + @Serializable class SearchResult : ArrayList() + @Serializable class Recommendations : ArrayList() @Serializable data class MediaSummary( - @SerialName("id") val id: Long, - @SerialName("title") val title: String, - @SerialName("original_title") val originalTitle: String, - @SerialName("year") val year: Int? = null, - @SerialName("rating") val rating: Double? = null, - @SerialName("permalink") val permalink: String? = null, - @SerialName("type") val type: String, - @SerialName("media_type") val mediaType: String? = null, - @SerialName("country") val country: String? = null, - @SerialName("language") val language: String? = null, - @SerialName("images") val images: Images, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("title") @SerialName("title") val title: String, + @JsonProperty("original_title") @SerialName("original_title") val originalTitle: String, + @JsonProperty("year") @SerialName("year") val year: Int? = null, + @JsonProperty("rating") @SerialName("rating") val rating: Double? = null, + @JsonProperty("permalink") @SerialName("permalink") val permalink: String? = null, + @JsonProperty("type") @SerialName("type") val type: String, + @JsonProperty("media_type") @SerialName("media_type") val mediaType: String? = null, + @JsonProperty("country") @SerialName("country") val country: String? = null, + @JsonProperty("language") @SerialName("language") val language: String? = null, + @JsonProperty("images") @SerialName("images") val images: Images, ) @Serializable data class Images( - @SerialName("thumb") val thumb: String? = null, - @SerialName("medium") val medium: String? = null, - @SerialName("poster") val poster: String? = null, + @JsonProperty("thumb") @SerialName("thumb") val thumb: String? = null, + @JsonProperty("medium") @SerialName("medium") val medium: String? = null, + @JsonProperty("poster") @SerialName("poster") val poster: String? = null, ) @Serializable data class Media( - @SerialName("id") val id: Long, - @SerialName("slug") val slug: String, - @SerialName("title") val title: String, - @SerialName("original_title") val originalTitle: String, - @SerialName("year") val mediaYear: Int, - @SerialName("episodes") val episodes: Long, - @SerialName("rating") val mediaRating: Double, - @SerialName("permalink") val permalink: String? = null, - @SerialName("synopsis") val synopsis: String? = null, - @SerialName("type") val type: String? = null, - @SerialName("media_type") val mediaType: String? = null, - @SerialName("country") val country: String? = null, - @SerialName("language") val language: String? = null, - @SerialName("images") val images: Images, - @SerialName("alt_titles") val altTitles: List? = null, - @SerialName("votes") val votes: Long? = null, - @SerialName("aired_start") val airedStart: String? = null, - @SerialName("released") val released: String? = null, - @SerialName("release_dates_fmt") val releaseDatesFmt: String, - @SerialName("genres") val genres: List? = null, - @SerialName("trailer") val trailer: Trailer?, - @SerialName("watchers") val watchers: Long, - @SerialName("ranked") val ranked: Long, - @SerialName("popularity") val popularity: Long, - @SerialName("runtime") val runtime: Long, - @SerialName("reviews_count") val reviewsCount: Long, - @SerialName("recs_count") val recsCount: Long, - @SerialName("comments_count") val commentsCount: Long, - @SerialName("certification") val certification: String, - @SerialName("status") val status: String, - @SerialName("enable_ads") val enableAds: Boolean, - @SerialName("sources") val sources: List, - @SerialName("updated_at") val updatedAt: Long, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("slug") @SerialName("slug") val slug: String, + @JsonProperty("title") @SerialName("title") val title: String, + @JsonProperty("original_title") @SerialName("original_title") val originalTitle: String, + @JsonProperty("year") @SerialName("year") val mediaYear: Int, + @JsonProperty("episodes") @SerialName("episodes") val episodes: Long, + @JsonProperty("rating") @SerialName("rating") val mediaRating: Double, + @JsonProperty("permalink") @SerialName("permalink") val permalink: String? = null, + @JsonProperty("synopsis") @SerialName("synopsis") val synopsis: String? = null, + @JsonProperty("type") @SerialName("type") val type: String? = null, + @JsonProperty("media_type") @SerialName("media_type") val mediaType: String? = null, + @JsonProperty("country") @SerialName("country") val country: String? = null, + @JsonProperty("language") @SerialName("language") val language: String? = null, + @JsonProperty("images") @SerialName("images") val images: Images, + @JsonProperty("alt_titles") @SerialName("alt_titles") val altTitles: List? = null, + @JsonProperty("votes") @SerialName("votes") val votes: Long? = null, + @JsonProperty("aired_start") @SerialName("aired_start") val airedStart: String? = null, + @JsonProperty("released") @SerialName("released") val released: String? = null, + @JsonProperty("release_dates_fmt") @SerialName("release_dates_fmt") val releaseDatesFmt: String, + @JsonProperty("genres") @SerialName("genres") val genres: List? = null, + @JsonProperty("trailer") @SerialName("trailer") val trailer: Trailer?, + @JsonProperty("watchers") @SerialName("watchers") val watchers: Long, + @JsonProperty("ranked") @SerialName("ranked") val ranked: Long, + @JsonProperty("popularity") @SerialName("popularity") val popularity: Long, + @JsonProperty("runtime") @SerialName("runtime") val runtime: Long, + @JsonProperty("reviews_count") @SerialName("reviews_count") val reviewsCount: Long, + @JsonProperty("recs_count") @SerialName("recs_count") val recsCount: Long, + @JsonProperty("comments_count") @SerialName("comments_count") val commentsCount: Long, + @JsonProperty("certification") @SerialName("certification") val certification: String, + @JsonProperty("status") @SerialName("status") val status: String, + @JsonProperty("enable_ads") @SerialName("enable_ads") val enableAds: Boolean, + @JsonProperty("sources") @SerialName("sources") val sources: List, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: Long, ) { suspend fun fetchCredits(): List { - val actors = app.get("$API_HOST/titles/$id/credits") { + val actors = app.get( + url = "$API_HOST/titles/$id/credits", interceptor = headerInterceptor - }.parsed().cast.map { + ).parsed().cast.map { ActorData( Actor( name = it.name, @@ -282,15 +300,17 @@ abstract class MyDramaListAPI : MainAPI() { } suspend fun fetchRecommendations(): Recommendations { - return app.get("$API_HOST/titles/$id/recommendations") { + return app.get( + url = "$API_HOST/titles/$id/recommendations", interceptor = headerInterceptor - }.parsed() + ).parsed() } suspend fun fetchTrailer(): String? { - return app.get("$SITE_HOST/v1/trailers/${trailer?.id}") { + return app.get( + url = "$SITE_HOST/v1/trailers/${trailer?.id}", interceptor = headerInterceptor - }.parsedSafe()?.trailer?.trailerDetails?.source + ).parsedSafe()?.trailer?.trailerDetails?.source } fun fixGenres(): List { @@ -305,9 +325,10 @@ abstract class MyDramaListAPI : MainAPI() { } private suspend fun Media.fetchEpisodes(): List { - return app.get("$API_HOST/titles/${this.id}/episodes") { + return app.get( + url = "$API_HOST/titles/${this.id}/episodes", interceptor = headerInterceptor - }.parsed().map { + ).parsed().map { it.episodes }.flatten().map { ep -> val link = LinkData( @@ -338,106 +359,107 @@ abstract class MyDramaListAPI : MainAPI() { @Serializable data class Genre( - @SerialName("id") val id: Long, - @SerialName("name") val name: String, - @SerialName("slug") val slug: String, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("slug") @SerialName("slug") val slug: String, ) @Serializable data class Tag( - @SerialName("id") val id: Long, - @SerialName("name") val name: String, - @SerialName("slug") val slug: String, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("slug") @SerialName("slug") val slug: String, ) @Serializable data class Source( - @SerialName("xid") val xid: String, - @SerialName("name") val name: String, - @SerialName("source") val source: String, - @SerialName("source_type") val sourceType: String, - @SerialName("link") val link: String, - @SerialName("image") val image: String, + @JsonProperty("xid") @SerialName("xid") val xid: String, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("source") @SerialName("source") val source: String, + @JsonProperty("source_type") @SerialName("source_type") val sourceType: String, + @JsonProperty("link") @SerialName("link") val link: String, + @JsonProperty("image") @SerialName("image") val image: String, ) @Serializable data class Trailer( - @SerialName("id") val id: Long? = null, + @JsonProperty("id") @SerialName("id") val id: Long? = null, ) @Serializable data class Credits( - @SerialName("cast") val cast: List, - @SerialName("crew") val crew: List, + @JsonProperty("cast") @SerialName("cast") val cast: List, + @JsonProperty("crew") @SerialName("crew") val crew: List, ) @Serializable data class Cast( - @SerialName("id") val id: Long, - @SerialName("name") val name: String, - @SerialName("url") val url: String, - @SerialName("slug") val slug: String, - @SerialName("images") val images: Images, - @SerialName("character_name") val characterName: String, - @SerialName("role") val role: String, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("url") @SerialName("url") val url: String, + @JsonProperty("slug") @SerialName("slug") val slug: String, + @JsonProperty("images") @SerialName("images") val images: Images, + @JsonProperty("character_name") @SerialName("character_name") val characterName: String, + @JsonProperty("role") @SerialName("role") val role: String, ) @Serializable data class Crew( - @SerialName("id") val id: Long, - @SerialName("name") val name: String, - @SerialName("slug") val slug: String, - @SerialName("images") val images: Images, - @SerialName("job") val job: String, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("slug") @SerialName("slug") val slug: String, + @JsonProperty("images") @SerialName("images") val images: Images, + @JsonProperty("job") @SerialName("job") val job: String, ) + @Serializable class ShowEpisodes : ArrayList() @Serializable data class ShowEpisodesItem( - @SerialName("name") val name: String, - @SerialName("release_date") val releaseDate: String, - @SerialName("episodes") val episodes: List, - @SerialName("timezone") val timezone: String, - @SerialName("total") val total: Int, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("release_date") @SerialName("release_date") val releaseDate: String, + @JsonProperty("episodes") @SerialName("episodes") val episodes: List, + @JsonProperty("timezone") @SerialName("timezone") val timezone: String, + @JsonProperty("total") @SerialName("total") val total: Int, ) @Serializable data class ShowEpisode( - @SerialName("id") val id: Int, - @SerialName("episode_number") val episodeNumber: Int, - @SerialName("rating") val rating: Double, - @SerialName("votes") val votes: Int, - @SerialName("released_at") val releasedAt: String, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("episode_number") @SerialName("episode_number") val episodeNumber: Int, + @JsonProperty("rating") @SerialName("rating") val rating: Double, + @JsonProperty("votes") @SerialName("votes") val votes: Int, + @JsonProperty("released_at") @SerialName("released_at") val releasedAt: String, ) @Serializable data class TrailerRoot( - @SerialName("trailer") val trailer: TrailerNode, + @JsonProperty("trailer") @SerialName("trailer") val trailer: TrailerNode, ) @Serializable data class TrailerNode( - @SerialName("trailer") val trailerDetails: TrailerDetails, + @JsonProperty("trailer") @SerialName("trailer") val trailerDetails: TrailerDetails, ) @Serializable data class TrailerDetails( - @SerialName("id") val id: Long, - @SerialName("source") val source: String, + @JsonProperty("id") @SerialName("id") val id: Long, + @JsonProperty("source") @SerialName("source") val source: String, ) @Serializable data class LinkData( - @SerialName("id") val id: Long? = null, - @SerialName("type") val type: String? = null, - @SerialName("season") val season: Int? = null, - @SerialName("episode") val episode: Int? = null, - @SerialName("title") val title: String? = null, - @SerialName("year") val year: Int? = null, - @SerialName("orgTitle") val orgTitle: String? = null, - @SerialName("lastSeason") val lastSeason: Int? = null, - @SerialName("date") val date: String? = null, - @SerialName("airedDate") val airedDate: String? = null, + @JsonProperty("id") @SerialName("id") val id: Long? = null, + @JsonProperty("type") @SerialName("type") val type: String? = null, + @JsonProperty("season") @SerialName("season") val season: Int? = null, + @JsonProperty("episode") @SerialName("episode") val episode: Int? = null, + @JsonProperty("title") @SerialName("title") val title: String? = null, + @JsonProperty("year") @SerialName("year") val year: Int? = null, + @JsonProperty("orgTitle") @SerialName("orgTitle") val orgTitle: String? = null, + @JsonProperty("lastSeason") @SerialName("lastSeason") val lastSeason: Int? = null, + @JsonProperty("date") @SerialName("date") val date: String? = null, + @JsonProperty("airedDate") @SerialName("airedDate") val airedDate: String? = null, ) } From 895d5f50166f0287f7c9fd69de97d65ebaddd306 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:07:36 -0600 Subject: [PATCH 085/192] Update --- .../cloudstream3/syncproviders/AuthAPI.kt | 69 +++++++++---------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 4c9d7fe5b98..9dc6b762f50 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -7,8 +7,10 @@ import com.lagradost.cloudstream3.APIHolder.unixTimeMS import com.lagradost.cloudstream3.base64Encode import com.lagradost.cloudstream3.syncproviders.AccountManager.Companion.APP_STRING import com.lagradost.cloudstream3.utils.AppContextUtils.splitQuery +import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonNames import java.net.URI import java.security.SecureRandom @@ -18,7 +20,7 @@ data class AuthLoginPage( /** * State/control code to verify against the redirectUrl to make sure the request is valid. * This parameter will be saved, and then used in AuthAPI::login. - * */ + */ val payload: String? = null, ) @@ -26,25 +28,24 @@ data class AuthLoginPage( data class AuthToken( /** * This is the general access tokens/api token representing a logged in user. - * - * `Access tokens are the thing that applications use to make API requests on behalf of a user.` - * */ - @SerialName("accessToken") + * Access tokens are the thing that applications use to make API requests on behalf of a user. + */ + @JsonProperty("accessToken") @SerialName("accessToken") val accessToken: String? = null, - /** - * For OAuth a special refresh token is issues to refresh the access token. - * */ - @SerialName("refreshToken") + /** For OAuth a special refresh token is issues to refresh the access token. */ + @JsonProperty("refreshToken") @SerialName("refreshToken") val refreshToken: String? = null, /** In UnixTime (sec) when it expires */ - @SerialName("accessTokenLifetime") + @JsonProperty("accessTokenLifetime") @SerialName("accessTokenLifetime") val accessTokenLifetime: Long? = null, /** In UnixTime (sec) when it expires */ - @SerialName("refreshTokenLifetime") + @JsonProperty("refreshTokenLifetime") @SerialName("refreshTokenLifetime") val refreshTokenLifetime: Long? = null, - /** Sometimes AuthToken needs to be customized to store e.g. username/password, - * this acts as a catch all to store text or JSON data. */ - @SerialName("payload") + /** + * Sometimes AuthToken needs to be customized to store e.g. username/password, + * this acts as a catch all to store text or JSON data. + */ + @JsonProperty("payload") @SerialName("payload") val payload: String? = null, ) { fun isAccessTokenExpired(marginSec: Long = 10L) = @@ -54,21 +55,25 @@ data class AuthToken( refreshTokenLifetime != null && unixTime + marginSec >= refreshTokenLifetime } +@OptIn(ExperimentalSerializationApi::class) // JsonNames is an experimental annotation for now @Serializable data class AuthUser( /** Account display-name, can also be email if name does not exist */ - @SerialName("name") + @JsonProperty("name") @SerialName("name") val name: String?, - /** Unique account identifier, - * if a subsequent login is done then it will be refused if another account with the same id exists*/ - @SerialName("id") + /** + * Unique account identifier. If a subsequent login is done then it + * will be refused if another account with the same id exists. + */ + @JsonProperty("id") @SerialName("id") val id: Int, /** Profile picture URL */ - @SerialName("profilePicture") + @JsonProperty("profilePicture") @SerialName("profilePicture") val profilePicture: String? = null, /** Profile picture Headers of the URL */ - @SerialName("profilePictureHeader") - val profilePictureHeaders: Map? = null + @JsonProperty("profilePictureHeader") + @SerialName("profilePictureHeaders") @JsonNames("profilePictureHeader") + val profilePictureHeaders: Map? = null, ) /** @@ -78,13 +83,11 @@ data class AuthUser( * * Any local set/get key should use user.id.toString(), * as token.accessToken (even hashed) is unsecure, and will rotate. - * */ + */ @Serializable data class AuthData( - @SerialName("user") - val user: AuthUser, - @SerialName("token") - val token: AuthToken, + @JsonProperty("user") @SerialName("user") val user: AuthUser, + @JsonProperty("token") @SerialName("token") val token: AuthToken, ) data class AuthPinData( @@ -109,14 +112,10 @@ data class AuthLoginRequirement( /** What the user responds to the AuthLoginRequirement */ @Serializable data class AuthLoginResponse( - @SerialName("password") - val password: String?, - @SerialName("username") - val username: String?, - @SerialName("email") - val email: String?, - @SerialName("server") - val server: String?, + @JsonProperty("password") @SerialName("password") val password: String?, + @JsonProperty("username") @SerialName("username") val username: String?, + @JsonProperty("email") @SerialName("email") val email: String?, + @JsonProperty("server") @SerialName("server") val server: String?, ) /** Stateless Authentication class used for all personalized content */ @@ -229,7 +228,7 @@ abstract class AuthAPI { * * Note that this will currently only be called *once* on logout, * and as such any network issues it will fail silently, and the token will not be revoked. - **/ + */ @Throws open suspend fun invalidateToken(token: AuthToken): Nothing = throw NotImplementedError() From 326b71bbbe51968a03fb4b793bcd8967bc68a6a8 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:18:46 -0600 Subject: [PATCH 086/192] Fix --- .../cloudstream3/metaproviders/MyDramaList.kt | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt index b50a548fadf..9a0d68d542e 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/MyDramaList.kt @@ -80,7 +80,7 @@ abstract class MyDramaListAPI : MainAPI() { val list = app.get( url = "${request.data}&limit=20&page=$page&lang=en-US", interceptor = headerInterceptor - ).parsed().map { element -> + ).parsed>().map { element -> element.toSearchResponse() } return newHomePageResponse(request.name, list) @@ -91,7 +91,7 @@ abstract class MyDramaListAPI : MainAPI() { url = "$API_HOST/search/titles", data = mapOf("q" to query), interceptor = headerInterceptor - ).parsed().map { element -> + ).parsed>().map { element -> element.toSearchResponse() } } @@ -219,12 +219,6 @@ abstract class MyDramaListAPI : MainAPI() { @JsonProperty("media") @SerialName("media") val media: MediaSummary? = null, ) - @Serializable - class SearchResult : ArrayList() - - @Serializable - class Recommendations : ArrayList() - @Serializable data class MediaSummary( @JsonProperty("id") @SerialName("id") val id: Long, @@ -299,11 +293,11 @@ abstract class MyDramaListAPI : MainAPI() { return actors } - suspend fun fetchRecommendations(): Recommendations { + suspend fun fetchRecommendations(): List { return app.get( url = "$API_HOST/titles/$id/recommendations", interceptor = headerInterceptor - ).parsed() + ).parsed>() } suspend fun fetchTrailer(): String? { @@ -328,7 +322,7 @@ abstract class MyDramaListAPI : MainAPI() { return app.get( url = "$API_HOST/titles/${this.id}/episodes", interceptor = headerInterceptor - ).parsed().map { + ).parsed>().map { it.episodes }.flatten().map { ep -> val link = LinkData( @@ -412,9 +406,6 @@ abstract class MyDramaListAPI : MainAPI() { @JsonProperty("job") @SerialName("job") val job: String, ) - @Serializable - class ShowEpisodes : ArrayList() - @Serializable data class ShowEpisodesItem( @JsonProperty("name") @SerialName("name") val name: String, From 52a017d8f2af720616cba5a1a213050a25b077b7 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:30:51 -0600 Subject: [PATCH 087/192] Fix --- .../java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt index 9dc6b762f50..60e41e8b3d5 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/AuthAPI.kt @@ -1,5 +1,6 @@ package com.lagradost.cloudstream3.syncproviders +import com.fasterxml.jackson.annotation.JsonAlias import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder import com.lagradost.cloudstream3.APIHolder.unixTime @@ -71,7 +72,7 @@ data class AuthUser( @JsonProperty("profilePicture") @SerialName("profilePicture") val profilePicture: String? = null, /** Profile picture Headers of the URL */ - @JsonProperty("profilePictureHeader") + @JsonProperty("profilePictureHeaders") @JsonAlias("profilePictureHeader") @SerialName("profilePictureHeaders") @JsonNames("profilePictureHeader") val profilePictureHeaders: Map? = null, ) From 64fa0594d94f629e70bba991e9289c7a2baab998 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:40:51 -0600 Subject: [PATCH 088/192] Fix trakt --- .../com/lagradost/cloudstream3/metaproviders/TraktProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt index 04fb6174c7c..2330678086f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -332,7 +332,7 @@ open class TraktProvider : MainAPI() { @JsonProperty("airs") @SerialName("airs") val airs: Airs? = null, @JsonProperty("network") @SerialName("network") val network: String? = null, @JsonProperty("images") @SerialName("images") val images: Images? = null, - @JsonProperty("movie") @JsonAlias("show") @SerialName("media") @JsonNames("movie", "show") val media: MediaDetails? = null, + @JsonProperty("media") @JsonAlias({ "movie", "show" }) @SerialName("media") @JsonNames("movie", "show") val media: MediaDetails? = null, ) @Serializable From 6e7bb284b3cdb7f061f2d8d7fb30b6eadfd2066a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:42:56 -0600 Subject: [PATCH 089/192] Fix --- .../com/lagradost/cloudstream3/metaproviders/TraktProvider.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt index 2330678086f..22a264898b0 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -332,7 +332,7 @@ open class TraktProvider : MainAPI() { @JsonProperty("airs") @SerialName("airs") val airs: Airs? = null, @JsonProperty("network") @SerialName("network") val network: String? = null, @JsonProperty("images") @SerialName("images") val images: Images? = null, - @JsonProperty("media") @JsonAlias({ "movie", "show" }) @SerialName("media") @JsonNames("movie", "show") val media: MediaDetails? = null, + @JsonProperty("media") @JsonAlias("movie", "show") @SerialName("media") @JsonNames("movie", "show") val media: MediaDetails? = null, ) @Serializable From 7af8234d5067067fe5c7a5e9c2712b5d4dea555e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 15:52:43 -0600 Subject: [PATCH 090/192] Order --- .../com/lagradost/cloudstream3/plugins/BasePlugin.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt index c741cf650fa..d214a044ad7 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/plugins/BasePlugin.kt @@ -68,10 +68,10 @@ abstract class BasePlugin { @SerialName("pluginClassName") var pluginClassName: String? = null - @SerialName("version") - var version: Int? = null - @SerialName("requiresResources") var requiresResources: Boolean = false + + @SerialName("version") + var version: Int? = null } -} \ No newline at end of file +} From 0007b20ef05040f6120341f978354b75c72103bb Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:42:42 -0600 Subject: [PATCH 091/192] Try change --- .github/workflows/pull_request.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index c4b432fbb7e..058aab24651 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,6 +1,9 @@ name: Artifact Build -on: [pull_request] +on: + pull_request: + issue_comment: + types: [created] permissions: contents: read @@ -8,6 +11,7 @@ permissions: jobs: build: runs-on: ubuntu-latest + if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v6 @@ -37,8 +41,14 @@ jobs: instrumented-tests: runs-on: ubuntu-latest + if: | + github.event_name == 'issue_comment' && + github.event.issue.pull_request && + contains(github.event.comment.body, 'run tests') steps: - uses: actions/checkout@v6 + with: + ref: refs/pull/${{ github.event.issue.number }}/head - name: Set up JDK 17 uses: actions/setup-java@v5 From 9c87eab9bf9c54721d0ef70d3d730caeb449d3b3 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:47:31 -0600 Subject: [PATCH 092/192] Update --- .github/workflows/pull_request.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 058aab24651..be244c68901 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -7,6 +7,7 @@ on: permissions: contents: read + pull-requests: read jobs: build: From 58bc3bce8df5b0b7035aac7c6a12b1a17ae8b0a3 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:50:42 -0600 Subject: [PATCH 093/192] Update --- .github/workflows/pull_request.yml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index be244c68901..23bcb420f3b 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -42,10 +42,7 @@ jobs: instrumented-tests: runs-on: ubuntu-latest - if: | - github.event_name == 'issue_comment' && - github.event.issue.pull_request && - contains(github.event.comment.body, 'run tests') + if: ${{ github.event.issue.pull_request && github.event.comment.body == '/run-tests' }} steps: - uses: actions/checkout@v6 with: From 66b4a52c01d4ea11bd38b1a8c54aaa6fdc47b37a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:54:09 -0600 Subject: [PATCH 094/192] + --- .github/workflows/pull_request.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 23bcb420f3b..a5f20eed841 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -7,6 +7,7 @@ on: permissions: contents: read + issues: read pull-requests: read jobs: From cd268e80249a3275d3f7a87093f8624d788ad3e5 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:55:15 -0600 Subject: [PATCH 095/192] - --- .github/workflows/pull_request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index a5f20eed841..0992658bade 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -43,7 +43,7 @@ jobs: instrumented-tests: runs-on: ubuntu-latest - if: ${{ github.event.issue.pull_request && github.event.comment.body == '/run-tests' }} + if: ${{ github.event.comment.body == '/run-tests' }} steps: - uses: actions/checkout@v6 with: From 762e63e97efe4277ab2f91e145b90e8eca4af26a Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:56:38 -0600 Subject: [PATCH 096/192] Update --- .github/workflows/pull_request.yml | 58 +----------------------------- 1 file changed, 1 insertion(+), 57 deletions(-) diff --git a/.github/workflows/pull_request.yml b/.github/workflows/pull_request.yml index 0992658bade..8f5c6286636 100644 --- a/.github/workflows/pull_request.yml +++ b/.github/workflows/pull_request.yml @@ -1,19 +1,13 @@ name: Artifact Build -on: - pull_request: - issue_comment: - types: [created] +on: [pull_request] permissions: contents: read - issues: read - pull-requests: read jobs: build: runs-on: ubuntu-latest - if: github.event_name == 'pull_request' steps: - uses: actions/checkout@v6 @@ -40,53 +34,3 @@ jobs: with: name: pull-request-build path: "app/build/outputs/apk/prerelease/debug/*.apk" - - instrumented-tests: - runs-on: ubuntu-latest - if: ${{ github.event.comment.body == '/run-tests' }} - steps: - - uses: actions/checkout@v6 - with: - ref: refs/pull/${{ github.event.issue.number }}/head - - - name: Set up JDK 17 - uses: actions/setup-java@v5 - with: - distribution: temurin - java-version: 17 - - - name: Grant execute permission for gradlew - run: chmod +x gradlew - - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 - with: - cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} - cache-read-only: false - - - name: Get target SDK - id: sdk - run: | - TARGET_SDK=$(grep 'targetSdk' gradle/libs.versions.toml | grep -o '[0-9]\+' | head -1) - echo "version=$TARGET_SDK" >> $GITHUB_OUTPUT - - - name: Enable KVM - run: | - echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules - sudo udevadm control --reload-rules - sudo udevadm trigger --name-match=kvm - - - name: Run Instrumented Tests - uses: reactivecircus/android-emulator-runner@v2 - with: - api-level: ${{ steps.sdk.outputs.version }} - arch: x86_64 - profile: Nexus 6 - script: ./gradlew connectedPrereleaseDebugAndroidTest - - - name: Upload Test Results - if: always() - uses: actions/upload-artifact@v7 - with: - name: instrumented-test-results - path: '**/build/reports/androidTests/' From 430069fb6d3b3f4aa72ef802420cddda0b1fd202 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 16:57:35 -0600 Subject: [PATCH 097/192] Add --- .github/workflows/instrumented-tests.yml | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 .github/workflows/instrumented-tests.yml diff --git a/.github/workflows/instrumented-tests.yml b/.github/workflows/instrumented-tests.yml new file mode 100644 index 00000000000..f24edc5e18a --- /dev/null +++ b/.github/workflows/instrumented-tests.yml @@ -0,0 +1,62 @@ +name: Instrumented Tests + +on: + issue_comment: + types: [created] + +permissions: + contents: read + pull-requests: read + +jobs: + instrumented-tests: + runs-on: ubuntu-latest + if: | + github.event.issue.pull_request && + contains(github.event.comment.body, 'run tests') + steps: + - uses: actions/checkout@v6 + with: + ref: refs/pull/${{ github.event.issue.number }}/head + + - name: Set up JDK 17 + uses: actions/setup-java@v5 + with: + distribution: temurin + java-version: 17 + + - name: Grant execute permission for gradlew + run: chmod +x gradlew + + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + with: + cache-encryption-key: ${{ secrets.GRADLE_ENCRYPTION_KEY }} + cache-read-only: false + + - name: Get target SDK + id: sdk + run: | + TARGET_SDK=$(grep 'targetSdk' gradle/libs.versions.toml | grep -o '[0-9]\+' | head -1) + echo "version=$TARGET_SDK" >> $GITHUB_OUTPUT + + - name: Enable KVM + run: | + echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules + sudo udevadm control --reload-rules + sudo udevadm trigger --name-match=kvm + + - name: Run Instrumented Tests + uses: reactivecircus/android-emulator-runner@v2 + with: + api-level: ${{ steps.sdk.outputs.version }} + arch: x86_64 + profile: Nexus 6 + script: ./gradlew connectedPrereleaseDebugAndroidTest + + - name: Upload Test Results + if: always() + uses: actions/upload-artifact@v7 + with: + name: instrumented-test-results + path: '**/build/reports/androidTests/' From 1d8d9b6b1bfcf86bd56919495ea08b6a8cf5bf2c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Tue, 23 Jun 2026 17:00:24 -0600 Subject: [PATCH 098/192] test --- .github/workflows/instrumented-tests.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/instrumented-tests.yml b/.github/workflows/instrumented-tests.yml index f24edc5e18a..1d37feaaaaf 100644 --- a/.github/workflows/instrumented-tests.yml +++ b/.github/workflows/instrumented-tests.yml @@ -9,11 +9,24 @@ permissions: pull-requests: read jobs: + debug: + runs-on: ubuntu-latest + steps: + - name: Dump event + run: | + echo "Event name: ${{ github.event_name }}" + echo "Is PR comment: ${{ github.event.issue.pull_request != null }}" + echo "Comment body: ${{ github.event.comment.body }}" + instrumented-tests: runs-on: ubuntu-latest if: | github.event.issue.pull_request && - contains(github.event.comment.body, 'run tests') + ( + contains(github.event.comment.body, 'run tests') || + contains(github.event.comment.body, 'Run tests') || + contains(github.event.comment.body, 'Run Tests') + ) steps: - uses: actions/checkout@v6 with: From 4f738a5099633104de23f2368e81051ec2558eac Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:11:03 -0600 Subject: [PATCH 099/192] Fix anilist --- .../cloudstream3/syncproviders/providers/AniListApi.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index aabbd38c164..380447bdd81 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -871,6 +871,13 @@ class AniListApi : SyncAPI() { @JsonProperty("Media") @SerialName("Media") val media: SeasonMedia, ) + @Serializable + data class RecommendedMedia( + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("title") @SerialName("title") val title: MediaTitle?, + @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: MediaCoverImage?, + ) + @Serializable data class SeasonMedia( @JsonProperty("id") @SerialName("id") val id: Int?, @@ -906,7 +913,7 @@ class AniListApi : SyncAPI() { @Serializable data class Recommendation( @JsonProperty("id") @SerialName("id") val id: Long, - @JsonProperty("mediaRecommendation") @SerialName("mediaRecommendation") val mediaRecommendation: SeasonMedia?, + @JsonProperty("mediaRecommendation") @SerialName("mediaRecommendation") val mediaRecommendation: RecommendedMedia?, ) @Serializable From 9d4d3c4db5a70c9905ef8181decde43dd2a42a95 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:21:23 -0600 Subject: [PATCH 100/192] Fix trakt --- .../metaproviders/TraktProvider.kt | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt index 22a264898b0..6011e14ea1d 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -69,7 +69,13 @@ open class TraktProvider : MainAPI() { } private fun MediaDetails.toSearchResponse(): SearchResponse { - val media = this.media ?: this + val media = this.media ?: MediaSummary( + title = this.title, + year = this.year, + ids = this.ids, + rating = this.rating, + images = this.images, + ) val mediaType = if (media.ids?.tvdb == null) TvType.Movie else TvType.TvSeries val poster = media.images?.poster?.firstOrNull() return if (mediaType == TvType.Movie) { @@ -77,7 +83,7 @@ open class TraktProvider : MainAPI() { name = media.title ?: "", url = Data( type = mediaType, - mediaDetails = media, + mediaDetails = this, ).toJson(), type = TvType.Movie, ) { @@ -89,7 +95,7 @@ open class TraktProvider : MainAPI() { name = media.title ?: "", url = Data( type = mediaType, - mediaDetails = media, + mediaDetails = this, ).toJson(), type = TvType.TvSeries, ) { @@ -226,7 +232,7 @@ open class TraktProvider : MainAPI() { this.episode = episode.number this.description = episode.overview this.runTime = episode.runtime - this.posterUrl = fixPath( episode.images?.screenshot?.firstOrNull()) + this.posterUrl = fixPath(episode.images?.screenshot?.firstOrNull()) this.score = Score.from10(episode.rating) this.addDate(episode.firstAired, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") @@ -304,6 +310,15 @@ open class TraktProvider : MainAPI() { @JsonProperty("mediaDetails") @SerialName("mediaDetails") val mediaDetails: MediaDetails? = null, ) + @Serializable + data class MediaSummary( + @JsonProperty("title") @SerialName("title") val title: String? = null, + @JsonProperty("year") @SerialName("year") val year: Int? = null, + @JsonProperty("ids") @SerialName("ids") val ids: Ids? = null, + @JsonProperty("rating") @SerialName("rating") val rating: Double? = null, + @JsonProperty("images") @SerialName("images") val images: Images? = null, + ) + @OptIn(ExperimentalSerializationApi::class) // JsonNames is an experimental annotation for now @Serializable data class MediaDetails( @@ -332,7 +347,7 @@ open class TraktProvider : MainAPI() { @JsonProperty("airs") @SerialName("airs") val airs: Airs? = null, @JsonProperty("network") @SerialName("network") val network: String? = null, @JsonProperty("images") @SerialName("images") val images: Images? = null, - @JsonProperty("media") @JsonAlias("movie", "show") @SerialName("media") @JsonNames("movie", "show") val media: MediaDetails? = null, + @JsonProperty("media") @JsonAlias("movie", "show") @SerialName("media") @JsonNames("movie", "show") val media: MediaSummary? = null, ) @Serializable From 7e08cda19f0419230a810ebee8a5f8f30a3aad07 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 09:28:27 -0600 Subject: [PATCH 101/192] Fix anilist --- .../syncproviders/providers/AniListApi.kt | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt index 380447bdd81..37795c30b74 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/AniListApi.kt @@ -55,7 +55,7 @@ class AniListApi : SyncAPI() { val token = AuthToken( accessToken = sanitizer["access_token"] ?: throw ErrorLoadingException("No access token"), - //refreshToken = sanitizer["refresh_token"], + // refreshToken = sanitizer["refresh_token"], accessTokenLifetime = APIHolder.unixTime + sanitizer["expires_in"]!!.toLong(), ) return token @@ -878,6 +878,13 @@ class AniListApi : SyncAPI() { @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: MediaCoverImage?, ) + @Serializable + data class CharacterMedia( + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("title") @SerialName("title") val title: MediaTitle?, + @JsonProperty("coverImage") @SerialName("coverImage") val coverImage: MediaCoverImage?, + ) + @Serializable data class SeasonMedia( @JsonProperty("id") @SerialName("id") val id: Int?, @@ -953,7 +960,7 @@ class AniListApi : SyncAPI() { @JsonProperty("name") @SerialName("name") val name: String?, @JsonProperty("voiceActors") @SerialName("voiceActors") val voiceActors: List?, @JsonProperty("favouriteOrder") @SerialName("favouriteOrder") val favouriteOrder: Int?, - @JsonProperty("media") @SerialName("media") val media: List?, + @JsonProperty("media") @SerialName("media") val media: List?, @JsonProperty("node") @SerialName("node") val node: Character?, ) From 80d29e35377442d7237c0c61cffccae4eb984700 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:02:51 -0600 Subject: [PATCH 102/192] Update --- .../syncproviders/providers/MALApi.kt | 55 ++++++++----------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index 814a644dcfc..d0ceac39c75 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -56,9 +56,10 @@ class MALApi : SyncAPI() { SyncWatchType.NONE ) - data class PayLoad( - val requestId: Int, - val codeVerifier: String + @Serializable + data class Payload( + @SerialName("requestId") val requestId: Int, + @SerialName("codeVerifier") val codeVerifier: String, ) override suspend fun login(redirectUrl: String, payload: String?): AuthToken? { @@ -178,13 +179,13 @@ class MALApi : SyncAPI() { @Serializable data class Recommendations( @SerialName("node") val node: Node? = null, - @SerialName("num_recommendations") val numRecommendations: Int? = null + @SerialName("num_recommendations") val numRecommendations: Int? = null, ) @Serializable data class Studios( @SerialName("id") val id: Int? = null, - @SerialName("name") val name: String? = null + @SerialName("name") val name: String? = null, ) @Serializable @@ -193,14 +194,14 @@ class MALApi : SyncAPI() { @SerialName("score") val score: Int? = null, @SerialName("num_episodes_watched") val numEpisodesWatched: Int? = null, @SerialName("is_rewatching") val isRewatching: Boolean? = null, - @SerialName("updated_at") val updatedAt: String? = null + @SerialName("updated_at") val updatedAt: String? = null, ) @Serializable data class RelatedAnime( @SerialName("node") val node: Node? = null, @SerialName("relation_type") val relationType: String? = null, - @SerialName("relation_type_formatted") val relationTypeFormatted: String? = null + @SerialName("relation_type_formatted") val relationTypeFormatted: String? = null, ) @Serializable @@ -209,13 +210,13 @@ class MALApi : SyncAPI() { @SerialName("completed") val completed: String? = null, @SerialName("on_hold") val onHold: String? = null, @SerialName("dropped") val dropped: String? = null, - @SerialName("plan_to_watch") val planToWatch: String? = null + @SerialName("plan_to_watch") val planToWatch: String? = null, ) @Serializable data class Statistics( @SerialName("status") val status: Status? = null, - @SerialName("num_list_users") val numListUsers: Int? = null + @SerialName("num_list_users") val numListUsers: Int? = null, ) private fun parseDate(string: String?): Long? { @@ -258,7 +259,7 @@ class MALApi : SyncAPI() { airStatus = when (malAnime.status) { "finished_airing" -> ShowStatus.Completed "currently_airing" -> ShowStatus.Ongoing - //"not_yet_aired" + // "not_yet_aired" else -> null }, nextAiring = null, @@ -355,12 +356,10 @@ class MALApi : SyncAPI() { val codeVerifier = generateCodeVerifier() val requestId = ++requestIdCounter val codeChallenge = codeVerifier - val request = - "$mainUrl/v1/oauth2/authorize?response_type=code&client_id=$key&code_challenge=$codeChallenge&state=RequestID$requestId" - + val request = "$mainUrl/v1/oauth2/authorize?response_type=code&client_id=$key&code_challenge=$codeChallenge&state=RequestID$requestId" return AuthLoginPage( url = request, - payload = PayLoad(requestId, codeVerifier).toJson() + payload = Payload(requestId, codeVerifier).toJson() ) } @@ -373,7 +372,6 @@ class MALApi : SyncAPI() { "refresh_token" to token.refreshToken!! ) ).parsed() - return AuthToken( accessToken = res.accessToken, refreshToken = res.refreshToken, @@ -382,20 +380,18 @@ class MALApi : SyncAPI() { } private var requestIdCounter = 0 - - private val allTitles = hashMapOf() @Serializable data class MalList( @SerialName("data") val data: List, - @SerialName("paging") val paging: Paging + @SerialName("paging") val paging: Paging, ) @Serializable data class MainPicture( @SerialName("medium") val medium: String, - @SerialName("large") val large: String + @SerialName("large") val large: String, ) @Serializable @@ -422,7 +418,7 @@ class MALApi : SyncAPI() { @SerialName("broadcast") val broadcast: Broadcast?, @SerialName("nsfw") val nsfw: String?, @SerialName("created_at") val createdAt: String?, - @SerialName("updated_at") val updatedAt: String? + @SerialName("updated_at") val updatedAt: String?, ) @Serializable @@ -470,32 +466,32 @@ class MALApi : SyncAPI() { @Serializable data class Paging( - @SerialName("next") val next: String? + @SerialName("next") val next: String?, ) @Serializable data class AlternativeTitles( @SerialName("synonyms") val synonyms: List, @SerialName("en") val en: String, - @SerialName("ja") val ja: String + @SerialName("ja") val ja: String, ) @Serializable data class Genres( @SerialName("id") val id: Int, - @SerialName("name") val name: String + @SerialName("name") val name: String, ) @Serializable data class StartSeason( @SerialName("year") val year: Int, - @SerialName("season") val season: String + @SerialName("season") val season: String, ) @Serializable data class Broadcast( @SerialName("day_of_the_week") val dayOfTheWeek: String?, - @SerialName("start_time") val startTime: String? + @SerialName("start_time") val startTime: String?, ) override suspend fun library(auth: AuthData?): LibraryMetadata? { @@ -616,7 +612,6 @@ class MALApi : SyncAPI() { ).text() } - @Serializable data class ResponseToken( @SerialName("token_type") val tokenType: String, @@ -640,12 +635,6 @@ class MALApi : SyncAPI() { data class MalNode( @SerialName("id") val id: Int, @SerialName("title") val title: String, - /* - also, but not used - main_picture -> - public string medium; - public string large; - */ ) @Serializable @@ -690,7 +679,7 @@ class MALApi : SyncAPI() { @Serializable data class MalSearch( @SerialName("data") val data: List, - //paging + // paging ) data class MalTitleHolder( From 6c2c8638e6ca4d530cba9973add634a9212ebf3d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:03:54 -0600 Subject: [PATCH 103/192] Update --- .../lagradost/cloudstream3/syncproviders/providers/MALApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index d0ceac39c75..7bc5416d7a2 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -53,7 +53,7 @@ class MALApi : SyncAPI() { SyncWatchType.PLANTOWATCH, SyncWatchType.DROPPED, SyncWatchType.ONHOLD, - SyncWatchType.NONE + SyncWatchType.NONE, ) @Serializable From a440d1c47ac8fb4b74104f83409a071aadb6a28b Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:06:09 -0600 Subject: [PATCH 104/192] Fix --- .../lagradost/cloudstream3/syncproviders/providers/MALApi.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index 7bc5416d7a2..1c7d24d59e7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -63,7 +63,7 @@ class MALApi : SyncAPI() { ) override suspend fun login(redirectUrl: String, payload: String?): AuthToken? { - val payloadData = parseJson(payload!!) + val payloadData = parseJson(payload!!) val sanitizer = splitRedirectUrl(redirectUrl) val state = sanitizer["state"]!! From 939c97a578a00146d0487970ede51224ae56cad4 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:09:51 -0600 Subject: [PATCH 105/192] Keep JsonProperty --- .../syncproviders/providers/MALApi.kt | 250 +++++++++--------- 1 file changed, 125 insertions(+), 125 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index 1c7d24d59e7..165b844ffb7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -58,8 +58,8 @@ class MALApi : SyncAPI() { @Serializable data class Payload( - @SerialName("requestId") val requestId: Int, - @SerialName("codeVerifier") val codeVerifier: String, + @JsonProperty("requestId") @SerialName("requestId") val requestId: Int, + @JsonProperty("codeVerifier") @SerialName("codeVerifier") val codeVerifier: String, ) override suspend fun login(redirectUrl: String, payload: String?): AuthToken? { @@ -142,81 +142,81 @@ class MALApi : SyncAPI() { @Serializable data class MalAnime( - @SerialName("id") val id: Int?, - @SerialName("title") val title: String?, - @SerialName("main_picture") val mainPicture: MainPicture?, - @SerialName("alternative_titles") val alternativeTitles: AlternativeTitles?, - @SerialName("start_date") val startDate: String?, - @SerialName("end_date") val endDate: String?, - @SerialName("synopsis") val synopsis: String?, - @SerialName("mean") val mean: Double?, - @SerialName("rank") val rank: Int?, - @SerialName("popularity") val popularity: Int?, - @SerialName("num_list_users") val numListUsers: Int?, - @SerialName("num_scoring_users") val numScoringUsers: Int?, - @SerialName("nsfw") val nsfw: String?, - @SerialName("created_at") val createdAt: String?, - @SerialName("updated_at") val updatedAt: String?, - @SerialName("media_type") val mediaType: String?, - @SerialName("status") val status: String?, - @SerialName("genres") val genres: ArrayList?, - @SerialName("my_list_status") val myListStatus: MyListStatus?, - @SerialName("num_episodes") val numEpisodes: Int?, - @SerialName("start_season") val startSeason: StartSeason?, - @SerialName("broadcast") val broadcast: Broadcast?, - @SerialName("source") val source: String?, - @SerialName("average_episode_duration") val averageEpisodeDuration: Int?, - @SerialName("rating") val rating: String?, - @SerialName("pictures") val pictures: ArrayList?, - @SerialName("background") val background: String?, - @SerialName("related_anime") val relatedAnime: ArrayList?, - @SerialName("related_manga") val relatedManga: ArrayList?, - @SerialName("recommendations") val recommendations: ArrayList?, - @SerialName("studios") val studios: ArrayList?, - @SerialName("statistics") val statistics: Statistics?, + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("main_picture") @SerialName("main_picture") val mainPicture: MainPicture?, + @JsonProperty("alternative_titles") @SerialName("alternative_titles") val alternativeTitles: AlternativeTitles?, + @JsonProperty("start_date") @SerialName("start_date") val startDate: String?, + @JsonProperty("end_date") @SerialName("end_date") val endDate: String?, + @JsonProperty("synopsis") @SerialName("synopsis") val synopsis: String?, + @JsonProperty("mean") @SerialName("mean") val mean: Double?, + @JsonProperty("rank") @SerialName("rank") val rank: Int?, + @JsonProperty("popularity") @SerialName("popularity") val popularity: Int?, + @JsonProperty("num_list_users") @SerialName("num_list_users") val numListUsers: Int?, + @JsonProperty("num_scoring_users") @SerialName("num_scoring_users") val numScoringUsers: Int?, + @JsonProperty("nsfw") @SerialName("nsfw") val nsfw: String?, + @JsonProperty("created_at") @SerialName("created_at") val createdAt: String?, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String?, + @JsonProperty("media_type") @SerialName("media_type") val mediaType: String?, + @JsonProperty("status") @SerialName("status") val status: String?, + @JsonProperty("genres") @SerialName("genres") val genres: ArrayList?, + @JsonProperty("my_list_status") @SerialName("my_list_status") val myListStatus: MyListStatus?, + @JsonProperty("num_episodes") @SerialName("num_episodes") val numEpisodes: Int?, + @JsonProperty("start_season") @SerialName("start_season") val startSeason: StartSeason?, + @JsonProperty("broadcast") @SerialName("broadcast") val broadcast: Broadcast?, + @JsonProperty("source") @SerialName("source") val source: String?, + @JsonProperty("average_episode_duration") @SerialName("average_episode_duration") val averageEpisodeDuration: Int?, + @JsonProperty("rating") @SerialName("rating") val rating: String?, + @JsonProperty("pictures") @SerialName("pictures") val pictures: ArrayList?, + @JsonProperty("background") @SerialName("background") val background: String?, + @JsonProperty("related_anime") @SerialName("related_anime") val relatedAnime: ArrayList?, + @JsonProperty("related_manga") @SerialName("related_manga") val relatedManga: ArrayList?, + @JsonProperty("recommendations") @SerialName("recommendations") val recommendations: ArrayList?, + @JsonProperty("studios") @SerialName("studios") val studios: ArrayList?, + @JsonProperty("statistics") @SerialName("statistics") val statistics: Statistics?, ) @Serializable data class Recommendations( - @SerialName("node") val node: Node? = null, - @SerialName("num_recommendations") val numRecommendations: Int? = null, + @JsonProperty("node") @SerialName("node") val node: Node? = null, + @JsonProperty("num_recommendations") @SerialName("num_recommendations") val numRecommendations: Int? = null, ) @Serializable data class Studios( - @SerialName("id") val id: Int? = null, - @SerialName("name") val name: String? = null, + @JsonProperty("id") @SerialName("id") val id: Int? = null, + @JsonProperty("name") @SerialName("name") val name: String? = null, ) @Serializable data class MyListStatus( - @SerialName("status") val status: String? = null, - @SerialName("score") val score: Int? = null, - @SerialName("num_episodes_watched") val numEpisodesWatched: Int? = null, - @SerialName("is_rewatching") val isRewatching: Boolean? = null, - @SerialName("updated_at") val updatedAt: String? = null, + @JsonProperty("status") @SerialName("status") val status: String? = null, + @JsonProperty("score") @SerialName("score") val score: Int? = null, + @JsonProperty("num_episodes_watched") @SerialName("num_episodes_watched") val numEpisodesWatched: Int? = null, + @JsonProperty("is_rewatching") @SerialName("is_rewatching") val isRewatching: Boolean? = null, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String? = null, ) @Serializable data class RelatedAnime( - @SerialName("node") val node: Node? = null, - @SerialName("relation_type") val relationType: String? = null, - @SerialName("relation_type_formatted") val relationTypeFormatted: String? = null, + @JsonProperty("node") @SerialName("node") val node: Node? = null, + @JsonProperty("relation_type") @SerialName("relation_type") val relationType: String? = null, + @JsonProperty("relation_type_formatted") @SerialName("relation_type_formatted") val relationTypeFormatted: String? = null, ) @Serializable data class Status( - @SerialName("watching") val watching: String? = null, - @SerialName("completed") val completed: String? = null, - @SerialName("on_hold") val onHold: String? = null, - @SerialName("dropped") val dropped: String? = null, - @SerialName("plan_to_watch") val planToWatch: String? = null, + @JsonProperty("watching") @SerialName("watching") val watching: String? = null, + @JsonProperty("completed") @SerialName("completed") val completed: String? = null, + @JsonProperty("on_hold") @SerialName("on_hold") val onHold: String? = null, + @JsonProperty("dropped") @SerialName("dropped") val dropped: String? = null, + @JsonProperty("plan_to_watch") @SerialName("plan_to_watch") val planToWatch: String? = null, ) @Serializable data class Statistics( - @SerialName("status") val status: Status? = null, - @SerialName("num_list_users") val numListUsers: Int? = null, + @JsonProperty("status") @SerialName("status") val status: Status? = null, + @JsonProperty("num_list_users") @SerialName("num_list_users") val numListUsers: Int? = null, ) private fun parseDate(string: String?): Long? { @@ -384,56 +384,56 @@ class MALApi : SyncAPI() { @Serializable data class MalList( - @SerialName("data") val data: List, - @SerialName("paging") val paging: Paging, + @JsonProperty("data") @SerialName("data") val data: List, + @JsonProperty("paging") @SerialName("paging") val paging: Paging, ) @Serializable data class MainPicture( - @SerialName("medium") val medium: String, - @SerialName("large") val large: String, + @JsonProperty("medium") @SerialName("medium") val medium: String, + @JsonProperty("large") @SerialName("large") val large: String, ) @Serializable data class Node( - @SerialName("id") val id: Int, - @SerialName("title") val title: String, - @SerialName("main_picture") val mainPicture: MainPicture?, - @SerialName("alternative_titles") val alternativeTitles: AlternativeTitles?, - @SerialName("media_type") val mediaType: String?, - @SerialName("num_episodes") val numEpisodes: Int?, - @SerialName("status") val status: String?, - @SerialName("start_date") val startDate: String?, - @SerialName("end_date") val endDate: String?, - @SerialName("average_episode_duration") val averageEpisodeDuration: Int?, - @SerialName("synopsis") val synopsis: String?, - @SerialName("mean") val mean: Double?, - @SerialName("genres") val genres: List?, - @SerialName("rank") val rank: Int?, - @SerialName("popularity") val popularity: Int?, - @SerialName("num_list_users") val numListUsers: Int?, - @SerialName("num_favorites") val numFavorites: Int?, - @SerialName("num_scoring_users") val numScoringUsers: Int?, - @SerialName("start_season") val startSeason: StartSeason?, - @SerialName("broadcast") val broadcast: Broadcast?, - @SerialName("nsfw") val nsfw: String?, - @SerialName("created_at") val createdAt: String?, - @SerialName("updated_at") val updatedAt: String?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("title") @SerialName("title") val title: String, + @JsonProperty("main_picture") @SerialName("main_picture") val mainPicture: MainPicture?, + @JsonProperty("alternative_titles") @SerialName("alternative_titles") val alternativeTitles: AlternativeTitles?, + @JsonProperty("media_type") @SerialName("media_type") val mediaType: String?, + @JsonProperty("num_episodes") @SerialName("num_episodes") val numEpisodes: Int?, + @JsonProperty("status") @SerialName("status") val status: String?, + @JsonProperty("start_date") @SerialName("start_date") val startDate: String?, + @JsonProperty("end_date") @SerialName("end_date") val endDate: String?, + @JsonProperty("average_episode_duration") @SerialName("average_episode_duration") val averageEpisodeDuration: Int?, + @JsonProperty("synopsis") @SerialName("synopsis") val synopsis: String?, + @JsonProperty("mean") @SerialName("mean") val mean: Double?, + @JsonProperty("genres") @SerialName("genres") val genres: List?, + @JsonProperty("rank") @SerialName("rank") val rank: Int?, + @JsonProperty("popularity") @SerialName("popularity") val popularity: Int?, + @JsonProperty("num_list_users") @SerialName("num_list_users") val numListUsers: Int?, + @JsonProperty("num_favorites") @SerialName("num_favorites") val numFavorites: Int?, + @JsonProperty("num_scoring_users") @SerialName("num_scoring_users") val numScoringUsers: Int?, + @JsonProperty("start_season") @SerialName("start_season") val startSeason: StartSeason?, + @JsonProperty("broadcast") @SerialName("broadcast") val broadcast: Broadcast?, + @JsonProperty("nsfw") @SerialName("nsfw") val nsfw: String?, + @JsonProperty("created_at") @SerialName("created_at") val createdAt: String?, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String?, ) @Serializable data class ListStatus( - @SerialName("status") val status: String?, - @SerialName("score") val score: Int, - @SerialName("num_episodes_watched") val numEpisodesWatched: Int, - @SerialName("is_rewatching") val isRewatching: Boolean, - @SerialName("updated_at") val updatedAt: String, + @JsonProperty("status") @SerialName("status") val status: String?, + @JsonProperty("score") @SerialName("score") val score: Int, + @JsonProperty("num_episodes_watched") @SerialName("num_episodes_watched") val numEpisodesWatched: Int, + @JsonProperty("is_rewatching") @SerialName("is_rewatching") val isRewatching: Boolean, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String, ) @Serializable data class Data( - @SerialName("node") val node: Node, - @SerialName("list_status") val listStatus: ListStatus?, + @JsonProperty("node") @SerialName("node") val node: Node, + @JsonProperty("list_status") @SerialName("list_status") val listStatus: ListStatus?, ) { fun toLibraryItem(): SyncAPI.LibraryItem { return SyncAPI.LibraryItem( @@ -466,32 +466,32 @@ class MALApi : SyncAPI() { @Serializable data class Paging( - @SerialName("next") val next: String?, + @JsonProperty("next") @SerialName("next") val next: String?, ) @Serializable data class AlternativeTitles( - @SerialName("synonyms") val synonyms: List, - @SerialName("en") val en: String, - @SerialName("ja") val ja: String, + @JsonProperty("synonyms") @SerialName("synonyms") val synonyms: List, + @JsonProperty("en") @SerialName("en") val en: String, + @JsonProperty("ja") @SerialName("ja") val ja: String, ) @Serializable data class Genres( - @SerialName("id") val id: Int, - @SerialName("name") val name: String, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("name") @SerialName("name") val name: String, ) @Serializable data class StartSeason( - @SerialName("year") val year: Int, - @SerialName("season") val season: String, + @JsonProperty("year") @SerialName("year") val year: Int, + @JsonProperty("season") @SerialName("season") val season: String, ) @Serializable data class Broadcast( - @SerialName("day_of_the_week") val dayOfTheWeek: String?, - @SerialName("start_time") val startTime: String?, + @JsonProperty("day_of_the_week") @SerialName("day_of_the_week") val dayOfTheWeek: String?, + @JsonProperty("start_time") @SerialName("start_time") val startTime: String?, ) override suspend fun library(auth: AuthData?): LibraryMetadata? { @@ -614,71 +614,71 @@ class MALApi : SyncAPI() { @Serializable data class ResponseToken( - @SerialName("token_type") val tokenType: String, - @SerialName("expires_in") val expiresIn: Int, - @SerialName("access_token") val accessToken: String, - @SerialName("refresh_token") val refreshToken: String, + @JsonProperty("token_type") @SerialName("token_type") val tokenType: String, + @JsonProperty("expires_in") @SerialName("expires_in") val expiresIn: Int, + @JsonProperty("access_token") @SerialName("access_token") val accessToken: String, + @JsonProperty("refresh_token") @SerialName("refresh_token") val refreshToken: String, ) @Serializable data class MalRoot( - @SerialName("data") val data: List, + @JsonProperty("data") @SerialName("data") val data: List, ) @Serializable data class MalDatum( - @SerialName("node") val node: MalNode, - @SerialName("list_status") val listStatus: MalStatus, + @JsonProperty("node") @SerialName("node") val node: MalNode, + @JsonProperty("list_status") @SerialName("list_status") val listStatus: MalStatus, ) @Serializable data class MalNode( - @SerialName("id") val id: Int, - @SerialName("title") val title: String, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("title") @SerialName("title") val title: String, ) @Serializable data class MalStatus( - @SerialName("status") val status: String, - @SerialName("score") val score: Int, - @SerialName("num_episodes_watched") val numEpisodesWatched: Int, - @SerialName("is_rewatching") val isRewatching: Boolean, - @SerialName("updated_at") val updatedAt: String, + @JsonProperty("status") @SerialName("status") val status: String, + @JsonProperty("score") @SerialName("score") val score: Int, + @JsonProperty("num_episodes_watched") @SerialName("num_episodes_watched") val numEpisodesWatched: Int, + @JsonProperty("is_rewatching") @SerialName("is_rewatching") val isRewatching: Boolean, + @JsonProperty("updated_at") @SerialName("updated_at") val updatedAt: String, ) @Serializable data class MalUser( - @SerialName("id") val id: Int, - @SerialName("name") val name: String, - @SerialName("location") val location: String, - @SerialName("joined_at") val joinedAt: String, - @SerialName("picture") val picture: String?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("location") @SerialName("location") val location: String, + @JsonProperty("joined_at") @SerialName("joined_at") val joinedAt: String, + @JsonProperty("picture") @SerialName("picture") val picture: String?, ) @Serializable data class MalMainPicture( - @SerialName("large") val large: String?, - @SerialName("medium") val medium: String?, + @JsonProperty("large") @SerialName("large") val large: String?, + @JsonProperty("medium") @SerialName("medium") val medium: String?, ) // Used for getDataAboutId() @Serializable data class SmallMalAnime( - @SerialName("id") val id: Int, - @SerialName("title") val title: String?, - @SerialName("num_episodes") val numEpisodes: Int, - @SerialName("my_list_status") val myListStatus: MalStatus?, - @SerialName("main_picture") val mainPicture: MalMainPicture?, + @JsonProperty("id") @SerialName("id") val id: Int, + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("num_episodes") @SerialName("num_episodes") val numEpisodes: Int, + @JsonProperty("my_list_status") @SerialName("my_list_status") val myListStatus: MalStatus?, + @JsonProperty("main_picture") @SerialName("main_picture") val mainPicture: MalMainPicture?, ) @Serializable data class MalSearchNode( - @SerialName("node") val node: Node, + @JsonProperty("node") @SerialName("node") val node: Node, ) @Serializable data class MalSearch( - @SerialName("data") val data: List, + @JsonProperty("data") @SerialName("data") val data: List, // paging ) From e65b4ee616f111abec347b707d2452f5fd834919 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 19:17:04 -0600 Subject: [PATCH 106/192] replace toKotlinObject --- .../cloudstream3/syncproviders/providers/MALApi.kt | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt index 165b844ffb7..27231c5bbb1 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/MALApi.kt @@ -21,7 +21,6 @@ import com.lagradost.cloudstream3.ui.SyncWatchType import com.lagradost.cloudstream3.ui.library.ListSorting import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson -import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.txt import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @@ -537,7 +536,7 @@ class MALApi : SyncAPI() { val fullList = mutableListOf() val offsetRegex = Regex("""offset=(\d+)""") while (true) { - val data: MalList = getMalAnimeListSlice(token, offset) ?: break + val data: MalList = getMalAnimeListSlice(token, offset) fullList.addAll(data.data) offset = data.paging.next?.let { offsetRegex.find(it)?.groupValues?.get(1)?.toInt() } @@ -546,7 +545,7 @@ class MALApi : SyncAPI() { return fullList.toTypedArray() } - private suspend fun getMalAnimeListSlice(token: AuthToken, offset: Int = 0): MalList? { + private suspend fun getMalAnimeListSlice(token: AuthToken, offset: Int = 0): MalList { val user = "@me" // Very lackluster docs // https://myanimelist.net/apiconfig/references/api/v2#operation/users_user_id_animelist_get @@ -557,7 +556,7 @@ class MALApi : SyncAPI() { "Authorization" to "Bearer ${token.accessToken}", ), cacheTime = 0 ).text() - return res.toKotlinObject() + return parseJson(res) } private suspend fun setScoreRequest( From 087ec757dff795b5791caecc23cfe97f69972c7e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:09:44 -0600 Subject: [PATCH 107/192] Update Simkl --- .../syncproviders/providers/SimklApi.kt | 296 ++++++++---------- 1 file changed, 125 insertions(+), 171 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt index a0791044a5f..d5d8604869e 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/syncproviders/providers/SimklApi.kt @@ -36,6 +36,7 @@ import com.lagradost.cloudstream3.utils.txt import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import kotlinx.serialization.Transient +import kotlinx.serialization.json.JsonElement import java.math.BigInteger import java.security.SecureRandom import java.text.SimpleDateFormat @@ -51,7 +52,7 @@ class SimklApi : SyncAPI() { override var name = "Simkl" override val idPrefix = "simkl" - val key = "simkl-key" + private val key = "simkl-key" override val redirectUrlIdentifier = "simkl" override val hasOAuth2 = true override val hasPin = true @@ -61,9 +62,6 @@ class SimklApi : SyncAPI() { override val createAccountUrl = "$mainUrl/signup" override val syncIdName = SyncIdName.Simkl - /** Automatically adds simkl auth headers */ - // private val interceptor = HeaderInterceptor() - /** * This is required to override the reported last activity as simkl activites * may not always update based on testing. @@ -72,7 +70,6 @@ class SimklApi : SyncAPI() { private object SimklCache { private const val SIMKL_CACHE_KEY = "SIMKL_API_CACHE" - enum class CacheTimes(val value: String) { OneMonth("30d"), ThirtyMinutes("30m") @@ -80,9 +77,9 @@ class SimklApi : SyncAPI() { @Serializable private class SimklCacheWrapper( - @SerialName("obj") val obj: T?, - @SerialName("validUntil") val validUntil: Long, - @SerialName("cacheTime") val cacheTime: Long = APIHolder.unixTime, + @JsonProperty("obj") @SerialName("obj") val obj: T?, + @JsonProperty("validUntil") @SerialName("validUntil") val validUntil: Long, + @JsonProperty("cacheTime") @SerialName("cacheTime") val cacheTime: Long = APIHolder.unixTime, ) { /** Returns true if cache is newer than cacheDays */ fun isFresh(): Boolean { @@ -93,18 +90,14 @@ class SimklApi : SyncAPI() { val unixTime = APIHolder.unixTime return if (validUntil > unixTime) { (validUntil - unixTime).toDuration(DurationUnit.SECONDS) - } else { - Duration.ZERO - } + } else Duration.ZERO } } fun cleanOldCache() { getKeys(SIMKL_CACHE_KEY)?.forEach { - val isOld = CloudStreamApp.getKey>(it)?.isFresh() == false - if (isOld) { - removeKey(it) - } + val isOld = CloudStreamApp.getKey>(it)?.isFresh() == false + if (isOld) removeKey(it) } } @@ -114,7 +107,7 @@ class SimklApi : SyncAPI() { SIMKL_CACHE_KEY, path, // Storing as plain sting is required to make generics work. - SimklCacheWrapper(value, APIHolder.unixTime + cacheTime.inWholeSeconds).toJson() + SimklCacheWrapper(value, APIHolder.unixTime + cacheTime.inWholeSeconds).toJson(), ) } @@ -129,7 +122,7 @@ class SimklApi : SyncAPI() { return if (cache?.isFresh() == true) { debugPrint { "Cache hit at: $SIMKL_CACHE_KEY/$path. " + - "Remains fresh for ${cache.remainingTime().inWholeDays} days or ${cache.remainingTime().inWholeSeconds} seconds." + "Remains fresh for ${cache.remainingTime().inWholeDays} days or ${cache.remainingTime().inWholeSeconds} seconds." } cache.obj } else { @@ -189,7 +182,7 @@ class SimklApi : SyncAPI() { enum class SimklListStatusType( var value: Int, @StringRes val stringRes: Int, - val originalName: String? + val originalName: String?, ) { Watching(0, R.string.type_watching, "watching"), Completed(1, R.string.type_completed, "completed"), @@ -208,90 +201,82 @@ class SimklApi : SyncAPI() { } } - // ------------------- @Serializable data class TokenRequest( - @SerialName("code") val code: String, - @SerialName("client_id") val clientId: String = CLIENT_ID, - @SerialName("client_secret") val clientSecret: String = CLIENT_SECRET, - @SerialName("redirect_uri") val redirectUri: String = "$APP_STRING://simkl", - @SerialName("grant_type") val grantType: String = "authorization_code" + @JsonProperty("code") @SerialName("code") val code: String, + @JsonProperty("client_id") @SerialName("client_id") val clientId: String = CLIENT_ID, + @JsonProperty("client_secret") @SerialName("client_secret") val clientSecret: String = CLIENT_SECRET, + @JsonProperty("redirect_uri") @SerialName("redirect_uri") val redirectUri: String = "$APP_STRING://simkl", + @JsonProperty("grant_type") @SerialName("grant_type") val grantType: String = "authorization_code", ) @Serializable data class TokenResponse( /** No expiration date */ - @SerialName("access_token") val accessToken: String, - @SerialName("token_type") val tokenType: String, - @SerialName("scope") val scope: String + @JsonProperty("access_token") @SerialName("access_token") val accessToken: String, + @JsonProperty("token_type") @SerialName("token_type") val tokenType: String, + @JsonProperty("scope") @SerialName("scope") val scope: String, ) - // ------------------- /** https://simkl.docs.apiary.io/#reference/users/settings/receive-settings */ @Serializable data class SettingsResponse( - @SerialName("user") - val user: User, - @SerialName("account") - val account: Account, + @JsonProperty("user") @SerialName("user") val user: User, + @JsonProperty("account") @SerialName("account") val account: Account, ) { @Serializable data class User( - @SerialName("name") - val name: String, - /** Url */ - @SerialName("avatar") - val avatar: String + @JsonProperty("name") @SerialName("name") val name: String, + @JsonProperty("avatar") @SerialName("avatar") val avatar: String, // Url ) @Serializable data class Account( - @SerialName("id") - val id: Int, + @JsonProperty("id") @SerialName("id") val id: Int, ) } @Serializable data class PinAuthResponse( - @SerialName("result") val result: String, - @SerialName("device_code") val deviceCode: String, - @SerialName("user_code") val userCode: String, - @SerialName("verification_url") val verificationUrl: String, - @SerialName("expires_in") val expiresIn: Int, - @SerialName("interval") val interval: Int, + @JsonProperty("result") @SerialName("result") val result: String, + @JsonProperty("device_code") @SerialName("device_code") val deviceCode: String, + @JsonProperty("user_code") @SerialName("user_code") val userCode: String, + @JsonProperty("verification_url") @SerialName("verification_url") val verificationUrl: String, + @JsonProperty("expires_in") @SerialName("expires_in") val expiresIn: Int, + @JsonProperty("interval") @SerialName("interval") val interval: Int, ) @Serializable data class PinExchangeResponse( - @SerialName("result") val result: String, - @SerialName("message") val message: String? = null, - @SerialName("access_token") val accessToken: String? = null, + @JsonProperty("result") @SerialName("result") val result: String, + @JsonProperty("message") @SerialName("message") val message: String? = null, + @JsonProperty("access_token") @SerialName("access_token") val accessToken: String? = null, ) // ------------------- @Serializable data class ActivitiesResponse( - @SerialName("all") val all: String?, - @SerialName("tv_shows") val tvShows: UpdatedAt, - @SerialName("anime") val anime: UpdatedAt, - @SerialName("movies") val movies: UpdatedAt, + @JsonProperty("all") @SerialName("all") val all: String?, + @JsonProperty("tv_shows") @SerialName("tv_shows") val tvShows: UpdatedAt, + @JsonProperty("anime") @SerialName("anime") val anime: UpdatedAt, + @JsonProperty("movies") @SerialName("movies") val movies: UpdatedAt, ) { @Serializable data class UpdatedAt( - @SerialName("all") val all: String?, - @SerialName("removed_from_list") val removedFromList: String?, - @SerialName("rated_at") val ratedAt: String?, + @JsonProperty("all") @SerialName("all") val all: String?, + @JsonProperty("removed_from_list") @SerialName("removed_from_list") val removedFromList: String?, + @JsonProperty("rated_at") @SerialName("rated_at") val ratedAt: String?, ) } /** https://simkl.docs.apiary.io/#reference/tv/episodes/get-tv-show-episodes */ @Serializable data class EpisodeMetadata( - @SerialName("title") val title: String?, - @SerialName("description") val description: String?, - @SerialName("season") val season: Int?, - @SerialName("episode") val episode: Int, - @SerialName("img") val img: String? + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("description") @SerialName("description") val description: String?, + @JsonProperty("season") @SerialName("season") val season: Int?, + @JsonProperty("episode") @SerialName("episode") val episode: Int, + @JsonProperty("img") @SerialName("img") val img: String?, ) { companion object { fun convertToEpisodes(list: List?): List? { @@ -316,15 +301,15 @@ class SimklApi : SyncAPI() { */ @Serializable open class MediaObject( - @SerialName("title") open val title: String?, - @SerialName("year") open val year: Int?, - @SerialName("ids") open val ids: Ids?, - @SerialName("total_episodes") val totalEpisodes: Int? = null, - @SerialName("status") val status: String? = null, - @SerialName("poster") val poster: String? = null, - @SerialName("type") val type: String? = null, - @SerialName("seasons") open val seasons: List? = null, - @SerialName("episodes") open val episodes: List? = null + @JsonProperty("title") @SerialName("title") open val title: String?, + @JsonProperty("year") @SerialName("year") open val year: Int?, + @JsonProperty("ids") @SerialName("ids") open val ids: Ids?, + @JsonProperty("total_episodes") @SerialName("total_episodes") val totalEpisodes: Int? = null, + @JsonProperty("status") @SerialName("status") val status: String? = null, + @JsonProperty("poster") @SerialName("poster") val poster: String? = null, + @JsonProperty("type") @SerialName("type") val type: String? = null, + @JsonProperty("seasons") @SerialName("seasons") open val seasons: List? = null, + @JsonProperty("episodes") @SerialName("episodes") open val episodes: List? = null, ) { fun hasEnded(): Boolean { return status == "released" || status == "ended" @@ -332,20 +317,20 @@ class SimklApi : SyncAPI() { @Serializable data class Season( - @SerialName("number") val number: Int, - @SerialName("episodes") val episodes: List + @JsonProperty("number") @SerialName("number") val number: Int, + @JsonProperty("episodes") @SerialName("episodes") val episodes: List, ) { @Serializable - data class Episode(@SerialName("number") val number: Int) + data class Episode(@JsonProperty("number") @SerialName("number") val number: Int) } @Serializable data class Ids( - @SerialName("simkl") val simkl: Int?, - @SerialName("imdb") val imdb: String? = null, - @SerialName("tmdb") val tmdb: String? = null, - @SerialName("mal") val mal: String? = null, - @SerialName("anilist") val anilist: String? = null, + @JsonProperty("simkl") @SerialName("simkl") val simkl: Int?, + @JsonProperty("imdb") @SerialName("imdb") val imdb: String? = null, + @JsonProperty("tmdb") @SerialName("tmdb") val tmdb: String? = null, + @JsonProperty("mal") @SerialName("mal") val mal: String? = null, + @JsonProperty("anilist") @SerialName("anilist") val anilist: String? = null, ) { companion object { fun fromMap(map: Map): Ids { @@ -354,7 +339,7 @@ class SimklApi : SyncAPI() { imdb = map[SimklSyncServices.Imdb], tmdb = map[SimklSyncServices.Tmdb], mal = map[SimklSyncServices.Mal], - anilist = map[SimklSyncServices.AniList] + anilist = map[SimklSyncServices.AniList], ) } } @@ -368,7 +353,7 @@ class SimklApi : SyncAPI() { currentIds?.simkl?.toString() ?: return null, getUrlFromId(currentIds.simkl), this.poster?.let { getPosterUrl(it) }, - if (this.type == "movie") TvType.Movie else TvType.TvSeries + if (this.type == "movie") TvType.Movie else TvType.TvSeries, ) } } @@ -383,7 +368,7 @@ class SimklApi : SyncAPI() { private var addEpisodes: Pair?, List?>? = null, private var removeEpisodes: Pair?, List?>? = null, // Required for knowing if the status should be overwritten - private var onList: Boolean = false + private var onList: Boolean = false, ) { fun token(token: AuthToken) = apply { this.headers = getHeaders(token) } fun apiUrl(url: String) = apply { this.url = url } @@ -410,7 +395,6 @@ class SimklApi : SyncAPI() { oldEpisodes: Int?, ) = apply { if (allEpisodes == null || newEpisodes == null) return@apply - fun getEpisodes(rawEpisodes: List) = if (rawEpisodes.any { it.season != null }) { EpisodeMetadata.convertToSeasons(rawEpisodes) to null @@ -529,7 +513,6 @@ class SimklApi : SyncAPI() { hasEnded: Boolean? ): Array? { if (simklId == null) return null - val cacheKey = "Episodes/$simklId" val cache = SimklCache.getKey>(cacheKey) @@ -548,6 +531,7 @@ class SimklApi : SyncAPI() { }.toTypedArray() } } + val url = when (type) { "anime" -> "https://api.simkl.com/anime/episodes/$simklId" "tv" -> "https://api.simkl.com/tv/episodes/$simklId" @@ -573,8 +557,8 @@ class SimklApi : SyncAPI() { @Transient override val ids: Ids? = null, @Transient override val seasons: List? = null, @Transient override val episodes: List? = null, - @SerialName("rating") val rating: Int? = null, - @SerialName("rated_at") val ratedAt: String? = null, + @JsonProperty("rating") @SerialName("rating") val rating: Int? = null, + @JsonProperty("rated_at") @SerialName("rated_at") val ratedAt: String? = null, ) : MediaObject(title, year, ids, seasons = seasons, episodes = episodes) @Serializable @@ -582,8 +566,8 @@ class SimklApi : SyncAPI() { @Transient override val title: String? = null, @Transient override val year: Int? = null, @Transient override val ids: Ids? = null, - @SerialName("rating") val rating: Int, - @SerialName("rated_at") val ratedAt: String? = getDateTime(APIHolder.unixTime) + @JsonProperty("rating") @SerialName("rating") val rating: Int, + @JsonProperty("rated_at") @SerialName("rated_at") val ratedAt: String? = getDateTime(APIHolder.unixTime), ) : MediaObject(title, year, ids) @Serializable @@ -591,29 +575,25 @@ class SimklApi : SyncAPI() { @Transient override val title: String? = null, @Transient override val year: Int? = null, @Transient override val ids: Ids? = null, - @SerialName("to") val to: String, - @SerialName("watched_at") val watchedAt: String? = getDateTime(APIHolder.unixTime) + @JsonProperty("to") @SerialName("to") val to: String, + @JsonProperty("watched_at") @SerialName("watched_at") val watchedAt: String? = getDateTime(APIHolder.unixTime), ) : MediaObject(title, year, ids) @Serializable data class StatusRequest( - @SerialName("movies") val movies: List, - @SerialName("shows") val shows: List + @JsonProperty("movies") @SerialName("movies") val movies: List, + @JsonProperty("shows") @SerialName("shows") val shows: List, ) /** https://simkl.docs.apiary.io/#reference/sync/get-all-items/get-all-items-in-the-user's-watchlist */ @Serializable data class AllItemsResponse( - @SerialName("shows") - val shows: List = emptyList(), - @SerialName("anime") - val anime: List = emptyList(), - @SerialName("movies") - val movies: List = emptyList(), + @JsonProperty("shows") @SerialName("shows") val shows: List = emptyList(), + @JsonProperty("anime") @SerialName("anime") val anime: List = emptyList(), + @JsonProperty("movies") @SerialName("movies") val movies: List = emptyList(), ) { companion object { fun merge(first: AllItemsResponse?, second: AllItemsResponse?): AllItemsResponse { - // Replace the first item with the same id, or add the new item fun MutableList.replaceOrAddItem(newItem: T, predicate: (T) -> Boolean) { for (i in this.indices) { @@ -625,7 +605,6 @@ class SimklApi : SyncAPI() { this.add(newItem) } - // fun merge( first: List?, second: List? @@ -661,13 +640,13 @@ class SimklApi : SyncAPI() { @Serializable data class MovieMetadata( - @SerialName("last_watched_at") override val lastWatchedAt: String?, - @SerialName("status") override val status: String, - @SerialName("user_rating") override val userRating: Int?, - @SerialName("last_watched") override val lastWatched: String?, - @SerialName("watched_episodes_count") override val watchedEpisodesCount: Int?, - @SerialName("total_episodes_count") override val totalEpisodesCount: Int?, - val movie: ShowMetadata.Show + @JsonProperty("last_watched_at") @SerialName("last_watched_at") override val lastWatchedAt: String?, + @JsonProperty("status") @SerialName("status") override val status: String, + @JsonProperty("user_rating") @SerialName("user_rating") override val userRating: Int?, + @JsonProperty("last_watched") @SerialName("last_watched") override val lastWatched: String?, + @JsonProperty("watched_episodes_count") @SerialName("watched_episodes_count") override val watchedEpisodesCount: Int?, + @JsonProperty("total_episodes_count") @SerialName("total_episodes_count") override val totalEpisodesCount: Int?, + @JsonProperty("movie") @SerialName("movie") val movie: ShowMetadata.Show, ) : Metadata { override fun getIds(): ShowMetadata.Show.Ids { return this.movie.ids @@ -688,20 +667,20 @@ class SimklApi : SyncAPI() { null, null, this.movie.year?.toYear(), - movie.ids.simkl + movie.ids.simkl, ) } } @Serializable data class ShowMetadata( - @SerialName("last_watched_at") override val lastWatchedAt: String?, - @SerialName("status") override val status: String, - @SerialName("user_rating") override val userRating: Int?, - @SerialName("last_watched") override val lastWatched: String?, - @SerialName("watched_episodes_count") override val watchedEpisodesCount: Int?, - @SerialName("total_episodes_count") override val totalEpisodesCount: Int?, - @SerialName("show") val show: Show + @JsonProperty("last_watched_at") @SerialName("last_watched_at") override val lastWatchedAt: String?, + @JsonProperty("status") @SerialName("status") override val status: String, + @JsonProperty("user_rating") @SerialName("user_rating") override val userRating: Int?, + @JsonProperty("last_watched") @SerialName("last_watched") override val lastWatched: String?, + @JsonProperty("watched_episodes_count") @SerialName("watched_episodes_count") override val watchedEpisodesCount: Int?, + @JsonProperty("total_episodes_count") @SerialName("total_episodes_count") override val totalEpisodesCount: Int?, + @JsonProperty("show") @SerialName("show") val show: Show, ) : Metadata { override fun getIds(): Show.Ids { return this.show.ids @@ -722,30 +701,30 @@ class SimklApi : SyncAPI() { null, null, this.show.year?.toYear(), - show.ids.simkl + show.ids.simkl, ) } @Serializable data class Show( - @SerialName("title") val title: String, - @SerialName("poster") val poster: String?, - @SerialName("year") val year: Int?, - @SerialName("ids") val ids: Ids, + @JsonProperty("title") @SerialName("title") val title: String, + @JsonProperty("poster") @SerialName("poster") val poster: String?, + @JsonProperty("year") @SerialName("year") val year: Int?, + @JsonProperty("ids") @SerialName("ids") val ids: Ids, ) { @Serializable data class Ids( - @SerialName("simkl") val simkl: Int, - @SerialName("slug") val slug: String?, - @SerialName("imdb") val imdb: String?, - @SerialName("zap2it") val zap2it: String?, - @SerialName("tmdb") val tmdb: String?, - @SerialName("offen") val offen: String?, - @SerialName("tvdb") val tvdb: String?, - @SerialName("mal") val mal: String?, - @SerialName("anidb") val anidb: String?, - @SerialName("anilist") val anilist: String?, - @SerialName("traktslug") val traktslug: String? + @JsonProperty("simkl") @SerialName("simkl") val simkl: Int, + @JsonProperty("slug") @SerialName("slug") val slug: String?, + @JsonProperty("imdb") @SerialName("imdb") val imdb: String?, + @JsonProperty("zap2it") @SerialName("zap2it") val zap2it: String?, + @JsonProperty("tmdb") @SerialName("tmdb") val tmdb: String?, + @JsonProperty("offen") @SerialName("offen") val offen: String?, + @JsonProperty("tvdb") @SerialName("tvdb") val tvdb: String?, + @JsonProperty("mal") @SerialName("mal") val mal: String?, + @JsonProperty("anidb") @SerialName("anidb") val anidb: String?, + @JsonProperty("anilist") @SerialName("anilist") val anilist: String?, + @JsonProperty("traktslug") @SerialName("traktslug") val traktslug: String?, ) { fun matchesId(database: SimklSyncServices, id: String): Boolean { return when (database) { @@ -762,27 +741,10 @@ class SimklApi : SyncAPI() { } } - /** - * Appends api keys to the requests - **/ - /*private inner class HeaderInterceptor : Interceptor { - override fun intercept(chain: Interceptor.Chain): Response { - debugPrint { "${this@SimklApi.name} made request to ${chain.request().url}" } - return chain.proceed( - chain.request() - .newBuilder() - .addHeader("Authorization", "Bearer $token") - .addHeader("simkl-api-key", CLIENT_ID) - .build() - ) - } - }*/ - private suspend fun getUser(token: AuthToken): SettingsResponse = app.post("$mainUrl/users/settings", headers = getHeaders(token)) .parsed() - /** * Useful to get episodes on demand to prevent unnecessary requests. */ @@ -790,7 +752,7 @@ class SimklApi : SyncAPI() { private val simklId: Int?, private val type: String?, private val totalEpisodeCount: Int?, - private val hasEnded: Boolean? + private val hasEnded: Boolean?, ) { suspend fun getEpisodes(): Array? { return getEpisodes(simklId, type, totalEpisodeCount, hasEnded) @@ -805,10 +767,12 @@ class SimklApi : SyncAPI() { val episodeConstructor: SimklEpisodeConstructor, override var isFavorite: Boolean? = null, override var maxEpisodes: Int? = null, - /** Save seen episodes separately to know the change from old to new. - * Required to remove seen episodes if count decreases */ + /** + * Save seen episodes separately to know the change from old to new. + * Required to remove seen episodes if count decreases. + */ val oldEpisodes: Int, - val oldStatus: String? + val oldStatus: String?, ) : SyncAPI.AbstractSyncStatus() override suspend fun status(auth: AuthData?, id: String): SyncAPI.AbstractSyncStatus? { @@ -860,7 +824,7 @@ class SimklApi : SyncAPI() { episodeConstructor = episodeConstructor, oldEpisodes = foundItem.watchedEpisodesCount ?: 0, oldScore = foundItem.userRating, - oldStatus = foundItem.status + oldStatus = foundItem.status, ) } else { return SimklSyncStatus( @@ -871,7 +835,7 @@ class SimklApi : SyncAPI() { episodeConstructor = episodeConstructor, oldEpisodes = 0, oldStatus = null, - oldScore = null + oldScore = null, ) } } @@ -879,7 +843,7 @@ class SimklApi : SyncAPI() { override suspend fun updateStatus( auth: AuthData?, id: String, - newStatus: AbstractSyncStatus + newStatus: AbstractSyncStatus, ): Boolean { val parsedId = readIdFromString(id) lastScoreTime = APIHolder.unixTime @@ -911,7 +875,6 @@ class SimklApi : SyncAPI() { } builder.episodes(episodes?.toList(), watchedEpisodes, simklStatus?.oldEpisodes) - requireLibraryRefresh = true return builder.execute() } @@ -920,7 +883,6 @@ class SimklApi : SyncAPI() { /** See https://simkl.docs.apiary.io/#reference/search/id-lookup/get-items-by-id */ private suspend fun searchByIds(serviceMap: Map): Array? { if (serviceMap.isEmpty()) return emptyArray() - return app.get( "$mainUrl/search/id", params = mapOf("client_id" to CLIENT_ID) + serviceMap.map { (service, id) -> @@ -937,12 +899,10 @@ class SimklApi : SyncAPI() { override fun loginRequest(): AuthLoginPage? { val lastLoginState = BigInteger(130, SecureRandom()).toString(32) - val url = - "https://simkl.com/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$APP_STRING://${redirectUrlIdentifier}&state=$lastLoginState" - + val url = "https://simkl.com/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$APP_STRING://${redirectUrlIdentifier}&state=$lastLoginState" return AuthLoginPage( url = url, - payload = lastLoginState + payload = lastLoginState, ) } @@ -957,7 +917,7 @@ class SimklApi : SyncAPI() { return app.get( "$mainUrl/sync/all-items/", params = params, - headers = getHeaders(auth.token) + headers = getHeaders(auth.token), ).parsedSafe() } @@ -976,10 +936,8 @@ class SimklApi : SyncAPI() { val lastRemoval = listOf( activities?.tvShows?.removedFromList, activities?.anime?.removedFromList, - activities?.movies?.removedFromList - ).maxOf { - getUnixTime(it) ?: -1 - } + activities?.movies?.removedFromList, + ).maxOf { getUnixTime(it) ?: -1 } val lastRealUpdate = listOf( activities?.tvShows?.all, @@ -1014,7 +972,6 @@ class SimklApi : SyncAPI() { override suspend fun library(auth: AuthData?): SyncAPI.LibraryMetadata? { val list = getSyncListSmart(auth ?: return null) ?: return null - val baseMap = SimklListStatusType.entries .filter { it.value >= 0 && it.value != SimklListStatusType.ReWatching.value } @@ -1024,9 +981,7 @@ class SimklApi : SyncAPI() { val syncMap = listOf(list.anime, list.movies, list.shows) .flatten() - .groupBy { - it.status - } + .groupBy { it.status } .mapNotNull { (status, list) -> val stringRes = status?.let { SimklListStatusType.fromString(it)?.stringRes } @@ -1064,7 +1019,7 @@ class SimklApi : SyncAPI() { userCode = pinAuthResp.userCode, verificationUrl = pinAuthResp.verificationUrl, expiresIn = pinAuthResp.expiresIn, - interval = pinAuthResp.interval + interval = pinAuthResp.interval, ) } @@ -1072,7 +1027,6 @@ class SimklApi : SyncAPI() { val pinAuthResp = app.get( "$mainUrl/oauth/pin/${payload.userCode}?client_id=$CLIENT_ID" ).parsedSafe() ?: return null - return AuthToken( accessToken = pinAuthResp.accessToken ?: return null, ) @@ -1099,7 +1053,7 @@ class SimklApi : SyncAPI() { return AuthUser( id = user.account.id, name = user.user.name, - profilePicture = user.user.avatar + profilePicture = user.user.avatar, ) } } From 1cb27c295a610f8650dadf973af45fc5bba7450c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:04:33 -0600 Subject: [PATCH 108/192] Update BackupUtils --- .../cloudstream3/utils/BackupUtils.kt | 69 ++++++++++--------- 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt index e2e1d96a385..0a561b4712a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/BackupUtils.kt @@ -9,8 +9,7 @@ import androidx.annotation.WorkerThread import androidx.core.net.toUri import androidx.fragment.app.FragmentActivity import androidx.preference.PreferenceManager -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.CloudStreamApp.Companion.getActivity import com.lagradost.cloudstream3.CommonActivity.showToast import com.lagradost.cloudstream3.R @@ -37,6 +36,8 @@ import com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESU import com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.KEY_RESUME_PACKAGES import com.lagradost.safefile.MediaFileContentType import com.lagradost.safefile.SafeFile +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import okhttp3.internal.closeQuietly import java.io.IOException import java.io.OutputStream @@ -50,7 +51,7 @@ object BackupUtils { /** * No sensitive or breaking data in the backup - * */ + */ private val nonTransferableKeys = listOf( ANILIST_CACHED_LIST, MAL_CACHED_LIST, @@ -95,8 +96,8 @@ object BackupUtils { // Download headers are unintuitively used in the resume watching system. // We can therefore not prune download headers in backups. - //DOWNLOAD_HEADER_CACHE_BACKUP, - //DOWNLOAD_HEADER_CACHE, + // DOWNLOAD_HEADER_CACHE_BACKUP, + // DOWNLOAD_HEADER_CACHE, // This may overwrite valid local data with invalid data @@ -121,18 +122,18 @@ object BackupUtils { // Kinda hack, but I couldn't think of a better way @Serializable data class BackupVars( - @SerialName("_Bool") val bool: Map?, - @SerialName("_Int") val int: Map?, - @SerialName("_String") val string: Map?, - @SerialName("_Float") val float: Map?, - @SerialName("_Long") val long: Map?, - @SerialName("_StringSet") val stringSet: Map?>?, + @JsonProperty("_Bool") @SerialName("_Bool") val bool: Map?, + @JsonProperty("_Int") @SerialName("_Int") val int: Map?, + @JsonProperty("_String") @SerialName("_String") val string: Map?, + @JsonProperty("_Float") @SerialName("_Float") val float: Map?, + @JsonProperty("_Long") @SerialName("_Long") val long: Map?, + @JsonProperty("_StringSet") @SerialName("_StringSet") val stringSet: Map?>?, ) @Serializable data class BackupFile( - @SerialName("datastore") val datastore: BackupVars, - @SerialName("settings") val settings: BackupVars + @JsonProperty("datastore") @SerialName("datastore") val datastore: BackupVars, + @JsonProperty("settings") @SerialName("settings") val settings: BackupVars, ) @Suppress("UNCHECKED_CAST") @@ -146,7 +147,7 @@ object BackupUtils { allData.filter { it.value is String } as? Map, allData.filter { it.value is Float } as? Map, allData.filter { it.value is Long } as? Map, - allData.filter { it.value as? Set != null } as? Map> + allData.filter { it.value as? Set != null } as? Map>, ) val allSettingsSorted = BackupVars( @@ -155,12 +156,12 @@ object BackupUtils { allSettings.filter { it.value is String } as? Map, allSettings.filter { it.value is Float } as? Map, allSettings.filter { it.value is Long } as? Map, - allSettings.filter { it.value as? Set != null } as? Map> + allSettings.filter { it.value as? Set != null } as? Map>, ) return BackupFile( allDataSorted, - allSettingsSorted + allSettingsSorted, ) } @@ -169,7 +170,7 @@ object BackupUtils { context: Context?, backupFile: BackupFile, restoreSettings: Boolean, - restoreDataStore: Boolean + restoreDataStore: Boolean, ) { if (context == null) return if (restoreSettings) { @@ -198,9 +199,9 @@ object BackupUtils { fun backup(context: Context?) = ioSafe { if (context == null) return@ioSafe - var fileStream: OutputStream? = null var printStream: PrintWriter? = null + try { if (!context.checkWrite()) { showToast(R.string.backup_failed, Toast.LENGTH_LONG) @@ -216,17 +217,13 @@ object BackupUtils { fileStream = stream.openNew() printStream = PrintWriter(fileStream) printStream.print(backupFile.toJson()) - - showToast( - R.string.backup_success, - Toast.LENGTH_LONG - ) + showToast(R.string.backup_success, Toast.LENGTH_LONG) } catch (e: Exception) { logError(e) try { showToast( txt(R.string.backup_failed_error_format, e.toString()), - Toast.LENGTH_LONG + Toast.LENGTH_LONG, ) } catch (e: Exception) { logError(e) @@ -245,7 +242,7 @@ object BackupUtils { name, folder = null, extension = ext, - tryResume = false + tryResume = false, ) } @@ -267,7 +264,7 @@ object BackupUtils { activity, restoredValue, restoreSettings = true, - restoreDataStore = true + restoreDataStore = true, ) activity.runOnUiThread { activity.recreate() } } catch (e: Exception) { @@ -308,7 +305,7 @@ object BackupUtils { private fun Context.restoreMap( map: Map?, - isEditingAppSettings: Boolean = false + isEditingAppSettings: Boolean = false, ) { val editor = DataStore.editor(this, isEditingAppSettings) map?.forEach { @@ -320,21 +317,27 @@ object BackupUtils { } /** - * Copy of [com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.basePathToFile], [com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getDefaultDir] and [com.lagradost.cloudstream3.utils.downloader.VideoDownloadManager.getBasePath] - * modded for backup specific paths - * */ - + * Copy of [com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getDefaultDir], + * modified for backup-specific paths. + */ fun getDefaultBackupDir(context: Context): SafeFile? { return SafeFile.fromMedia(context, MediaFileContentType.Downloads) } + /** + * Copy of [com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.getBasePath], + * modified for backup-specific paths. + */ fun getCurrentBackupDir(context: Context): Pair { val settingsManager = PreferenceManager.getDefaultSharedPreferences(context) - val basePathSetting = - settingsManager.getString(context.getString(R.string.backup_path_key), null) + val basePathSetting = settingsManager.getString(context.getString(R.string.backup_path_key), null) return baseBackupPathToFile(context, basePathSetting) to basePathSetting } + /** + * Copy of [com.lagradost.cloudstream3.utils.downloader.DownloadFileManagement.basePathToFile], + * modified for backup-specific paths. + */ private fun baseBackupPathToFile(context: Context, path: String?): SafeFile? { return when { path.isNullOrBlank() -> getDefaultBackupDir(context) From 8ab4513968c9d6d39a7e9847d14f65a461d496c4 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 11:27:58 -0600 Subject: [PATCH 109/192] Update Torrent --- .../cloudstream3/ui/player/Torrent.kt | 165 +++++++----------- 1 file changed, 60 insertions(+), 105 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt index 75de64418eb..7e5d04eb0c7 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.ui.player -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.api.Log import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.ErrorLoadingException @@ -10,6 +9,8 @@ import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLinkType import com.lagradost.cloudstream3.utils.newExtractorLink +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import torrServer.TorrServer import java.io.File import java.net.ConnectException @@ -33,14 +34,14 @@ object Torrent { /** Returns true if the server is up */ private suspend fun echo(): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { app.get( "$TORRENT_SERVER_URL/echo", - ).text().isNotEmpty() - } catch (e: ConnectException) { + ).text.isNotEmpty() + } catch (_: ConnectException) { // `Failed to connect to /127.0.0.1:8090` if the server is down false } catch (t: Throwable) { @@ -53,7 +54,7 @@ object Torrent { /** Gracefully shutdown the server. * should not be used because I am unable to start it again, and the stopTorrentServer() crashes the app */ suspend fun shutdown(): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { @@ -69,7 +70,7 @@ object Torrent { /** Lists all torrents by the server */ @Throws private suspend fun list(): Array { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { throw ErrorLoadingException("Not initialized") } return app.post( @@ -84,7 +85,7 @@ object Torrent { /** Drops a single torrent, (I think) this means closing the stream. Returns returns if it is successful */ private suspend fun drop(hash: String): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { @@ -105,7 +106,7 @@ object Torrent { /** Removes a single torrent from the server registry */ private suspend fun rem(hash: String): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { @@ -127,7 +128,7 @@ object Torrent { /** Removes all torrents from the server, and returns if it is successful */ suspend fun clearAll(): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return true } return try { @@ -165,10 +166,8 @@ object Torrent { /** Gets all the metadata of a torrent, will throw if that hash does not exists * https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/torrents.go#L126 */ @Throws - suspend fun get( - hash: String, - ): TorrentStatus { - if(TORRENT_SERVER_URL.isEmpty()) { + suspend fun get(hash: String): TorrentStatus { + if (TORRENT_SERVER_URL.isEmpty()) { throw ErrorLoadingException("Not initialized") } return app.post( @@ -185,7 +184,7 @@ object Torrent { /** Adds a torrent to the server, this is needed for us to get the hash for further modification, as well as start streaming it*/ @Throws private suspend fun add(url: String): TorrentStatus { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { throw ErrorLoadingException("Not initialized") } return app.post( @@ -205,7 +204,7 @@ object Torrent { return true } val port = TorrServer.startTorrentServer(dir, 0) - if(port < 0) { + if (port < 0) { return false } TORRENT_SERVER_URL = "http://127.0.0.1:$port" @@ -281,94 +280,53 @@ object Torrent { // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/main/web/api/route.go#L7 @Serializable data class TorrentRequest( - @SerialName("action") - val action: String, - @SerialName("hash") - val hash: String = "", - @SerialName("link") - val link: String = "", - @SerialName("title") - val title: String = "", - @SerialName("poster") - val poster: String = "", - @SerialName("data") - val data: String = "", - @SerialName("save_to_db") - val saveToDB: Boolean = false, + @JsonProperty("action") @SerialName("action") val action: String, + @JsonProperty("hash") @SerialName("hash") val hash: String = "", + @JsonProperty("link") @SerialName("link") val link: String = "", + @JsonProperty("title") @SerialName("title") val title: String = "", + @JsonProperty("poster") @SerialName("poster") val poster: String = "", + @JsonProperty("data") @SerialName("data") val data: String = "", + @JsonProperty("save_to_db") @SerialName("save_to_db") val saveToDB: Boolean = false, ) // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/torr/state/state.go#L33 // omitempty = nullable @Serializable data class TorrentStatus( - @SerialName("title") - var title: String, - @SerialName("poster") - var poster: String, - @SerialName("data") - var data: String?, - @SerialName("timestamp") - var timestamp: Long, - @SerialName("name") - var name: String?, - @SerialName("hash") - var hash: String?, - @SerialName("stat") - var stat: Int, - @SerialName("stat_string") - var statString: String, - @SerialName("loaded_size") - var loadedSize: Long?, - @SerialName("torrent_size") - var torrentSize: Long?, - @SerialName("preloaded_bytes") - var preloadedBytes: Long?, - @SerialName("preload_size") - var preloadSize: Long?, - @SerialName("download_speed") - var downloadSpeed: Double?, - @SerialName("upload_speed") - var uploadSpeed: Double?, - @SerialName("total_peers") - var totalPeers: Int?, - @SerialName("pending_peers") - var pendingPeers: Int?, - @SerialName("active_peers") - var activePeers: Int?, - @SerialName("connected_seeders") - var connectedSeeders: Int?, - @SerialName("half_open_peers") - var halfOpenPeers: Int?, - @SerialName("bytes_written") - var bytesWritten: Long?, - @SerialName("bytes_written_data") - var bytesWrittenData: Long?, - @SerialName("bytes_read") - var bytesRead: Long?, - @SerialName("bytes_read_data") - var bytesReadData: Long?, - @SerialName("bytes_read_useful_data") - var bytesReadUsefulData: Long?, - @SerialName("chunks_written") - var chunksWritten: Long?, - @SerialName("chunks_read") - var chunksRead: Long?, - @SerialName("chunks_read_useful") - var chunksReadUseful: Long?, - @SerialName("chunks_read_wasted") - var chunksReadWasted: Long?, - @SerialName("pieces_dirtied_good") - var piecesDirtiedGood: Long?, - @SerialName("pieces_dirtied_bad") - var piecesDirtiedBad: Long?, - @SerialName("duration_seconds") - var durationSeconds: Double?, - @SerialName("bit_rate") - var bitRate: String?, - @SerialName("file_stats") - var fileStats: List?, - @SerialName("trackers") - var trackers: List?, + @JsonProperty("title") @SerialName("title") var title: String, + @JsonProperty("poster") @SerialName("poster") var poster: String, + @JsonProperty("data") @SerialName("data") var data: String?, + @JsonProperty("timestamp") @SerialName("timestamp") var timestamp: Long, + @JsonProperty("name") @SerialName("name") var name: String?, + @JsonProperty("hash") @SerialName("hash") var hash: String?, + @JsonProperty("stat") @SerialName("stat") var stat: Int, + @JsonProperty("stat_string") @SerialName("stat_string") var statString: String, + @JsonProperty("loaded_size") @SerialName("loaded_size") var loadedSize: Long?, + @JsonProperty("torrent_size") @SerialName("torrent_size") var torrentSize: Long?, + @JsonProperty("preloaded_bytes") @SerialName("preloaded_bytes") var preloadedBytes: Long?, + @JsonProperty("preload_size") @SerialName("preload_size") var preloadSize: Long?, + @JsonProperty("download_speed") @SerialName("download_speed") var downloadSpeed: Double?, + @JsonProperty("upload_speed") @SerialName("upload_speed") var uploadSpeed: Double?, + @JsonProperty("total_peers") @SerialName("total_peers") var totalPeers: Int?, + @JsonProperty("pending_peers") @SerialName("pending_peers") var pendingPeers: Int?, + @JsonProperty("active_peers") @SerialName("active_peers") var activePeers: Int?, + @JsonProperty("connected_seeders") @SerialName("connected_seeders") var connectedSeeders: Int?, + @JsonProperty("half_open_peers") @SerialName("half_open_peers") var halfOpenPeers: Int?, + @JsonProperty("bytes_written") @SerialName("bytes_written") var bytesWritten: Long?, + @JsonProperty("bytes_written_data") @SerialName("bytes_written_data") var bytesWrittenData: Long?, + @JsonProperty("bytes_read") @SerialName("bytes_read") var bytesRead: Long?, + @JsonProperty("bytes_read_data") @SerialName("bytes_read_data") var bytesReadData: Long?, + @JsonProperty("bytes_read_useful_data") @SerialName("bytes_read_useful_data") var bytesReadUsefulData: Long?, + @JsonProperty("chunks_written") @SerialName("chunks_written") var chunksWritten: Long?, + @JsonProperty("chunks_read") @SerialName("chunks_read") var chunksRead: Long?, + @JsonProperty("chunks_read_useful") @SerialName("chunks_read_useful") var chunksReadUseful: Long?, + @JsonProperty("chunks_read_wasted") @SerialName("chunks_read_wasted") var chunksReadWasted: Long?, + @JsonProperty("pieces_dirtied_good") @SerialName("pieces_dirtied_good") var piecesDirtiedGood: Long?, + @JsonProperty("pieces_dirtied_bad") @SerialName("pieces_dirtied_bad") var piecesDirtiedBad: Long?, + @JsonProperty("duration_seconds") @SerialName("duration_seconds") var durationSeconds: Double?, + @JsonProperty("bit_rate") @SerialName("bit_rate") var bitRate: String?, + @JsonProperty("file_stats") @SerialName("file_stats") var fileStats: List?, + @JsonProperty("trackers") @SerialName("trackers") var trackers: List?, ) { fun streamUrl(url: String): String { val fileName = @@ -386,11 +344,8 @@ object Torrent { @Serializable data class TorrentFileStat( - @SerialName("id") - val id: Int?, - @SerialName("path") - val path: String?, - @SerialName("length") - val length: Long?, + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("path") @SerialName("path") val path: String?, + @JsonProperty("length") @SerialName("length") val length: Long?, ) -} \ No newline at end of file +} From cad8b33892555ad7621f7bc6b804542eedab35b4 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 12:42:20 -0600 Subject: [PATCH 110/192] Update SyncUtil --- .../lagradost/cloudstream3/utils/SyncUtil.kt | 137 +++++++++--------- 1 file changed, 67 insertions(+), 70 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt index 1f5a08d40a1..53dea508344 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/SyncUtil.kt @@ -3,13 +3,13 @@ package com.lagradost.cloudstream3.utils // TODO: FIX import android.util.Log -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.APIHolder.apis -//import com.lagradost.cloudstream3.animeproviders.AniflixProvider import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import java.util.concurrent.TimeUnit object SyncUtil { @@ -25,18 +25,16 @@ object SyncUtil { private const val NINE_ANIME = "9anime" private const val TWIST_MOE = "Twistmoe" - private val matchList = - mapOf( - "9anime" to NINE_ANIME, - "gogoanime" to GOGOANIME, - "gogoanimes" to GOGOANIME, - "twist.moe" to TWIST_MOE - ) + private val matchList = mapOf( + "9anime" to NINE_ANIME, + "gogoanime" to GOGOANIME, + "gogoanimes" to GOGOANIME, + "twist.moe" to TWIST_MOE, + ) suspend fun getIdsFromUrl(url: String?): Pair? { if (url == null) return null Log.i(TAG, "getIdsFromUrl $url") - for (regex in regexs) { regex.find(url)?.let { match -> if (match.groupValues.size == 3) { @@ -57,121 +55,120 @@ object SyncUtil { } } } + return null } - /** first. Mal, second. Anilist, - * valid sites are: Gogoanime, Twistmoe and 9anime*/ + /** + * first. Mal, second. Anilist, + * valid sites are: Gogoanime, Twistmoe and 9anime + */ private suspend fun getIdsFromSlug( slug: String, - site: String = "Gogoanime" + site: String = "Gogoanime", ): Pair? { Log.i(TAG, "getIdsFromSlug $slug $site") try { - //Gogoanime, Twistmoe and 9anime - val url = - "https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/pages/$site/$slug.json" + // Gogoanime, Twistmoe and 9anime + val url = "https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/pages/$site/$slug.json" val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).text() val mapped = tryParseJson(response) val overrideMal = mapped?.malId ?: mapped?.mal?.id ?: mapped?.anilist?.malId val overrideAnilist = mapped?.aniId ?: mapped?.anilist?.id - if (overrideMal != null) { return overrideMal.toString() to overrideAnilist?.toString() } + return null } catch (e: Exception) { logError(e) } + return null } suspend fun getUrlsFromId(id: String, type: String = "anilist"): List { - val url = - "https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/$type/anime/$id.json" + val url = "https://raw.githubusercontent.com/MALSync/MAL-Sync-Backup/master/data/$type/anime/$id.json" val response = app.get(url, cacheTime = 1, cacheUnit = TimeUnit.DAYS).parsed() val pages = response.pages ?: return emptyList() - val current = - pages.gogoanime.values.union(pages.nineanime.values).union(pages.twistmoe.values) - .mapNotNull { it.url }.toMutableList() + val current = pages.gogoanime.values.union(pages.nineanime.values).union(pages.twistmoe.values) + .mapNotNull { it.url }.toMutableList() if (type == "anilist") { // TODO MAKE BETTER apis.filter { it.name.contains("Aniflix", ignoreCase = true) }.forEach { current.add("${it.mainUrl}/anime/$id") } } + return current } @Serializable data class SyncPage( - @SerialName("Pages") val pages: SyncPages?, + @JsonProperty("Pages") @SerialName("Pages") val pages: SyncPages?, ) @Serializable data class SyncPages( - @SerialName("9anime") val nineanime: Map = emptyMap(), - @SerialName("Gogoanime") val gogoanime: Map = emptyMap(), - @SerialName("Twistmoe") val twistmoe: Map = emptyMap(), + @JsonProperty("9anime") @SerialName("9anime") val nineanime: Map = emptyMap(), + @JsonProperty("Gogoanime") @SerialName("Gogoanime") val gogoanime: Map = emptyMap(), + @JsonProperty("Twistmoe") @SerialName("Twistmoe") val twistmoe: Map = emptyMap(), ) @Serializable data class ProviderPage( - @SerialName("url") val url: String?, + @JsonProperty("url") @SerialName("url") val url: String?, ) @Serializable data class MalSyncPage( - @SerialName("identifier") val identifier: String?, - @SerialName("type") val type: String?, - @SerialName("page") val page: String?, - @SerialName("title") val title: String?, - @SerialName("url") val url: String?, - @SerialName("image") val image: String?, - @SerialName("hentai") val hentai: Boolean?, - @SerialName("sticky") val sticky: Boolean?, - @SerialName("active") val active: Boolean?, - @SerialName("actor") val actor: String?, - @SerialName("malId") val malId: Int?, - @SerialName("aniId") val aniId: Int?, - @SerialName("createdAt") val createdAt: String?, - @SerialName("updatedAt") val updatedAt: String?, - @SerialName("deletedAt") val deletedAt: String?, - @SerialName("Mal") val mal: Mal?, - @SerialName("Anilist") val anilist: Anilist?, - @SerialName("malUrl") val malUrl: String? + @JsonProperty("identifier") @SerialName("identifier") val identifier: String?, + @JsonProperty("type") @SerialName("type") val type: String?, + @JsonProperty("page") @SerialName("page") val page: String?, + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("url") @SerialName("url") val url: String?, + @JsonProperty("image") @SerialName("image") val image: String?, + @JsonProperty("hentai") @SerialName("hentai") val hentai: Boolean?, + @JsonProperty("sticky") @SerialName("sticky") val sticky: Boolean?, + @JsonProperty("active") @SerialName("active") val active: Boolean?, + @JsonProperty("actor") @SerialName("actor") val actor: String?, + @JsonProperty("malId") @SerialName("malId") val malId: Int?, + @JsonProperty("aniId") @SerialName("aniId") val aniId: Int?, + @JsonProperty("createdAt") @SerialName("createdAt") val createdAt: String?, + @JsonProperty("updatedAt") @SerialName("updatedAt") val updatedAt: String?, + @JsonProperty("deletedAt") @SerialName("deletedAt") val deletedAt: String?, + @JsonProperty("Mal") @SerialName("Mal") val mal: Mal?, + @JsonProperty("Anilist") @SerialName("Anilist") val anilist: Anilist?, + @JsonProperty("malUrl") @SerialName("malUrl") val malUrl: String?, ) @Serializable data class Anilist( -// @SerialName("altTitle") val altTitle: List?, -// @SerialName("externalLinks") val externalLinks: List?, - @SerialName("id") val id: Int?, - @SerialName("malId") val malId: Int?, - @SerialName("type") val type: String?, - @SerialName("title") val title: String?, - @SerialName("url") val url: String?, - @SerialName("image") val image: String?, - @SerialName("category") val category: String?, - @SerialName("hentai") val hentai: Boolean?, - @SerialName("createdAt") val createdAt: String?, - @SerialName("updatedAt") val updatedAt: String?, - @SerialName("deletedAt") val deletedAt: String? + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("malId") @SerialName("malId") val malId: Int?, + @JsonProperty("type") @SerialName("type") val type: String?, + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("url") @SerialName("url") val url: String?, + @JsonProperty("image") @SerialName("image") val image: String?, + @JsonProperty("category") @SerialName("category") val category: String?, + @JsonProperty("hentai") @SerialName("hentai") val hentai: Boolean?, + @JsonProperty("createdAt") @SerialName("createdAt") val createdAt: String?, + @JsonProperty("updatedAt") @SerialName("updatedAt") val updatedAt: String?, + @JsonProperty("deletedAt") @SerialName("deletedAt") val deletedAt: String?, ) @Serializable data class Mal( -// @SerialName("altTitle") val altTitle: List?, - @SerialName("id") val id: Int?, - @SerialName("type") val type: String?, - @SerialName("title") val title: String?, - @SerialName("url") val url: String?, - @SerialName("image") val image: String?, - @SerialName("category") val category: String?, - @SerialName("hentai") val hentai: Boolean?, - @SerialName("createdAt") val createdAt: String?, - @SerialName("updatedAt") val updatedAt: String?, - @SerialName("deletedAt") val deletedAt: String? + @JsonProperty("id") @SerialName("id") val id: Int?, + @JsonProperty("type") @SerialName("type") val type: String?, + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("url") @SerialName("url") val url: String?, + @JsonProperty("image") @SerialName("image") val image: String?, + @JsonProperty("category") @SerialName("category") val category: String?, + @JsonProperty("hentai") @SerialName("hentai") val hentai: Boolean?, + @JsonProperty("createdAt") @SerialName("createdAt") val createdAt: String?, + @JsonProperty("updatedAt") @SerialName("updatedAt") val updatedAt: String?, + @JsonProperty("deletedAt") @SerialName("deletedAt") val deletedAt: String?, ) } From 4e1586fa1aadb83bb8fca56e9d262301e95efc82 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:15:58 -0600 Subject: [PATCH 111/192] Update ControllerActivity --- .../cloudstream3/ui/ControllerActivity.kt | 147 ++++++------------ 1 file changed, 46 insertions(+), 101 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt index 2aadfb13c5a..a3f05fe68d0 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt @@ -12,6 +12,7 @@ import android.widget.ImageView import android.widget.LinearLayout import android.widget.ListView import androidx.appcompat.app.AlertDialog +import com.fasterxml.jackson.annotation.JsonProperty import com.google.android.gms.cast.MediaLoadOptions import com.google.android.gms.cast.MediaQueueItem import com.google.android.gms.cast.MediaSeekOptions @@ -34,35 +35,24 @@ import com.lagradost.cloudstream3.ui.player.SubtitleData import com.lagradost.cloudstream3.ui.result.ResultEpisode import com.lagradost.cloudstream3.ui.subtitles.ChromecastSubtitlesFragment import com.lagradost.cloudstream3.utils.AppContextUtils.sortSubs +import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.toJson import com.lagradost.cloudstream3.utils.CastHelper.awaitLinks import com.lagradost.cloudstream3.utils.CastHelper.getMediaInfo import com.lagradost.cloudstream3.utils.Coroutines.ioSafe -import com.lagradost.cloudstream3.utils.DataStore.toKotlinObject import com.lagradost.cloudstream3.utils.DataStoreHelper import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.UIHelper.dismissSafe +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import org.json.JSONObject -/*class SkipOpController(val view: ImageView) : UIController() { - init { - view.setImageResource(R.drawable.exo_controls_fastforward) - view.setOnClickListener { - remoteMediaClient?.let { - val options = MediaSeekOptions.Builder() - .setPosition(it.approximateStreamPosition + 85000) - it.seek(options.build()) - } - } - } -}*/ - private fun RemoteMediaClient.getItemIndex(): Int? { return try { val index = this.mediaQueue.itemIds.indexOf(this.currentItem?.itemId ?: 0) if (index < 0) null else index - } catch (e: Exception) { + } catch (_: Exception) { null } } @@ -89,48 +79,41 @@ class SkipNextEpisodeController(val view: ImageView) : UIController() { } } +@Serializable data class MetadataHolder( - val apiName: String, - val isMovie: Boolean, - val title: String?, - val poster: String?, - val currentEpisodeIndex: Int, - val episodes: List, - val currentLinks: List, - val currentSubtitles: List + @JsonProperty("apiName") @SerialName("apiName") val apiName: String, + @JsonProperty("isMovie") @SerialName("isMovie") val isMovie: Boolean, + @JsonProperty("title") @SerialName("title") val title: String?, + @JsonProperty("poster") @SerialName("poster") val poster: String?, + @JsonProperty("currentEpisodeIndex") @SerialName("currentEpisodeIndex") val currentEpisodeIndex: Int, + @JsonProperty("episodes") @SerialName("episodes") val episodes: List, + @JsonProperty("currentLinks") @SerialName("currentLinks") val currentLinks: List, + @JsonProperty("currentSubtitles") @SerialName("currentSubtitles") val currentSubtitles: List, ) -class SelectSourceController(val view: ImageView, val activity: ControllerActivity) : - UIController() { +class SelectSourceController(val view: ImageView, val activity: ControllerActivity) : UIController() { init { view.setImageResource(R.drawable.ic_baseline_playlist_play_24) view.setOnClickListener { - // lateinit var dialog: AlertDialog val holder = getCurrentMetaData() - if (holder != null) { val items = holder.currentLinks if (items.isNotEmpty() && remoteMediaClient?.currentItem != null) { - val subTracks = - remoteMediaClient?.mediaInfo?.mediaTracks?.filter { it.type == MediaTrack.TYPE_TEXT } - ?: ArrayList() + val subTracks = remoteMediaClient?.mediaInfo?.mediaTracks?.filter { it.type == MediaTrack.TYPE_TEXT } + ?: ArrayList() - val bottomSheetDialogBuilder = - AlertDialog.Builder(view.context, R.style.AlertDialogCustomBlack) + val bottomSheetDialogBuilder = AlertDialog.Builder(view.context, R.style.AlertDialogCustomBlack) bottomSheetDialogBuilder.setView(R.layout.sort_bottom_sheet) + val bottomSheetDialog = bottomSheetDialogBuilder.create() bottomSheetDialog.show() - // bottomSheetDialog.setContentView(R.layout.sort_bottom_sheet) - val providerList = - bottomSheetDialog.findViewById(R.id.sort_providers)!! - val subtitleList = - bottomSheetDialog.findViewById(R.id.sort_subtitles)!! + + val providerList = bottomSheetDialog.findViewById(R.id.sort_providers)!! + val subtitleList = bottomSheetDialog.findViewById(R.id.sort_subtitles)!! if (subTracks.isEmpty()) { - bottomSheetDialog.findViewById(R.id.sort_subtitles_holder)?.visibility = - GONE + bottomSheetDialog.findViewById(R.id.sort_subtitles_holder)?.visibility = GONE } else { - val arrayAdapter = - ArrayAdapter(view.context, R.layout.sort_bottom_single_choice) + val arrayAdapter = ArrayAdapter(view.context, R.layout.sort_bottom_single_choice) arrayAdapter.add(view.context.getString(R.string.no_subtitles)) arrayAdapter.addAll(subTracks.mapNotNull { it.name }) @@ -138,10 +121,8 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi subtitleList.adapter = arrayAdapter val currentTracks = remoteMediaClient?.mediaStatus?.activeTrackIds - - val subtitleIndex = - if (currentTracks == null) 0 else subTracks.map { it.id } - .indexOfFirst { currentTracks.contains(it) } + 1 + val subtitleIndex = if (currentTracks == null) 0 else subTracks.map { it.id } + .indexOfFirst { currentTracks.contains(it) } + 1 subtitleList.setSelection(subtitleIndex) subtitleList.setItemChecked(subtitleIndex, true) @@ -153,9 +134,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi ChromecastSubtitlesFragment.getCurrentSavedStyle().apply { val font = TextTrackStyle() font.setFontFamily(fontFamily ?: "Google Sans") - fontGenericFamily?.let { - font.fontGenericFamily = it - } + fontGenericFamily?.let { font.fontGenericFamily = it } font.windowColor = windowColor font.backgroundColor = backgroundColor @@ -172,7 +151,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi if (!it.status.isSuccess) { Log.e( "CHROMECAST", "Failed with status code:" + - it.status.statusCode + " > " + it.status.statusMessage + it.status.statusCode + " > " + it.status.statusMessage ) } } @@ -181,17 +160,15 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi } } - //https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation + // https://developers.google.com/cast/docs/reference/web_receiver/cast.framework.messages.MediaInformation val contentUrl = (remoteMediaClient?.currentItem?.media?.contentUrl ?: remoteMediaClient?.currentItem?.media?.contentId) - val sortingMethods = - items.map { "${it.name} ${Qualities.getStringByInt(it.quality)}" } - .toTypedArray() + val sortingMethods = items.map { "${it.name} ${Qualities.getStringByInt(it.quality)}" } + .toTypedArray() val sotringIndex = items.indexOfFirst { it.url == contentUrl } - val arrayAdapter = - ArrayAdapter(view.context, R.layout.sort_bottom_single_choice) + val arrayAdapter = ArrayAdapter(view.context, R.layout.sort_bottom_single_choice) arrayAdapter.addAll(sortingMethods.toMutableList()) providerList.choiceMode = AbsListView.CHOICE_MODE_SINGLE @@ -201,10 +178,8 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi providerList.setOnItemClickListener { _, _, which, _ -> val epData = holder.episodes[holder.currentEpisodeIndex] - fun loadMirror(index: Int) { if (holder.currentLinks.size <= index) return - val mediaItem = getMediaInfo( epData, holder, @@ -214,25 +189,21 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi ) val startAt = remoteMediaClient?.approximateStreamPosition ?: 0 - - //remoteMediaClient.load(mediaItem, true, startAt) try { // THIS IS VERY IMPORTANT BECAUSE WE NEVER WANT TO AUTOLOAD THE NEXT EPISODE val currentIdIndex = remoteMediaClient?.getItemIndex() - val nextId = remoteMediaClient?.mediaQueue?.itemIds?.get( currentIdIndex?.plus(1) ?: 0 ) + if (currentIdIndex == null && nextId != null) { awaitLinks( remoteMediaClient?.queueInsertAndPlayItem( MediaQueueItem.Builder(mediaItem).build(), nextId, startAt, - JSONObject() + JSONObject(), ) - ) { - loadMirror(index + 1) - } + ) { loadMirror(index + 1) } } else { val mediaLoadOptions = MediaLoadOptions.Builder() @@ -244,11 +215,9 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi mediaItem, mediaLoadOptions ) - ) { - loadMirror(index + 1) - } + ) { loadMirror(index + 1) } } - } catch (e: Exception) { + } catch (_: Exception) { val mediaLoadOptions = MediaLoadOptions.Builder() .setPlayPosition(startAt) @@ -259,8 +228,8 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi } } } - loadMirror(which) + loadMirror(which) bottomSheetDialog.dismissSafe(activity) } } @@ -271,22 +240,18 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi private fun getCurrentMetaData(): MetadataHolder? { return try { val data = remoteMediaClient?.mediaInfo?.customData?.toString() - data?.toKotlinObject() - } catch (e: Exception) { + parseJson(data) + } catch (_: Exception) { null } } var isLoadingMore = false - - override fun onMediaStatusUpdated() { super.onMediaStatusUpdated() val meta = getCurrentMetaData() + view.visibility = if ((meta?.currentLinks?.size ?: 0) > 1) VISIBLE else INVISIBLE - view.visibility = if ((meta?.currentLinks?.size - ?: 0) > 1 - ) VISIBLE else INVISIBLE try { if (meta != null && meta.episodes.size > meta.currentEpisodeIndex + 1) { val currentIdIndex = remoteMediaClient?.getItemIndex() ?: return @@ -303,7 +268,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi currentPosition, currentDuration, epData, - meta.episodes.getOrNull(index + 1) + meta.episodes.getOrNull(index + 1), ) } catch (t: Throwable) { logError(t) @@ -314,9 +279,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi ioSafe { val currentLinks = mutableSetOf() val currentSubs = mutableSetOf() - val generator = RepoLinkGenerator(listOf(epData)) - val isSuccessful = safeApiCall { generator.generateLinks( clearCache = false, @@ -329,7 +292,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi currentSubs.add(it) }, offset = 0, - isCasting = true + isCasting = true, ) } @@ -340,32 +303,18 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi val jsonCopy = meta.copy( currentLinks = sortedLinks, currentSubtitles = sortedSubs, - currentEpisodeIndex = index + currentEpisodeIndex = index, ) - val done = - JSONObject(jsonCopy.toJson()) - + val done = JSONObject(jsonCopy.toJson()) val mediaInfo = getMediaInfo( epData, jsonCopy, 0, done, - sortedSubs + sortedSubs, ) - /*fun loadIndex(index: Int) { - println("LOAD INDEX::::: $index") - if (meta.currentLinks.size <= index) return - val info = getMediaInfo( - epData, - meta, - index, - done) - awaitLinks(remoteMediaClient?.load(info, true, 0)) { - loadIndex(index + 1) - } - }*/ activity.runOnUiThread { awaitLinks( remoteMediaClient?.queueAppendItem( @@ -374,7 +323,6 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi ) ) { println("FAILED TO LOAD NEXT ITEM") - // loadIndex(1) } isLoadingMore = false } @@ -397,10 +345,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi class SkipTimeController(val view: ImageView, forwards: Boolean) : UIController() { init { - //val settingsManager = PreferenceManager.getDefaultSharedPreferences() - //val time = settingsManager?.getInt("chromecast_tap_time", 30) ?: 30 val time = 30 - //view.setImageResource(if (forwards) R.drawable.netflix_skip_forward else R.drawable.netflix_skip_back) view.setImageResource(if (forwards) R.drawable.go_forward_30 else R.drawable.go_back_30) view.setOnClickListener { remoteMediaClient?.let { From 784ca7740983358e355feb42ce907dcbfe579599 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 13:29:30 -0600 Subject: [PATCH 112/192] Fix --- .../java/com/lagradost/cloudstream3/ui/ControllerActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt index a3f05fe68d0..f00fd803150 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/ControllerActivity.kt @@ -239,7 +239,7 @@ class SelectSourceController(val view: ImageView, val activity: ControllerActivi private fun getCurrentMetaData(): MetadataHolder? { return try { - val data = remoteMediaClient?.mediaInfo?.customData?.toString() + val data = remoteMediaClient?.mediaInfo?.customData?.toString() ?: return null parseJson(data) } catch (_: Exception) { null From 076433afda0ed4cc920370ce3ad590d381d92e78 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:24:21 -0600 Subject: [PATCH 113/192] Remove use of toKotlinObject --- .../lagradost/cloudstream3/utils/DataStore.kt | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 02ee697911f..1203b9dcacb 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -193,20 +193,36 @@ object DataStore { setKey(getFolderName(folder, path), value) } + @Deprecated( + message = "Use parseJson(this) directly instead.", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + expression = "parseJson(this)", + imports = ["com.lagradost.cloudstream3.utils.AppUtils.parseJson"], + ), + ) inline fun String.toKotlinObject(): T { - return parseJson(this) + return parseJson(this) } + @Deprecated( + message = "Use parseJson(this) directly instead.", + level = DeprecationLevel.ERROR, + replaceWith = ReplaceWith( + expression = "parseJson(this)", + imports = ["com.lagradost.cloudstream3.utils.AppUtils.parseJson"], + ), + ) fun String.toKotlinObject(valueType: Class): T { - return parseJson(this, valueType.kotlin) + return parseJson(this) } // GET KEY GIVEN PATH AND DEFAULT VALUE, NULL IF ERROR inline fun Context.getKey(path: String, defVal: T?): T? { try { val json: String = getSharedPrefs().getString(path, null) ?: return defVal - return json.toKotlinObject() - } catch (e: Exception) { + return parseJson(json) + } catch (_: Exception) { return null } } From a5b41e212dc2403a04f017225eb67acfbdfbf72c Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:28:53 -0600 Subject: [PATCH 114/192] Fix --- .../lagradost/cloudstream3/utils/DataStore.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt index 1203b9dcacb..a9ce936cd0f 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/DataStore.kt @@ -181,11 +181,11 @@ object DataStore { } fun Context.getKey(path: String, valueType: Class): T? { - try { + return try { val json: String = getSharedPrefs().getString(path, null) ?: return null - return parseJson(json, valueType.kotlin) - } catch (e: Exception) { - return null + parseJson(json, valueType.kotlin) + } catch (_: Exception) { + null } } @@ -202,7 +202,7 @@ object DataStore { ), ) inline fun String.toKotlinObject(): T { - return parseJson(this) + return parseJson(this) } @Deprecated( @@ -214,16 +214,16 @@ object DataStore { ), ) fun String.toKotlinObject(valueType: Class): T { - return parseJson(this) + return parseJson(this, valueType.kotlin) } // GET KEY GIVEN PATH AND DEFAULT VALUE, NULL IF ERROR inline fun Context.getKey(path: String, defVal: T?): T? { - try { + return try { val json: String = getSharedPrefs().getString(path, null) ?: return defVal - return parseJson(json) + parseJson(json) } catch (_: Exception) { - return null + null } } From f9d4b97de3abffa74d16bb759aa0a1c3aedf179e Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:42:05 -0600 Subject: [PATCH 115/192] Update aes --- .../cloudstream3/extractors/helper/AesHelper.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt index ed048fb82ce..22527bcfb01 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/AesHelper.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.extractors.helper -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.cloudstream3.Prerelease import com.lagradost.cloudstream3.base64DecodeArray import com.lagradost.cloudstream3.base64Encode @@ -10,6 +9,8 @@ import dev.whyoleg.cryptography.CryptographyProvider import dev.whyoleg.cryptography.DelicateCryptographyApi import dev.whyoleg.cryptography.algorithms.AES import dev.whyoleg.cryptography.algorithms.MD5 +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable object AesHelper { @@ -31,7 +32,7 @@ object AesHelper { password = pass, salt = parse.s.hexToByteArray(), ivLength = parse.iv.length / 2, - saltLength = parse.s.length / 2 + saltLength = parse.s.length / 2, ) ?: return null val aesKey = aesCbc.keyDecoder().decodeFromByteArrayBlocking(AES.Key.Format.RAW, key) @@ -100,7 +101,7 @@ object AesHelper { } generatedData.copyOfRange(0, keyLength) to - generatedData.copyOfRange(keyLength, targetKeySize) + generatedData.copyOfRange(keyLength, targetKeySize) } catch (_: Exception) { null } @@ -115,8 +116,8 @@ object AesHelper { @Serializable private data class AesData( - @SerialName("ct") val ct: String, - @SerialName("iv") val iv: String, - @SerialName("s") val s: String, + @JsonProperty("ct") @SerialName("ct") val ct: String, + @JsonProperty("iv") @SerialName("iv") val iv: String, + @JsonProperty("s") @SerialName("s") val s: String, ) } From 901dac90c80b0266876017b018ad2cfabb3cda7d Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 14:45:26 -0600 Subject: [PATCH 116/192] Update gogohelper --- .../extractors/helper/GogoHelper.kt | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt index 199a514b131..22ce5bb4b26 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/GogoHelper.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.extractors.helper -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.fleeksoft.ksoup.nodes.Document import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.base64Decode @@ -18,6 +17,8 @@ import dev.whyoleg.cryptography.CryptographyProvider import dev.whyoleg.cryptography.DelicateCryptographyApi import dev.whyoleg.cryptography.algorithms.AES import io.ktor.http.Url +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable object GogoHelper { @@ -42,7 +43,7 @@ object GogoHelper { string: String, iv: String, secretKeyString: String, - encrypt: Boolean = true + encrypt: Boolean = true, ): String { val ivBytes = iv.encodeToByteArray() val keyBytes = secretKeyString.encodeToByteArray() @@ -77,7 +78,7 @@ object GogoHelper { isUsingAdaptiveKeys: Boolean, isUsingAdaptiveData: Boolean, // If you don't want to re-fetch the document - iframeDocument: Document? = null + iframeDocument: Document? = null, ) = safeApiCall { if ((iv == null || secretKey == null || secretDecryptKey == null) && !isUsingAdaptiveKeys) return@safeApiCall @@ -85,10 +86,9 @@ object GogoHelper { val id = Regex("id=([^&]+)").find(iframeUrl)!!.value.removePrefix("id=") var document: Document? = iframeDocument - val foundIv = - iv ?: (document ?: app.get(iframeUrl).document().also { document = it }) - .select("""div.wrapper[class*=container]""") - .attr("class").split("-").lastOrNull() ?: return@safeApiCall + val foundIv = iv ?: (document ?: app.get(iframeUrl).document().also { document = it }) + .select("""div.wrapper[class*=container]""") + .attr("class").split("-").lastOrNull() ?: return@safeApiCall val foundKey = secretKey ?: getKey(base64Decode(id) + foundIv) ?: return@safeApiCall val foundDecryptKey = secretDecryptKey ?: foundKey @@ -106,25 +106,24 @@ object GogoHelper { "id=$encryptedId&alias=$id" } - val jsonResponse = - app.get( - "$mainUrl/encrypt-ajax.php?$encryptRequestData", - headers = mapOf("X-Requested-With" to "XMLHttpRequest") - ) + val jsonResponse = app.get( + "$mainUrl/encrypt-ajax.php?$encryptRequestData", + headers = mapOf("X-Requested-With" to "XMLHttpRequest") + ) val dataencrypted = jsonResponse.parsedSafe()?.data ?: return@safeApiCall val datadecrypted = cryptoHandler(dataencrypted, foundIv, foundDecryptKey, false) val sources = AppUtils.parseJson(datadecrypted) suspend fun invokeGogoSource( source: GogoSource, - sourceCallback: (ExtractorLink) -> Unit + sourceCallback: (ExtractorLink) -> Unit, ) { if (source.file.contains(".m3u8")) { M3u8Helper.generateM3u8( mainApiName, source.file, mainUrl, - headers = mapOf("Origin" to "https://plyr.link") + headers = mapOf("Origin" to "https://plyr.link"), ).forEach(sourceCallback) } else { sourceCallback.invoke( @@ -146,20 +145,20 @@ object GogoHelper { @Serializable data class GogoSources( - @SerialName("source") val source: List?, - @SerialName("sourceBk") val sourceBk: List?, + @JsonProperty("source") @SerialName("source") val source: List?, + @JsonProperty("sourceBk") @SerialName("sourceBk") val sourceBk: List?, ) @Serializable data class GogoSource( - @SerialName("file") val file: String, - @SerialName("label") val label: String?, - @SerialName("type") val type: String?, - @SerialName("default") val default: String? = null + @JsonProperty("file") @SerialName("file") val file: String, + @JsonProperty("label") @SerialName("label") val label: String?, + @JsonProperty("type") @SerialName("type") val type: String?, + @JsonProperty("default") @SerialName("default") val default: String? = null, ) @Serializable data class GogoJsonData( - @SerialName("data") val data: String? = null + @JsonProperty("data") @SerialName("data") val data: String? = null, ) } From f12063f146718bf6561a895f7698cd8c758d6fcc Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 25 Jun 2026 15:04:33 -0600 Subject: [PATCH 117/192] Update JWPlayerHelper --- .../extractors/helper/JWPlayerHelper.kt | 103 ++++++++++-------- 1 file changed, 55 insertions(+), 48 deletions(-) diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt index f8780ac562b..c9ba4a624ee 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/extractors/helper/JWPlayerHelper.kt @@ -1,7 +1,6 @@ package com.lagradost.cloudstream3.extractors.helper -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.api.Log import com.lagradost.cloudstream3.Prerelease import com.lagradost.cloudstream3.SubtitleFile @@ -10,6 +9,8 @@ import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.M3u8Helper import com.lagradost.cloudstream3.utils.newExtractorLink +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import kotlin.collections.orEmpty @Prerelease @@ -24,10 +25,16 @@ object JwPlayerHelper { * ```js *