diff --git a/app/src/androidTest/java/com/lagradost/cloudstream3/utils/serializers/SerializerTest.kt b/app/src/androidTest/java/com/lagradost/cloudstream3/utils/serializers/SerializerTest.kt new file mode 100644 index 000000000..15ad532f8 --- /dev/null +++ b/app/src/androidTest/java/com/lagradost/cloudstream3/utils/serializers/SerializerTest.kt @@ -0,0 +1,157 @@ +package com.lagradost.cloudstream3.utils.serializers + +import android.net.Uri +import com.lagradost.cloudstream3.utils.AppUtils.parseJson +import com.lagradost.cloudstream3.utils.AppUtils.toJson +import kotlinx.serialization.ExperimentalSerializationApi +import kotlinx.serialization.KeepGeneratedSerializer +import kotlinx.serialization.Serializable +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertNull +import org.junit.Assert.assertTrue +import org.junit.Test + +@OptIn(ExperimentalSerializationApi::class) +@KeepGeneratedSerializer +@Serializable(with = NonEmptyData.Serializer::class) +data class NonEmptyData( + val title: String = "", + val tags: List = emptyList(), + val meta: Map = emptyMap(), + val name: String = "hello", +) { + object Serializer : NonEmptySerializer(NonEmptyData.generatedSerializer()) +} + +@OptIn(ExperimentalSerializationApi::class) +@KeepGeneratedSerializer +@Serializable(with = WriteOnlyData.Serializer::class) +data class WriteOnlyData( + val fieldA: String = "", + val fieldB: String = "", +) { + object Serializer : WriteOnlySerializer( + WriteOnlyData.generatedSerializer(), + setOf("fieldB"), + ) +} + +@OptIn(ExperimentalSerializationApi::class) +@KeepGeneratedSerializer +@Serializable(with = MultiWriteOnly.Serializer::class) +data class MultiWriteOnly( + val fieldA: String = "", + val fieldB: String = "", + val fieldC: String = "", +) { + object Serializer : WriteOnlySerializer( + MultiWriteOnly.generatedSerializer(), + setOf("fieldB", "fieldC"), + ) +} + +@Serializable +data class UriData( + @Serializable(with = UriSerializer::class) + val uri: Uri = Uri.EMPTY, +) + +class SerializerTest { + + @Test + fun nonEmptySerializerOmitsEmptyStrings() { + val data = NonEmptyData(title = "", name = "hello") + val result = data.toJson() + assertFalse(result.contains("title")) + assertTrue(result.contains("name")) + } + + @Test + fun nonEmptySerializerOmitsEmptyLists() { + val data = NonEmptyData(tags = emptyList(), name = "hello") + val result = data.toJson() + assertFalse(result.contains("tags")) + } + + @Test + fun nonEmptySerializerOmitsEmptyMaps() { + val data = NonEmptyData(meta = emptyMap(), name = "hello") + val result = data.toJson() + assertFalse(result.contains("meta")) + } + + @Test + fun nonEmptySerializerKeepsNonEmptyFields() { + val data = NonEmptyData(title = "hello", tags = listOf("a"), meta = mapOf("k" to "v")) + val result = data.toJson() + assertTrue(result.contains("title")) + assertTrue(result.contains("tags")) + assertTrue(result.contains("meta")) + } + + @Test + fun nonEmptySerializerDoesNotAffectDeserialization() { + val input = """{"title":"hello","tags":["a"],"meta":{"k":"v"},"name":"world"}""" + val result = parseJson(input) + assertEquals("hello", result.title) + assertEquals(listOf("a"), result.tags) + assertEquals(mapOf("k" to "v"), result.meta) + assertEquals("world", result.name) + } + + @Test + fun writeOnlySerializerOmitsFieldOnSerialize() { + val data = WriteOnlyData(fieldA = "hello", fieldB = "secret") + val result = data.toJson() + assertTrue(result.contains("fieldA")) + assertFalse(result.contains("fieldB")) + } + + @Test + fun writeOnlySerializerDeserializesNormally() { + val input = """{"fieldA":"hello","fieldB":"secret"}""" + val result = parseJson(input) + assertEquals("hello", result.fieldA) + assertEquals("secret", result.fieldB) + } + + @Test + fun writeOnlySerializerDeserializesMissingAsDefault() { + val input = """{"fieldA":"hello"}""" + val result = parseJson(input) + assertEquals("hello", result.fieldA) + assertEquals("", result.fieldB) + } + + @Test + fun writeOnlySerializerHandlesMultipleKeys() { + val data = MultiWriteOnly(fieldA = "hello", fieldB = "secret1", fieldC = "secret2") + val result = data.toJson() + assertTrue(result.contains("fieldA")) + assertFalse(result.contains("fieldB")) + assertFalse(result.contains("fieldC")) + } + + @Test + fun uriSerializerSerializesUriToString() { + val data = UriData(uri = Uri.parse("https://example.com/path?query=1")) + val result = data.toJson() + assertTrue(result.contains("https://example.com/path?query=1")) + } + + @Test + fun uriSerializerDeserializesStringToUri() { + val input = """{"uri":"https://example.com/path?query=1"}""" + val result = parseJson(input) + assertEquals(Uri.parse("https://example.com/path?query=1"), result.uri) + } + + @Test + fun uriSerializerRoundtripsCorrectly() { + val data = UriData(uri = Uri.parse("https://example.com/path?query=1")) + val encoded = data.toJson() + val decoded = parseJson(encoded) + assertEquals(data.uri, decoded.uri) + } +} diff --git a/app/src/androidTest/java/com/lagradost/cloudstream3/utils/serializers/UriSerializerTest.kt b/app/src/androidTest/java/com/lagradost/cloudstream3/utils/serializers/UriSerializerTest.kt deleted file mode 100644 index 3ffd37124..000000000 --- a/app/src/androidTest/java/com/lagradost/cloudstream3/utils/serializers/UriSerializerTest.kt +++ /dev/null @@ -1,41 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializers - -import android.net.Uri -import com.lagradost.cloudstream3.utils.AppUtils.parseJson -import com.lagradost.cloudstream3.utils.AppUtils.toJson -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import org.junit.Assert.assertEquals -import org.junit.Assert.assertTrue -import org.junit.Test - -@Serializable -data class UriData( - @Serializable(with = UriSerializer::class) - @SerialName("uri") val uri: Uri = Uri.EMPTY, -) - -class UriSerializerTest { - - @Test - fun uriSerializerSerializesUriToString() { - val data = UriData(uri = Uri.parse("https://example.com/path?query=1")) - val result = data.toJson() - assertTrue(result.contains("https://example.com/path?query=1")) - } - - @Test - fun uriSerializerDeserializesStringToUri() { - val input = """{"uri":"https://example.com/path?query=1"}""" - val result = parseJson(input) - assertEquals(Uri.parse("https://example.com/path?query=1"), result.uri) - } - - @Test - fun uriSerializerRoundtripsCorrectly() { - val data = UriData(uri = Uri.parse("https://example.com/path?query=1")) - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data.uri, decoded.uri) - } -} 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 7e5d04eb0..2e554f75e 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 @@ -9,8 +9,6 @@ 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 @@ -34,14 +32,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 (_: ConnectException) { + } catch (e: ConnectException) { // `Failed to connect to /127.0.0.1:8090` if the server is down false } catch (t: Throwable) { @@ -54,7 +52,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 { @@ -70,7 +68,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( @@ -85,7 +83,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 { @@ -106,7 +104,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 { @@ -128,7 +126,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 { @@ -166,8 +164,10 @@ 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( @@ -184,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( @@ -204,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" @@ -278,55 +278,94 @@ 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, + @JsonProperty("action") + val action: String, + @JsonProperty("hash") + val hash: String = "", + @JsonProperty("link") + val link: String = "", + @JsonProperty("title") + val title: String = "", + @JsonProperty("poster") + val poster: String = "", + @JsonProperty("data") + val data: String = "", + @JsonProperty("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?, + @JsonProperty("title") + var title: String, + @JsonProperty("poster") + var poster: String, + @JsonProperty("data") + var data: String?, + @JsonProperty("timestamp") + var timestamp: Long, + @JsonProperty("name") + var name: String?, + @JsonProperty("hash") + var hash: String?, + @JsonProperty("stat") + var stat: Int, + @JsonProperty("stat_string") + var statString: String, + @JsonProperty("loaded_size") + var loadedSize: Long?, + @JsonProperty("torrent_size") + var torrentSize: Long?, + @JsonProperty("preloaded_bytes") + var preloadedBytes: Long?, + @JsonProperty("preload_size") + var preloadSize: Long?, + @JsonProperty("download_speed") + var downloadSpeed: Double?, + @JsonProperty("upload_speed") + var uploadSpeed: Double?, + @JsonProperty("total_peers") + var totalPeers: Int?, + @JsonProperty("pending_peers") + var pendingPeers: Int?, + @JsonProperty("active_peers") + var activePeers: Int?, + @JsonProperty("connected_seeders") + var connectedSeeders: Int?, + @JsonProperty("half_open_peers") + var halfOpenPeers: Int?, + @JsonProperty("bytes_written") + var bytesWritten: Long?, + @JsonProperty("bytes_written_data") + var bytesWrittenData: Long?, + @JsonProperty("bytes_read") + var bytesRead: Long?, + @JsonProperty("bytes_read_data") + var bytesReadData: Long?, + @JsonProperty("bytes_read_useful_data") + var bytesReadUsefulData: Long?, + @JsonProperty("chunks_written") + var chunksWritten: Long?, + @JsonProperty("chunks_read") + var chunksRead: Long?, + @JsonProperty("chunks_read_useful") + var chunksReadUseful: Long?, + @JsonProperty("chunks_read_wasted") + var chunksReadWasted: Long?, + @JsonProperty("pieces_dirtied_good") + var piecesDirtiedGood: Long?, + @JsonProperty("pieces_dirtied_bad") + var piecesDirtiedBad: Long?, + @JsonProperty("duration_seconds") + var durationSeconds: Double?, + @JsonProperty("bit_rate") + var bitRate: String?, + @JsonProperty("file_stats") + var fileStats: List?, + @JsonProperty("trackers") + var trackers: List?, ) { fun streamUrl(url: String): String { val fileName = @@ -342,10 +381,12 @@ 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?, + @JsonProperty("id") + val id: Int?, + @JsonProperty("path") + val path: String?, + @JsonProperty("length") + val length: Long?, ) -} +} \ No newline at end of file diff --git a/library/api/jvm/library.api b/library/api/jvm/library.api index cd2aaeea1..025ebc391 100644 --- a/library/api/jvm/library.api +++ b/library/api/jvm/library.api @@ -5831,7 +5831,6 @@ public class com/lagradost/cloudstream3/metaproviders/TraktProvider : com/lagrad } public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Airs { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs$Companion; public fun ()V public fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V public synthetic fun (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5848,23 +5847,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Airs { public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Airs$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Airs$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Cast { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Cast$Companion; public fun ()V public fun (Ljava/lang/String;Ljava/util/List;Ljava/lang/Long;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Person;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;)V public synthetic fun (Ljava/lang/String;Ljava/util/List;Ljava/lang/Long;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Person;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5885,23 +5868,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Cast { public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Cast$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Cast$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Cast; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Cast;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Cast$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Data { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Data$Companion; public fun ()V public fun (Lcom/lagradost/cloudstream3/TvType;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;)V public synthetic fun (Lcom/lagradost/cloudstream3/TvType;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5916,23 +5883,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Data { public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Data$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Data$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Data; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Data;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Data$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Ids { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids$Companion; public fun ()V public fun (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;)V public synthetic fun (Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5955,23 +5906,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Ids { public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Ids$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Ids$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Images { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images$Companion; public fun ()V public fun (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;)V public synthetic fun (Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -5998,23 +5933,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Images public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Images$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Images$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData$Companion; public fun ()V public fun (Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;ZLjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZ)V public synthetic fun (Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;ZLjava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ZZZILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -6075,26 +5994,10 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$LinkDa public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$LinkData$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails$Companion; public fun ()V - public fun (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary;ILkotlin/jvm/internal/DefaultConstructorMarker;)V + public fun (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;)V + public synthetic fun (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;ILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun component1 ()Ljava/lang/String; public final fun component10 ()Ljava/lang/String; public final fun component11 ()Ljava/lang/String; @@ -6113,7 +6016,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaD public final fun component23 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs; public final fun component24 ()Ljava/lang/String; public final fun component25 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images; - public final fun component26 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary; + public final fun component26 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; public final fun component3 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids; public final fun component4 ()Ljava/lang/String; public final fun component5 ()Ljava/lang/String; @@ -6121,8 +6024,8 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaD public final fun component7 ()Ljava/lang/Integer; public final fun component8 ()Ljava/lang/String; public final fun component9 ()Ljava/lang/String; - public final fun copy (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; - public static synthetic fun copy$default (Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary;ILjava/lang/Object;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; + public final fun copy (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; + public static synthetic fun copy$default (Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Long;Ljava/lang/Long;Ljava/lang/String;Ljava/util/List;Ljava/util/List;Ljava/util/List;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;ILjava/lang/Object;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; public fun equals (Ljava/lang/Object;)Z public final fun getAiredEpisodes ()Ljava/lang/Integer; public final fun getAirs ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Airs; @@ -6137,7 +6040,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaD public final fun getImages ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images; public final fun getLanguage ()Ljava/lang/String; public final fun getLanguages ()Ljava/util/List; - public final fun getMedia ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary; + public final fun getMedia ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; public final fun getNetwork ()Ljava/lang/String; public final fun getOverview ()Ljava/lang/String; public final fun getRating ()Ljava/lang/Double; @@ -6154,60 +6057,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaD public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaDetails$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary$Companion; - public fun ()V - public fun (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/Double;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;)V - public synthetic fun (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/Double;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;ILkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun component1 ()Ljava/lang/String; - public final fun component2 ()Ljava/lang/Integer; - public final fun component3 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids; - public final fun component4 ()Ljava/lang/Double; - public final fun component5 ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images; - public final fun copy (Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/Double;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary; - public static synthetic fun copy$default (Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary;Ljava/lang/String;Ljava/lang/Integer;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Ljava/lang/Double;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;ILjava/lang/Object;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary; - public fun equals (Ljava/lang/Object;)Z - public final fun getIds ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids; - public final fun getImages ()Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images; - public final fun getRating ()Ljava/lang/Double; - public final fun getTitle ()Ljava/lang/String; - public final fun getYear ()Ljava/lang/Integer; - public fun hashCode ()I - public fun toString ()Ljava/lang/String; -} - -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$MediaSummary$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$People { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$People$Companion; public fun ()V public fun (Ljava/util/List;)V public synthetic fun (Ljava/util/List;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -6220,23 +6070,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$People public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$People$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$People$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$People; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$People;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$People$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Person { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Person$Companion; public fun ()V public fun (Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;)V public synthetic fun (Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -6253,23 +6087,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Person public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Person$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Person$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Person; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Person;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Person$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons$Companion; public fun ()V public fun (Ljava/lang/Integer;Ljava/lang/Integer;Ljava/util/List;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V public synthetic fun (Ljava/lang/Integer;Ljava/lang/Integer;Ljava/util/List;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Ljava/lang/String;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -6306,23 +6124,7 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Season public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$Seasons$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode { - public static final field Companion Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode$Companion; public fun ()V public fun (Ljava/util/List;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;)V public synthetic fun (Ljava/util/List;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Ids;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$Images;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/Double;Ljava/lang/Integer;Ljava/lang/Integer;Ljava/lang/String;Ljava/lang/String;Ljava/lang/Integer;ILkotlin/jvm/internal/DefaultConstructorMarker;)V @@ -6363,21 +6165,6 @@ public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$TraktE public fun toString ()Ljava/lang/String; } -public final synthetic class com/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode$$serializer : kotlinx/serialization/internal/GeneratedSerializer { - public static final field INSTANCE Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode$$serializer; - public final fun childSerializers ()[Lkotlinx/serialization/KSerializer; - public final fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode; - public synthetic fun deserialize (Lkotlinx/serialization/encoding/Decoder;)Ljava/lang/Object; - public final fun getDescriptor ()Lkotlinx/serialization/descriptors/SerialDescriptor; - public final fun serialize (Lkotlinx/serialization/encoding/Encoder;Lcom/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode;)V - public synthetic fun serialize (Lkotlinx/serialization/encoding/Encoder;Ljava/lang/Object;)V - public fun typeParametersSerializers ()[Lkotlinx/serialization/KSerializer; -} - -public final class com/lagradost/cloudstream3/metaproviders/TraktProvider$TraktEpisode$Companion { - public final fun serializer ()Lkotlinx/serialization/KSerializer; -} - public final class com/lagradost/cloudstream3/mvvm/ArchComponentExtKt { public static final field DEBUG_EXCEPTION Ljava/lang/String; public static final field DEBUG_PRINT Ljava/lang/String; 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 6011e14ea..dafec4d97 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/metaproviders/TraktProvider.kt @@ -34,10 +34,6 @@ 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" @@ -50,6 +46,7 @@ open class TraktProvider : MainAPI() { ) private val traktApiUrl = "https://api.trakt.tv" + private val traktClientId: String = BuildConfig.TRAKT_CLIENT_ID override val mainPage = mainPageOf( @@ -61,21 +58,16 @@ 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 ?: MediaSummary( - title = this.title, - year = this.year, - ids = this.ids, - rating = this.rating, - images = this.images, - ) + + val media = this.media ?: this val mediaType = if (media.ids?.tvdb == null) TvType.Movie else TvType.TvSeries val poster = media.images?.poster?.firstOrNull() return if (mediaType == TvType.Movie) { @@ -83,7 +75,7 @@ open class TraktProvider : MainAPI() { name = media.title ?: "", url = Data( type = mediaType, - mediaDetails = this, + mediaDetails = media, ).toJson(), type = TvType.Movie, ) { @@ -95,7 +87,7 @@ open class TraktProvider : MainAPI() { name = media.title ?: "", url = Data( type = mediaType, - mediaDetails = this, + mediaDetails = media, ).toJson(), type = TvType.TvSeries, ) { @@ -106,7 +98,9 @@ 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() }) @@ -121,7 +115,9 @@ 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( @@ -132,7 +128,9 @@ 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 = @@ -144,6 +142,7 @@ 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 +156,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,6 +190,7 @@ 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() @@ -198,7 +198,9 @@ 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, @@ -232,7 +234,8 @@ 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.rating = episode.rating?.times(10)?.roundToInt() this.score = Score.from10(episode.rating) this.addDate(episode.firstAired, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX") @@ -304,164 +307,143 @@ open class TraktProvider : MainAPI() { return "https://$url" } - @Serializable data class Data( - @JsonProperty("type") @SerialName("type") val type: TvType? = null, - @JsonProperty("mediaDetails") @SerialName("mediaDetails") val mediaDetails: MediaDetails? = null, + val type: TvType? = null, + 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( - @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("media") @JsonAlias("movie", "show") @SerialName("media") @JsonNames("movie", "show") val media: MediaSummary? = null, + @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 ) - @Serializable data class Airs( - @JsonProperty("day") @SerialName("day") val day: String? = null, - @JsonProperty("time") @SerialName("time") val time: String? = null, - @JsonProperty("timezone") @SerialName("timezone") val timezone: String? = null, + @JsonProperty("day") val day: String? = null, + @JsonProperty("time") val time: String? = null, + @JsonProperty("timezone") val timezone: String? = null, ) - @Serializable data class Ids( - @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, + @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, ) - @Serializable data class Images( - @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, + @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, ) - @Serializable data class People( - @JsonProperty("cast") @SerialName("cast") val cast: List? = null, + @JsonProperty("cast") val cast: List? = null, ) - @Serializable data class Cast( - @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, + @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, ) - @Serializable data class Person( - @JsonProperty("name") @SerialName("name") val name: String? = null, - @JsonProperty("ids") @SerialName("ids") val ids: Ids? = null, - @JsonProperty("images") @SerialName("images") val images: Images? = null, + @JsonProperty("name") val name: String? = null, + @JsonProperty("ids") val ids: Ids? = null, + @JsonProperty("images") val images: Images? = null, ) - @Serializable data class Seasons( - @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, + @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, ) - @Serializable data class TraktEpisode( - @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, + @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, ) - @Serializable data class LinkData( - @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, + @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, ) } diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/FloatAsIntSerializer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/FloatAsIntSerializer.kt deleted file mode 100644 index 12c8f6ed0..000000000 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/FloatAsIntSerializer.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializers - -import com.lagradost.cloudstream3.Prerelease -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 -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.doubleOrNull -import kotlinx.serialization.json.intOrNull - -/** - * Replicates Jackson's ACCEPT_FLOAT_AS_INT behaviour for Int fields. - * A floating-point JSON number is truncated to Int by dropping the - * fractional part, exactly like Jackson's default truncation behaviour. - * - * Usage: - * - * @Serializable - * data class MyData( - * @Serializable(with = FloatAsIntSerializer::class) - * @SerialName("count") val count: Int = 0, - * ) - */ -@Prerelease -object FloatAsIntSerializer : KSerializer { - - override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("FloatAsInt", PrimitiveKind.INT) - - override fun deserialize(decoder: Decoder): Int { - val jsonDecoder = decoder as? JsonDecoder ?: return decoder.decodeInt() - val element = jsonDecoder.decodeJsonElement() - if (element !is JsonPrimitive) return 0 - return element.intOrNull ?: element.doubleOrNull?.toInt() ?: 0 - } - - override fun serialize(encoder: Encoder, value: Int) = encoder.encodeInt(value) -} diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/FloatAsLongSerializer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/FloatAsLongSerializer.kt deleted file mode 100644 index 7fc394107..000000000 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/FloatAsLongSerializer.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializers - -import com.lagradost.cloudstream3.Prerelease -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 -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.doubleOrNull -import kotlinx.serialization.json.longOrNull - -/** - * Replicates Jackson's ACCEPT_FLOAT_AS_INT behaviour for Long fields. - * A floating-point JSON number is truncated to Long by dropping the - * fractional part, exactly like Jackson's default truncation behaviour. - * - * Usage: - * - * @Serializable - * data class MyData( - * @Serializable(with = FloatAsLongSerializer::class) - * @SerialName("timestamp") val timestamp: Long = 0L, - * ) - */ -@Prerelease -object FloatAsLongSerializer : KSerializer { - - override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("FloatAsLong", PrimitiveKind.LONG) - - override fun deserialize(decoder: Decoder): Long { - val jsonDecoder = decoder as? JsonDecoder ?: return decoder.decodeLong() - val element = jsonDecoder.decodeJsonElement() - if (element !is JsonPrimitive) return 0L - return element.longOrNull ?: element.doubleOrNull?.toLong() ?: 0L - } - - override fun serialize(encoder: Encoder, value: Long) = encoder.encodeLong(value) -} diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/JsonTransformSerializer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/JsonTransformSerializer.kt deleted file mode 100644 index 6b9c25b59..000000000 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/JsonTransformSerializer.kt +++ /dev/null @@ -1,75 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializers - -import com.lagradost.cloudstream3.Prerelease -import kotlinx.serialization.KSerializer -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.json.JsonTransformingSerializer - -/** - * Composable deserialize transformer that applies multiple Jackson-equivalent - * behaviours to specific fields by key. Pass only the sets you need; all - * default to empty (no-op). - * - * Behaviours (applied in order per field): - * singleValueAsListKeys ACCEPT_SINGLE_VALUE_AS_ARRAY - * emptyStringAsNullKeys ACCEPT_EMPTY_STRING_AS_NULL_OBJECT - * emptyArrayAsNullKeys ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT - * - * Usage: - * - * @OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now - * @KeepGeneratedSerializer - * @Serializable(with = MyData.Serializer::class) - * data class MyData( - * @SerialName("title") val title: String? = null, - * @SerialName("tags") val tags: List? = null, - * @SerialName("meta") val meta: MyMeta? = null, - * ) { - * object Serializer : JsonTransformSerializer( - * MyData.generatedSerializer(), - * singleValueAsListKeys = setOf("tags"), - * emptyStringAsNullKeys = setOf("title", "tags"), - * emptyArrayAsNullKeys = setOf("tags", "meta"), - * ) - * } - */ -@Prerelease -abstract class JsonTransformSerializer( - tSerializer: KSerializer, - private val singleValueAsListKeys: Set = emptySet(), - private val emptyArrayAsNullKeys: Set = emptySet(), - private val emptyStringAsNullKeys: Set = emptySet(), -) : JsonTransformingSerializer(tSerializer) { - - override fun transformDeserialize(element: JsonElement): JsonElement { - if (element !is JsonObject) return element - return JsonObject(element.mapValues { (key, value) -> - var result = value - if (key in singleValueAsListKeys) { - result = when (result) { - is JsonArray -> result - JsonNull -> JsonArray(emptyList()) - else -> JsonArray(listOf(result)) - } - } - - if (key in emptyStringAsNullKeys) { - if (result is JsonPrimitive && result.isString && result.content.isEmpty()) { - result = JsonNull - } - } - - if (key in emptyArrayAsNullKeys) { - if (result is JsonArray && result.isEmpty()) { - result = JsonNull - } - } - - result - }) - } -} diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NonEmptySerializer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NonEmptySerializer.kt index 8bc8f1734..62b306e1f 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NonEmptySerializer.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NonEmptySerializer.kt @@ -17,13 +17,13 @@ import kotlinx.serialization.json.JsonTransformingSerializer * * Usage: * - * @OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now + * @OptIn(ExperimentalSerializationApi::class) * @KeepGeneratedSerializer * @Serializable(with = MyData.Serializer::class) * data class MyData( - * @SerialName("tags") val tags: List = emptyList(), - * @SerialName("title") val title: String = "", - * @SerialName("meta") val meta: Map = emptyMap(), + * val tags: List = emptyList(), + * val title: String = "", + * val meta: Map = emptyMap(), * ) { * object Serializer : NonEmptySerializer(MyData.generatedSerializer()) * } @@ -33,6 +33,7 @@ abstract class NonEmptySerializer(tSerializer: KSerializer) : override fun transformSerialize(element: JsonElement): JsonElement { if (element !is JsonObject) return element + return JsonObject(element.filterValues { value -> when (value) { is JsonPrimitive -> value.content.isNotEmpty() diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NullableStringSerializer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NullableStringSerializer.kt deleted file mode 100644 index 6755304a5..000000000 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/NullableStringSerializer.kt +++ /dev/null @@ -1,49 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializers - -import com.lagradost.cloudstream3.Prerelease -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.KSerializer -import kotlinx.serialization.builtins.serializer -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 -import kotlinx.serialization.json.JsonDecoder -import kotlinx.serialization.json.JsonNull -import kotlinx.serialization.json.JsonPrimitive -import kotlinx.serialization.json.decodeFromJsonElement - -/** - * Convenience serializer for nullable String fields that combines - * ACCEPT_EMPTY_STRING_AS_NULL_OBJECT with null passthrough. - * An empty JSON string (`""`) or JSON null is decoded as null. - * - * Usage: - * - * @Serializable - * data class MyData( - * @Serializable(with = NullableStringSerializer::class) - * @SerialName("title") val title: String? = null, - * ) - */ -@Prerelease -object NullableStringSerializer : KSerializer { - - override val descriptor: SerialDescriptor = - PrimitiveSerialDescriptor("NullableString", PrimitiveKind.STRING) - - override fun deserialize(decoder: Decoder): String? { - val jsonDecoder = decoder as? JsonDecoder ?: return decoder.decodeString() - return when (val element = jsonDecoder.decodeJsonElement()) { - is JsonPrimitive -> element.content.ifEmpty { null } - JsonNull -> null - else -> jsonDecoder.json.decodeFromJsonElement(String.serializer(), element) - } - } - - override fun serialize(encoder: Encoder, value: String?) { - @OptIn(ExperimentalSerializationApi::class) // encodeNull is experimental for now - if (value == null) encoder.encodeNull() else encoder.encodeString(value) - } -} diff --git a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/WriteOnlySerializer.kt b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/WriteOnlySerializer.kt index 1b6ca9aee..1d06b7fca 100644 --- a/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/WriteOnlySerializer.kt +++ b/library/src/commonMain/kotlin/com/lagradost/cloudstream3/utils/serializers/WriteOnlySerializer.kt @@ -12,12 +12,12 @@ import kotlinx.serialization.json.JsonTransformingSerializer * * Usage: * - * @OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now + * @OptIn(ExperimentalSerializationApi::class) * @KeepGeneratedSerializer * @Serializable(with = MyData.Serializer::class) * data class MyData( - * @SerialName("fieldA") val fieldA: String = "", - * @SerialName("fieldB") val fieldB: String = "", + * val fieldA: String = "", + * val fieldB: String = "", * ) { * object Serializer : WriteOnlySerializer( * MyData.generatedSerializer(), diff --git a/library/src/commonTest/kotlin/com/lagradost/cloudstream3/utils/serializers/SerializersTest.kt b/library/src/commonTest/kotlin/com/lagradost/cloudstream3/utils/serializers/SerializersTest.kt deleted file mode 100644 index 89c0fea81..000000000 --- a/library/src/commonTest/kotlin/com/lagradost/cloudstream3/utils/serializers/SerializersTest.kt +++ /dev/null @@ -1,602 +0,0 @@ -package com.lagradost.cloudstream3.utils.serializers - -import com.lagradost.cloudstream3.utils.AppUtils.parseJson -import com.lagradost.cloudstream3.utils.AppUtils.toJson -import kotlinx.serialization.ExperimentalSerializationApi -import kotlinx.serialization.KeepGeneratedSerializer -import kotlinx.serialization.SerialName -import kotlinx.serialization.Serializable -import kotlin.test.Test -import kotlin.test.assertEquals -import kotlin.test.assertFalse -import kotlin.test.assertNull -import kotlin.test.assertTrue - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = NonEmptyData.Serializer::class) -data class NonEmptyData( - @SerialName("title") val title: String = "", - @SerialName("tags") val tags: List = emptyList(), - @SerialName("meta") val meta: Map = emptyMap(), - @SerialName("name") val name: String = "hello", -) { - object Serializer : NonEmptySerializer(NonEmptyData.generatedSerializer()) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = WriteOnlyData.Serializer::class) -data class WriteOnlyData( - @SerialName("fieldA") val fieldA: String = "", - @SerialName("fieldB") val fieldB: String = "", -) { - object Serializer : WriteOnlySerializer( - WriteOnlyData.generatedSerializer(), - setOf("fieldB"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = MultiWriteOnly.Serializer::class) -data class MultiWriteOnly( - @SerialName("fieldA") val fieldA: String = "", - @SerialName("fieldB") val fieldB: String = "", - @SerialName("fieldC") val fieldC: String = "", -) { - object Serializer : WriteOnlySerializer( - MultiWriteOnly.generatedSerializer(), - setOf("fieldB", "fieldC"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = SingleValueData.Serializer::class) -data class SingleValueData( - @SerialName("tags") val tags: List = emptyList(), - @SerialName("nums") val nums: List = emptyList(), -) { - object Serializer : JsonTransformSerializer( - SingleValueData.generatedSerializer(), - singleValueAsListKeys = setOf("tags", "nums"), - ) -} - -@Serializable -data class NestedMeta( - @SerialName("key") val key: String = "", -) - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = EmptyArrayData.Serializer::class) -data class EmptyArrayData( - @SerialName("meta") val meta: NestedMeta? = null, - @SerialName("other") val other: String = "hello", -) { - object Serializer : JsonTransformSerializer( - EmptyArrayData.generatedSerializer(), - emptyArrayAsNullKeys = setOf("meta"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = EmptyStringData.Serializer::class) -data class EmptyStringData( - @SerialName("title") val title: String? = null, - @SerialName("episode") val episode: NestedMeta? = null, - @SerialName("keep") val keep: String? = "hello", -) { - object Serializer : JsonTransformSerializer( - EmptyStringData.generatedSerializer(), - emptyStringAsNullKeys = setOf("title", "episode", "keep"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = SingleValueOrNullData.Serializer::class) -data class SingleValueOrNullData( - @SerialName("tags") val tags: List? = null, - @SerialName("nums") val nums: List? = null, - @SerialName("other") val other: String = "hello", -) { - object Serializer : JsonTransformSerializer( - SingleValueOrNullData.generatedSerializer(), - singleValueAsListKeys = setOf("tags", "nums"), - emptyArrayAsNullKeys = setOf("tags", "nums"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = NullableFieldsData.Serializer::class) -data class NullableFieldsData( - @SerialName("title") val title: String? = null, - @SerialName("meta") val meta: NestedMeta? = null, - @SerialName("other") val other: String = "hello", -) { - object Serializer : JsonTransformSerializer( - NullableFieldsData.generatedSerializer(), - emptyStringAsNullKeys = setOf("title"), - emptyArrayAsNullKeys = setOf("meta"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = SingleValueOrEmptyStringData.Serializer::class) -data class SingleValueOrEmptyStringData( - @SerialName("tags") val tags: List = emptyList(), - @SerialName("title") val title: String? = null, -) { - object Serializer : JsonTransformSerializer( - SingleValueOrEmptyStringData.generatedSerializer(), - singleValueAsListKeys = setOf("tags"), - emptyStringAsNullKeys = setOf("title"), - ) -} - -@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now -@KeepGeneratedSerializer -@Serializable(with = AllTransformsData.Serializer::class) -data class AllTransformsData( - @SerialName("tags") val tags: List? = null, - @SerialName("title") val title: String? = null, - @SerialName("meta") val meta: NestedMeta? = null, - @SerialName("other") val other: String = "hello", -) { - object Serializer : JsonTransformSerializer( - AllTransformsData.generatedSerializer(), - singleValueAsListKeys = setOf("tags"), - emptyArrayAsNullKeys = setOf("tags", "meta"), - emptyStringAsNullKeys = setOf("title", "tags"), - ) -} - -@Serializable -data class FloatIntData( - @Serializable(with = FloatAsIntSerializer::class) - @SerialName("count") val count: Int = 0, -) - -@Serializable -data class FloatLongData( - @Serializable(with = FloatAsLongSerializer::class) - @SerialName("timestamp") val timestamp: Long = 0L, -) - -@Serializable -data class NullableStringData( - @Serializable(with = NullableStringSerializer::class) - @SerialName("title") val title: String? = null, -) - -class SerializersTest { - - @Test - fun nonEmptySerializerOmitsEmptyStrings() { - val data = NonEmptyData(title = "", name = "hello") - val result = data.toJson() - assertFalse(result.contains("title")) - assertTrue(result.contains("name")) - } - - @Test - fun nonEmptySerializerOmitsEmptyLists() { - val data = NonEmptyData(tags = emptyList(), name = "hello") - val result = data.toJson() - assertFalse(result.contains("tags")) - } - - @Test - fun nonEmptySerializerOmitsEmptyMaps() { - val data = NonEmptyData(meta = emptyMap(), name = "hello") - val result = data.toJson() - assertFalse(result.contains("meta")) - } - - @Test - fun nonEmptySerializerKeepsNonEmptyFields() { - val data = NonEmptyData(title = "hello", tags = listOf("a"), meta = mapOf("k" to "v")) - val result = data.toJson() - assertTrue(result.contains("title")) - assertTrue(result.contains("tags")) - assertTrue(result.contains("meta")) - } - - @Test - fun nonEmptySerializerDoesNotAffectDeserialization() { - val input = """{"title":"hello","tags":["a"],"meta":{"k":"v"},"name":"world"}""" - val result = parseJson(input) - assertEquals("hello", result.title) - assertEquals(listOf("a"), result.tags) - assertEquals(mapOf("k" to "v"), result.meta) - assertEquals("world", result.name) - } - - @Test - fun writeOnlySerializerOmitsFieldOnSerialize() { - val data = WriteOnlyData(fieldA = "hello", fieldB = "secret") - val result = data.toJson() - assertTrue(result.contains("fieldA")) - assertFalse(result.contains("fieldB")) - } - - @Test - fun writeOnlySerializerDeserializesNormally() { - val input = """{"fieldA":"hello","fieldB":"secret"}""" - val result = parseJson(input) - assertEquals("hello", result.fieldA) - assertEquals("secret", result.fieldB) - } - - @Test - fun writeOnlySerializerDeserializesMissingAsDefault() { - val input = """{"fieldA":"hello"}""" - val result = parseJson(input) - assertEquals("hello", result.fieldA) - assertEquals("", result.fieldB) - } - - @Test - fun writeOnlySerializerHandlesMultipleKeys() { - val data = MultiWriteOnly(fieldA = "hello", fieldB = "secret1", fieldC = "secret2") - val result = data.toJson() - assertTrue(result.contains("fieldA")) - assertFalse(result.contains("fieldB")) - assertFalse(result.contains("fieldC")) - } - - @Test - fun singleValueAsListDecodesArrayNormally() { - val input = """{"tags":["a","b"],"nums":[1,2]}""" - val result = parseJson(input) - assertEquals(listOf("a", "b"), result.tags) - assertEquals(listOf(1, 2), result.nums) - } - - @Test - fun singleValueAsListWrapsBareStringInList() { - val input = """{"tags":"a","nums":[1]}""" - val result = parseJson(input) - assertEquals(listOf("a"), result.tags) - } - - @Test - fun singleValueAsListWrapsBareIntInList() { - val input = """{"tags":[],"nums":42}""" - val result = parseJson(input) - assertEquals(listOf(42), result.nums) - } - - @Test - fun singleValueAsListDecodesNullAsEmptyList() { - val input = """{"tags":null,"nums":[]}""" - val result = parseJson(input) - assertEquals(emptyList(), result.tags) - } - - @Test - fun singleValueAsListRoundtripsCorrectly() { - val data = SingleValueData(tags = listOf("x", "y"), nums = listOf(1, 2)) - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun emptyArrayAsNullDecodesEmptyArrayAsNull() { - val input = """{"meta":[],"other":"hello"}""" - val result = parseJson(input) - assertNull(result.meta) - } - - @Test - fun emptyArrayAsNullDecodesNullAsNull() { - val input = """{"meta":null,"other":"hello"}""" - val result = parseJson(input) - assertNull(result.meta) - } - - @Test - fun emptyArrayAsNullDecodesObjectNormally() { - val input = """{"meta":{"key":"value"},"other":"hello"}""" - val result = parseJson(input) - assertEquals(NestedMeta("value"), result.meta) - } - - @Test - fun emptyArrayAsNullDoesNotAffectOtherFields() { - val input = """{"meta":[],"other":"world"}""" - val result = parseJson(input) - assertEquals("world", result.other) - } - - @Test - fun emptyArrayAsNullRoundtripsCorrectly() { - val data = EmptyArrayData(meta = NestedMeta("test"), other = "hello") - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun emptyStringAsNullDecodesEmptyStringAsNull() { - val input = """{"title":"","episode":null,"keep":"hello"}""" - val result = parseJson(input) - assertNull(result.title) - } - - @Test - fun emptyStringAsNullDecodesNullAsNull() { - val input = """{"title":null,"episode":null,"keep":"hello"}""" - val result = parseJson(input) - assertNull(result.title) - } - - @Test - fun emptyStringAsNullKeepsNonEmptyString() { - val input = """{"title":"hello","episode":null,"keep":"world"}""" - val result = parseJson(input) - assertEquals("hello", result.title) - } - - @Test - fun emptyStringAsNullDecodesObjectNormally() { - val input = """{"title":null,"episode":{"key":"value"},"keep":"hello"}""" - val result = parseJson(input) - assertEquals(NestedMeta("value"), result.episode) - } - - @Test - fun emptyStringAsNullDoesNotAffectNonEmptyFields() { - val input = """{"title":"","episode":null,"keep":"world"}""" - val result = parseJson(input) - assertEquals("world", result.keep) - } - - @Test - fun emptyStringAsNullRoundtripsCorrectly() { - val data = EmptyStringData(title = "hello", episode = NestedMeta("x"), keep = "world") - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun singleValueOrNullWrapsBareValueInList() { - val input = """{"tags":"a","nums":1,"other":"hello"}""" - val result = parseJson(input) - assertEquals(listOf("a"), result.tags) - assertEquals(listOf(1), result.nums) - } - - @Test - fun singleValueOrNullTreatsEmptyArrayAsNull() { - val input = """{"tags":[],"nums":[],"other":"hello"}""" - val result = parseJson(input) - assertNull(result.tags) - assertNull(result.nums) - } - - @Test - fun singleValueOrNullDecodesArrayNormally() { - val input = """{"tags":["a","b"],"nums":[1,2],"other":"hello"}""" - val result = parseJson(input) - assertEquals(listOf("a", "b"), result.tags) - assertEquals(listOf(1, 2), result.nums) - } - - @Test - fun singleValueOrNullDoesNotAffectOtherFields() { - val input = """{"tags":[],"nums":[],"other":"world"}""" - val result = parseJson(input) - assertEquals("world", result.other) - } - - @Test - fun nullableFieldsEmptyStringBecomesNull() { - val input = """{"title":"","meta":{"key":"value"},"other":"hello"}""" - val result = parseJson(input) - assertNull(result.title) - assertEquals(NestedMeta("value"), result.meta) - } - - @Test - fun nullableFieldsEmptyArrayBecomesNull() { - val input = """{"title":"hello","meta":[],"other":"hello"}""" - val result = parseJson(input) - assertEquals("hello", result.title) - assertNull(result.meta) - } - - @Test - fun nullableFieldsBothNullAtOnce() { - val input = """{"title":"","meta":[],"other":"hello"}""" - val result = parseJson(input) - assertNull(result.title) - assertNull(result.meta) - } - - @Test - fun nullableFieldsDoesNotAffectOtherFields() { - val input = """{"title":"","meta":[],"other":"world"}""" - val result = parseJson(input) - assertEquals("world", result.other) - } - - @Test - fun nullableFieldsRoundtripsCorrectly() { - val data = NullableFieldsData(title = "hello", meta = NestedMeta("x"), other = "world") - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun singleValueOrEmptyStringWrapsBareString() { - val input = """{"tags":"a","title":"hello"}""" - val result = parseJson(input) - assertEquals(listOf("a"), result.tags) - assertEquals("hello", result.title) - } - - @Test - fun singleValueOrEmptyStringTurnsEmptyTitleToNull() { - val input = """{"tags":["a"],"title":""}""" - val result = parseJson(input) - assertEquals(listOf("a"), result.tags) - assertNull(result.title) - } - - @Test - fun singleValueOrEmptyStringRoundtripsCorrectly() { - val data = SingleValueOrEmptyStringData(tags = listOf("x"), title = "hello") - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun allTransformsWrapsBareStringInList() { - val input = """{"tags":"a","title":"hello","meta":{"key":"value"},"other":"world"}""" - val result = parseJson(input) - assertEquals(listOf("a"), result.tags) - } - - @Test - fun allTransformsEmptyArrayTagsBecomesNull() { - val input = """{"tags":[],"title":"hello","meta":{"key":"value"},"other":"world"}""" - val result = parseJson(input) - assertNull(result.tags) - } - - @Test - fun allTransformsEmptyMetaBecomesNull() { - val input = """{"tags":["a"],"title":"hello","meta":[],"other":"world"}""" - val result = parseJson(input) - assertNull(result.meta) - } - - @Test - fun allTransformsEmptyTitleBecomesNull() { - val input = """{"tags":["a"],"title":"","meta":{"key":"value"},"other":"world"}""" - val result = parseJson(input) - assertNull(result.title) - } - - @Test - fun allTransformsAllNullAtOnce() { - val input = """{"tags":[],"title":"","meta":[],"other":"world"}""" - val result = parseJson(input) - assertNull(result.tags) - assertNull(result.title) - assertNull(result.meta) - } - - @Test - fun allTransformsDoesNotAffectOtherFields() { - val input = """{"tags":[],"title":"","meta":[],"other":"world"}""" - val result = parseJson(input) - assertEquals("world", result.other) - } - - @Test - fun allTransformsRoundtripsCorrectly() { - val data = AllTransformsData(tags = listOf("a"), title = "hello", meta = NestedMeta("x"), other = "world") - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun floatAsIntTruncatesFloat() { - val input = """{"count":3.9}""" - val result = parseJson(input) - assertEquals(3, result.count) - } - - @Test - fun floatAsIntDecodesIntNormally() { - val input = """{"count":42}""" - val result = parseJson(input) - assertEquals(42, result.count) - } - - @Test - fun floatAsIntHandlesNegativeFloat() { - val input = """{"count":-2.7}""" - val result = parseJson(input) - assertEquals(-2, result.count) - } - - @Test - fun floatAsIntRoundtripsCorrectly() { - val data = FloatIntData(count = 7) - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun floatAsLongTruncatesFloat() { - val input = """{"timestamp":1234567890.9}""" - val result = parseJson(input) - assertEquals(1234567890L, result.timestamp) - } - - @Test - fun floatAsLongDecodesLongNormally() { - val input = """{"timestamp":9999999999}""" - val result = parseJson(input) - assertEquals(9999999999L, result.timestamp) - } - - @Test - fun floatAsLongHandlesNegativeFloat() { - val input = """{"timestamp":-100.6}""" - val result = parseJson(input) - assertEquals(-100L, result.timestamp) - } - - @Test - fun floatAsLongRoundtripsCorrectly() { - val data = FloatLongData(timestamp = 1700000000L) - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } - - @Test - fun nullableStringDecodesEmptyStringAsNull() { - val input = """{"title":""}""" - val result = parseJson(input) - assertNull(result.title) - } - - @Test - fun nullableStringDecodesNullAsNull() { - val input = """{"title":null}""" - val result = parseJson(input) - assertNull(result.title) - } - - @Test - fun nullableStringKeepsNonEmptyString() { - val input = """{"title":"hello"}""" - val result = parseJson(input) - assertEquals("hello", result.title) - } - - @Test - fun nullableStringRoundtripsCorrectly() { - val data = NullableStringData(title = "world") - val encoded = data.toJson() - val decoded = parseJson(encoded) - assertEquals(data, decoded) - } -}