From 35bb94ff51bda30d0e931cece2ac6c69cbf431c5 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Thu, 4 Jun 2026 14:19:05 -0600 Subject: [PATCH 1/2] Torrent: migrate to kotlinx serialization --- .../cloudstream3/ui/player/Torrent.kt | 96 ++++++++++--------- 1 file changed, 50 insertions(+), 46 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt index 2e554f75eaf..66a496295da 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt @@ -1,6 +1,5 @@ package com.lagradost.cloudstream3.ui.player -import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.api.Log import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.ErrorLoadingException @@ -9,6 +8,8 @@ import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLinkType import com.lagradost.cloudstream3.utils.newExtractorLink +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import torrServer.TorrServer import java.io.File import java.net.ConnectException @@ -278,93 +279,95 @@ object Torrent { // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/torrents.go#L18 // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/main/web/api/route.go#L7 + @Serializable data class TorrentRequest( - @JsonProperty("action") + @SerialName("action") val action: String, - @JsonProperty("hash") + @SerialName("hash") val hash: String = "", - @JsonProperty("link") + @SerialName("link") val link: String = "", - @JsonProperty("title") + @SerialName("title") val title: String = "", - @JsonProperty("poster") + @SerialName("poster") val poster: String = "", - @JsonProperty("data") + @SerialName("data") val data: String = "", - @JsonProperty("save_to_db") + @SerialName("save_to_db") val saveToDB: Boolean = false, ) // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/torr/state/state.go#L33 // omitempty = nullable + @Serializable data class TorrentStatus( - @JsonProperty("title") + @SerialName("title") var title: String, - @JsonProperty("poster") + @SerialName("poster") var poster: String, - @JsonProperty("data") + @SerialName("data") var data: String?, - @JsonProperty("timestamp") + @SerialName("timestamp") var timestamp: Long, - @JsonProperty("name") + @SerialName("name") var name: String?, - @JsonProperty("hash") + @SerialName("hash") var hash: String?, - @JsonProperty("stat") + @SerialName("stat") var stat: Int, - @JsonProperty("stat_string") + @SerialName("stat_string") var statString: String, - @JsonProperty("loaded_size") + @SerialName("loaded_size") var loadedSize: Long?, - @JsonProperty("torrent_size") + @SerialName("torrent_size") var torrentSize: Long?, - @JsonProperty("preloaded_bytes") + @SerialName("preloaded_bytes") var preloadedBytes: Long?, - @JsonProperty("preload_size") + @SerialName("preload_size") var preloadSize: Long?, - @JsonProperty("download_speed") + @SerialName("download_speed") var downloadSpeed: Double?, - @JsonProperty("upload_speed") + @SerialName("upload_speed") var uploadSpeed: Double?, - @JsonProperty("total_peers") + @SerialName("total_peers") var totalPeers: Int?, - @JsonProperty("pending_peers") + @SerialName("pending_peers") var pendingPeers: Int?, - @JsonProperty("active_peers") + @SerialName("active_peers") var activePeers: Int?, - @JsonProperty("connected_seeders") + @SerialName("connected_seeders") var connectedSeeders: Int?, - @JsonProperty("half_open_peers") + @SerialName("half_open_peers") var halfOpenPeers: Int?, - @JsonProperty("bytes_written") + @SerialName("bytes_written") var bytesWritten: Long?, - @JsonProperty("bytes_written_data") + @SerialName("bytes_written_data") var bytesWrittenData: Long?, - @JsonProperty("bytes_read") + @SerialName("bytes_read") var bytesRead: Long?, - @JsonProperty("bytes_read_data") + @SerialName("bytes_read_data") var bytesReadData: Long?, - @JsonProperty("bytes_read_useful_data") + @SerialName("bytes_read_useful_data") var bytesReadUsefulData: Long?, - @JsonProperty("chunks_written") + @SerialName("chunks_written") var chunksWritten: Long?, - @JsonProperty("chunks_read") + @SerialName("chunks_read") var chunksRead: Long?, - @JsonProperty("chunks_read_useful") + @SerialName("chunks_read_useful") var chunksReadUseful: Long?, - @JsonProperty("chunks_read_wasted") + @SerialName("chunks_read_wasted") var chunksReadWasted: Long?, - @JsonProperty("pieces_dirtied_good") + @SerialName("pieces_dirtied_good") var piecesDirtiedGood: Long?, - @JsonProperty("pieces_dirtied_bad") + @SerialName("pieces_dirtied_bad") var piecesDirtiedBad: Long?, - @JsonProperty("duration_seconds") + @SerialName("duration_seconds") var durationSeconds: Double?, - @JsonProperty("bit_rate") + @SerialName("bit_rate") var bitRate: String?, - @JsonProperty("file_stats") + @SerialName("file_stats") var fileStats: List?, - @JsonProperty("trackers") + @SerialName("trackers") var trackers: List?, ) { fun streamUrl(url: String): String { @@ -381,12 +384,13 @@ object Torrent { } } + @Serializable data class TorrentFileStat( - @JsonProperty("id") + @SerialName("id") val id: Int?, - @JsonProperty("path") + @SerialName("path") val path: String?, - @JsonProperty("length") + @SerialName("length") val length: Long?, ) -} \ No newline at end of file +} From 95d41470c4b497d6fad559b236afe6c81e25e5b2 Mon Sep 17 00:00:00 2001 From: Luna712 <142361265+Luna712@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:19:25 -0600 Subject: [PATCH 2/2] Keep JsonProperty where different than variable name --- .../cloudstream3/ui/player/Torrent.kt | 157 +++++++----------- 1 file changed, 56 insertions(+), 101 deletions(-) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt index 66a496295da..f4706c1cdc8 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/player/Torrent.kt @@ -1,5 +1,6 @@ package com.lagradost.cloudstream3.ui.player +import com.fasterxml.jackson.annotation.JsonProperty import com.lagradost.api.Log import com.lagradost.cloudstream3.CommonActivity import com.lagradost.cloudstream3.ErrorLoadingException @@ -33,14 +34,14 @@ object Torrent { /** Returns true if the server is up */ private suspend fun echo(): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { app.get( "$TORRENT_SERVER_URL/echo", ).text.isNotEmpty() - } catch (e: ConnectException) { + } catch (_: ConnectException) { // `Failed to connect to /127.0.0.1:8090` if the server is down false } catch (t: Throwable) { @@ -53,7 +54,7 @@ object Torrent { /** Gracefully shutdown the server. * should not be used because I am unable to start it again, and the stopTorrentServer() crashes the app */ suspend fun shutdown(): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { @@ -69,7 +70,7 @@ object Torrent { /** Lists all torrents by the server */ @Throws private suspend fun list(): Array { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { throw ErrorLoadingException("Not initialized") } return app.post( @@ -84,7 +85,7 @@ object Torrent { /** Drops a single torrent, (I think) this means closing the stream. Returns returns if it is successful */ private suspend fun drop(hash: String): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { @@ -105,7 +106,7 @@ object Torrent { /** Removes a single torrent from the server registry */ private suspend fun rem(hash: String): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return false } return try { @@ -127,7 +128,7 @@ object Torrent { /** Removes all torrents from the server, and returns if it is successful */ suspend fun clearAll(): Boolean { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { return true } return try { @@ -165,10 +166,8 @@ object Torrent { /** Gets all the metadata of a torrent, will throw if that hash does not exists * https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/web/api/torrents.go#L126 */ @Throws - suspend fun get( - hash: String, - ): TorrentStatus { - if(TORRENT_SERVER_URL.isEmpty()) { + suspend fun get(hash: String): TorrentStatus { + if (TORRENT_SERVER_URL.isEmpty()) { throw ErrorLoadingException("Not initialized") } return app.post( @@ -185,7 +184,7 @@ object Torrent { /** Adds a torrent to the server, this is needed for us to get the hash for further modification, as well as start streaming it*/ @Throws private suspend fun add(url: String): TorrentStatus { - if(TORRENT_SERVER_URL.isEmpty()) { + if (TORRENT_SERVER_URL.isEmpty()) { throw ErrorLoadingException("Not initialized") } return app.post( @@ -205,7 +204,7 @@ object Torrent { return true } val port = TorrServer.startTorrentServer(dir, 0) - if(port < 0) { + if (port < 0) { return false } TORRENT_SERVER_URL = "http://127.0.0.1:$port" @@ -281,94 +280,53 @@ object Torrent { // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/main/web/api/route.go#L7 @Serializable data class TorrentRequest( - @SerialName("action") - val action: String, - @SerialName("hash") - val hash: String = "", - @SerialName("link") - val link: String = "", - @SerialName("title") - val title: String = "", - @SerialName("poster") - val poster: String = "", - @SerialName("data") - val data: String = "", - @SerialName("save_to_db") - val saveToDB: Boolean = false, + @SerialName("action") val action: String, + @SerialName("hash") val hash: String = "", + @SerialName("link") val link: String = "", + @SerialName("title") val title: String = "", + @SerialName("poster") val poster: String = "", + @SerialName("data") val data: String = "", + @JsonProperty("save_to_db") @SerialName("save_to_db") val saveToDB: Boolean = false, ) // https://github.com/Diegopyl1209/torrentserver-aniyomi/blob/c18f58e51b6738f053261bc863177078aa9c1c98/torr/state/state.go#L33 // omitempty = nullable @Serializable data class TorrentStatus( - @SerialName("title") - var title: String, - @SerialName("poster") - var poster: String, - @SerialName("data") - var data: String?, - @SerialName("timestamp") - var timestamp: Long, - @SerialName("name") - var name: String?, - @SerialName("hash") - var hash: String?, - @SerialName("stat") - var stat: Int, - @SerialName("stat_string") - var statString: String, - @SerialName("loaded_size") - var loadedSize: Long?, - @SerialName("torrent_size") - var torrentSize: Long?, - @SerialName("preloaded_bytes") - var preloadedBytes: Long?, - @SerialName("preload_size") - var preloadSize: Long?, - @SerialName("download_speed") - var downloadSpeed: Double?, - @SerialName("upload_speed") - var uploadSpeed: Double?, - @SerialName("total_peers") - var totalPeers: Int?, - @SerialName("pending_peers") - var pendingPeers: Int?, - @SerialName("active_peers") - var activePeers: Int?, - @SerialName("connected_seeders") - var connectedSeeders: Int?, - @SerialName("half_open_peers") - var halfOpenPeers: Int?, - @SerialName("bytes_written") - var bytesWritten: Long?, - @SerialName("bytes_written_data") - var bytesWrittenData: Long?, - @SerialName("bytes_read") - var bytesRead: Long?, - @SerialName("bytes_read_data") - var bytesReadData: Long?, - @SerialName("bytes_read_useful_data") - var bytesReadUsefulData: Long?, - @SerialName("chunks_written") - var chunksWritten: Long?, - @SerialName("chunks_read") - var chunksRead: Long?, - @SerialName("chunks_read_useful") - var chunksReadUseful: Long?, - @SerialName("chunks_read_wasted") - var chunksReadWasted: Long?, - @SerialName("pieces_dirtied_good") - var piecesDirtiedGood: Long?, - @SerialName("pieces_dirtied_bad") - var piecesDirtiedBad: Long?, - @SerialName("duration_seconds") - var durationSeconds: Double?, - @SerialName("bit_rate") - var bitRate: String?, - @SerialName("file_stats") - var fileStats: List?, - @SerialName("trackers") - var trackers: List?, + @SerialName("title") var title: String, + @SerialName("poster") var poster: String, + @SerialName("data") var data: String?, + @SerialName("timestamp") var timestamp: Long, + @SerialName("name") var name: String?, + @SerialName("hash") var hash: String?, + @SerialName("stat") var stat: Int, + @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?, + @SerialName("trackers") var trackers: List?, ) { fun streamUrl(url: String): String { val fileName = @@ -386,11 +344,8 @@ object Torrent { @Serializable data class TorrentFileStat( - @SerialName("id") - val id: Int?, - @SerialName("path") - val path: String?, - @SerialName("length") - val length: Long?, + @SerialName("id") val id: Int?, + @SerialName("path") val path: String?, + @SerialName("length") val length: Long?, ) }