Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1640,11 +1640,11 @@ object VideoDownloadManager {
}

fun getDownloadResumePackage(context: Context, id: Int): DownloadResumePackage? {
return context.getKey(KEY_RESUME_PACKAGES, id.toString())
return context.getKey<DownloadResumePackage>(KEY_RESUME_PACKAGES, id.toString())
}

fun getDownloadQueuePackage(context: Context, id: Int): DownloadQueueWrapper? {
return context.getKey(KEY_RESUME_IN_QUEUE, id.toString())
return context.getKey<DownloadQueueWrapper>(KEY_RESUME_IN_QUEUE, id.toString())
}

fun getDownloadEpisodeMetadata(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
package com.lagradost.cloudstream3.utils.downloader

import android.net.Uri
import com.fasterxml.jackson.annotation.JsonIgnore
import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.Score
import com.lagradost.cloudstream3.SkipSerializationTest
import com.lagradost.cloudstream3.TvType
import com.lagradost.cloudstream3.services.DownloadQueueService
import com.lagradost.cloudstream3.ui.player.SubtitleData
import com.lagradost.cloudstream3.ui.result.ResultEpisode
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.serializers.UriSerializer
import com.lagradost.cloudstream3.utils.serializers.WriteOnlySerializer
import com.lagradost.safefile.SafeFile
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.KeepGeneratedSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import java.io.IOException
import java.io.OutputStream
import java.util.Objects

object DownloadObjects {
/** An item can either be something to resume or something new to start */
@Serializable
data class DownloadQueueWrapper(
@JsonProperty("resumePackage") val resumePackage: DownloadResumePackage?,
@JsonProperty("downloadItem") val downloadItem: DownloadQueueItem?,
@JsonProperty("resumePackage") @SerialName("resumePackage") val resumePackage: DownloadResumePackage?,
@JsonProperty("downloadItem") @SerialName("downloadItem") val downloadItem: DownloadQueueItem?,
) {
init {
assert(resumePackage != null || downloadItem != null) {
Expand All @@ -26,56 +35,66 @@ object DownloadObjects {
}

/** Loop through the current download instances to see if it is currently downloading. Also includes link loading. */
@JsonIgnore
fun isCurrentlyDownloading(): Boolean {
return DownloadQueueService.downloadInstances.value.any { it.downloadQueueWrapper.id == this.id }
}

@JsonProperty("id")
@JsonProperty("id") @SerialName("id")
val id = resumePackage?.item?.ep?.id ?: downloadItem!!.episode.id

@JsonProperty("parentId")
@JsonProperty("parentId") @SerialName("parentId")
val parentId = resumePackage?.item?.ep?.parentId ?: downloadItem!!.episode.parentId
}

/** General data about the episode and show to start a download from. */
@Serializable
data class DownloadQueueItem(
@JsonProperty("episode") val episode: ResultEpisode,
@JsonProperty("isMovie") val isMovie: Boolean,
@JsonProperty("resultName") val resultName: String,
@JsonProperty("resultType") val resultType: TvType,
@JsonProperty("resultPoster") val resultPoster: String?,
@JsonProperty("apiName") val apiName: String,
@JsonProperty("resultId") val resultId: Int,
@JsonProperty("resultUrl") val resultUrl: String,
@JsonProperty("links") val links: List<ExtractorLink>? = null,
@JsonProperty("subs") val subs: List<SubtitleData>? = null,
@JsonProperty("episode") @SerialName("episode") val episode: ResultEpisode,
@JsonProperty("isMovie") @SerialName("isMovie") val isMovie: Boolean,
@JsonProperty("resultName") @SerialName("resultName") val resultName: String,
@JsonProperty("resultType") @SerialName("resultType") val resultType: TvType,
@JsonProperty("resultPoster") @SerialName("resultPoster") val resultPoster: String?,
@JsonProperty("apiName") @SerialName("apiName") val apiName: String,
@JsonProperty("resultId") @SerialName("resultId") val resultId: Int,
@JsonProperty("resultUrl") @SerialName("resultUrl") val resultUrl: String,
@JsonProperty("links") @SerialName("links") val links: List<ExtractorLink>? = null,
@JsonProperty("subs") @SerialName("subs") val subs: List<SubtitleData>? = null,
) {
fun toWrapper(): DownloadQueueWrapper {
return DownloadQueueWrapper(null, this)
}
}

interface DownloadCached {
val id: Int
}

abstract class DownloadCached(
@JsonProperty("id") open val id: Int,
)

@OptIn(ExperimentalSerializationApi::class) // KeepGeneratedSerializer is an experimental annotation for now
@KeepGeneratedSerializer
@Serializable(with = DownloadEpisodeCached.Serializer::class)
data class DownloadEpisodeCached(
@JsonProperty("name") val name: String?,
@JsonProperty("poster") val poster: String?,
@JsonProperty("episode") val episode: Int,
@JsonProperty("season") val season: Int?,
@JsonProperty("parentId") val parentId: Int,
@JsonProperty("score") var score: Score? = null,
@JsonProperty("description") val description: String?,
@JsonProperty("cacheTime") val cacheTime: Long,
override val id: Int,
) : DownloadCached(id) {
@JsonProperty("name") @SerialName("name") val name: String?,
@JsonProperty("poster") @SerialName("poster") val poster: String?,
@JsonProperty("episode") @SerialName("episode") val episode: Int,
@JsonProperty("season") @SerialName("season") val season: Int?,
@JsonProperty("parentId") @SerialName("parentId") val parentId: Int,
@JsonProperty("score") @SerialName("score") var score: Score? = null,
@JsonProperty("description") @SerialName("description") val description: String?,
@JsonProperty("cacheTime") @SerialName("cacheTime") val cacheTime: Long,
@JsonProperty("id") @SerialName("id") override val id: Int,
) : DownloadCached {
object Serializer : WriteOnlySerializer<DownloadEpisodeCached>(
DownloadEpisodeCached.generatedSerializer(),
setOf("rating"),
)

@JsonProperty("rating", access = JsonProperty.Access.WRITE_ONLY)
@SerialName("rating")
@Deprecated(
"`rating` is the old scoring system, use score instead",
replaceWith = ReplaceWith("score"),
level = DeprecationLevel.ERROR
level = DeprecationLevel.ERROR,
)
var rating: Int? = null
set(value) {
Expand All @@ -87,74 +106,81 @@ object DownloadObjects {
}

/** What to display to the user for a downloaded show/movie. Includes info such as name, poster and url */
@Serializable
data class DownloadHeaderCached(
@JsonProperty("apiName") val apiName: String,
@JsonProperty("url") val url: String,
@JsonProperty("type") val type: TvType,
@JsonProperty("name") val name: String,
@JsonProperty("poster") val poster: String?,
@JsonProperty("cacheTime") val cacheTime: Long,
override val id: Int,
) : DownloadCached(id)

@JsonProperty("apiName") @SerialName("apiName") val apiName: String,
@JsonProperty("url") @SerialName("url") val url: String,
@JsonProperty("type") @SerialName("type") val type: TvType,
@JsonProperty("name") @SerialName("name") val name: String,
@JsonProperty("poster") @SerialName("poster") val poster: String?,
@JsonProperty("cacheTime") @SerialName("cacheTime") val cacheTime: Long,
@JsonProperty("id") @SerialName("id") override val id: Int,
) : DownloadCached

@Serializable
data class DownloadResumePackage(
@JsonProperty("item") val item: DownloadItem,
@JsonProperty("item") @SerialName("item") val item: DownloadItem,
/** Tills which link should get resumed */
@JsonProperty("linkIndex") val linkIndex: Int?,
@JsonProperty("linkIndex") @SerialName("linkIndex") val linkIndex: Int?,
) {
fun toWrapper(): DownloadQueueWrapper {
return DownloadQueueWrapper(this, null)
}
}

@Serializable
data class DownloadItem(
@JsonProperty("source") val source: String?,
@JsonProperty("folder") val folder: String?,
@JsonProperty("ep") val ep: DownloadEpisodeMetadata,
@JsonProperty("links") val links: List<ExtractorLink>,
@JsonProperty("source") @SerialName("source") val source: String?,
@JsonProperty("folder") @SerialName("folder") val folder: String?,
@JsonProperty("ep") @SerialName("ep") val ep: DownloadEpisodeMetadata,
@JsonProperty("links") @SerialName("links") val links: List<ExtractorLink>,
)

/** Metadata for a specific episode and how to display it. */
@Serializable
data class DownloadEpisodeMetadata(
@JsonProperty("id") val id: Int,
@JsonProperty("parentId") val parentId: Int,
@JsonProperty("mainName") val mainName: String,
@JsonProperty("sourceApiName") val sourceApiName: String?,
@JsonProperty("poster") val poster: String?,
@JsonProperty("name") val name: String?,
@JsonProperty("season") val season: Int?,
@JsonProperty("episode") val episode: Int?,
@JsonProperty("type") val type: TvType?,
@JsonProperty("id") @SerialName("id") val id: Int,
@JsonProperty("parentId") @SerialName("parentId") val parentId: Int,
@JsonProperty("mainName") @SerialName("mainName") val mainName: String,
@JsonProperty("sourceApiName") @SerialName("sourceApiName") val sourceApiName: String?,
@JsonProperty("poster") @SerialName("poster") val poster: String?,
@JsonProperty("name") @SerialName("name") val name: String?,
@JsonProperty("season") @SerialName("season") val season: Int?,
@JsonProperty("episode") @SerialName("episode") val episode: Int?,
@JsonProperty("type") @SerialName("type") val type: TvType?,
)


@Serializable
data class DownloadedFileInfo(
@JsonProperty("totalBytes") val totalBytes: Long,
@JsonProperty("relativePath") val relativePath: String,
@JsonProperty("displayName") val displayName: String,
@JsonProperty("extraInfo") val extraInfo: String? = null,
@JsonProperty("basePath") val basePath: String? = null, // null is for legacy downloads. See getBasePath()
@JsonProperty("totalBytes") @SerialName("totalBytes") val totalBytes: Long,
@JsonProperty("relativePath") @SerialName("relativePath") val relativePath: String,
@JsonProperty("displayName") @SerialName("displayName") val displayName: String,
@JsonProperty("extraInfo") @SerialName("extraInfo") val extraInfo: String? = null,
@JsonProperty("basePath") @SerialName("basePath") val basePath: String? = null, // null is for legacy downloads. See getBasePath()
// Hash of the link associated with this DownloadFile, used so not override old data in the DownloadedFileInfo
@JsonProperty("linkHash") val linkHash : Int? = null
@JsonProperty("linkHash") @SerialName("linkHash") val linkHash: Int? = null,
)

@Serializable
@SkipSerializationTest // Uri has issues with Jackson
data class DownloadedFileInfoResult(
@JsonProperty("fileLength") val fileLength: Long,
@JsonProperty("totalBytes") val totalBytes: Long,
@JsonProperty("path") val path: Uri,
@JsonProperty("fileLength") @SerialName("fileLength") val fileLength: Long,
@JsonProperty("totalBytes") @SerialName("totalBytes") val totalBytes: Long,
@JsonProperty("path") @SerialName("path")
@Serializable(with = UriSerializer::class)
val path: Uri,
)


@Serializable
data class ResumeWatching(
@JsonProperty("parentId") val parentId: Int,
@JsonProperty("episodeId") val episodeId: Int?,
@JsonProperty("episode") val episode: Int?,
@JsonProperty("season") val season: Int?,
@JsonProperty("updateTime") val updateTime: Long,
@JsonProperty("isFromDownload") val isFromDownload: Boolean,
@JsonProperty("parentId") @SerialName("parentId") val parentId: Int,
@JsonProperty("episodeId") @SerialName("episodeId") val episodeId: Int?,
@JsonProperty("episode") @SerialName("episode") val episode: Int?,
@JsonProperty("season") @SerialName("season") val season: Int?,
@JsonProperty("updateTime") @SerialName("updateTime") val updateTime: Long,
@JsonProperty("isFromDownload") @SerialName("isFromDownload") val isFromDownload: Boolean,
)


data class DownloadStatus(
/** if you should retry with the same args and hope for a better result */
val retrySame: Boolean,
Expand All @@ -164,20 +190,19 @@ object DownloadObjects {
val success: Boolean,
)


data class CreateNotificationMetadata(
val type: VideoDownloadManager.DownloadType,
val bytesDownloaded: Long,
val bytesTotal: Long,
val hlsProgress: Long? = null,
val hlsTotal: Long? = null,
val bytesPerSecond: Long
val bytesPerSecond: Long,
)

data class StreamData(
private val fileLength: Long,
val file: SafeFile,
//val fileStream: OutputStream,
// val fileStream: OutputStream,
) {
@Throws(IOException::class)
fun open(): OutputStream {
Expand All @@ -198,9 +223,11 @@ object DownloadObjects {
val exists: Boolean get() = file.exists() == true
}


/** bytes have the size end-start where the byte range is [start,end)
* note that ByteArray is a pointer and therefore cant be stored without cloning it */
/**
* Bytes have the size end-start where the byte range is [start,end)
* note that ByteArray is a pointer and therefore can't be stored
* without cloning it.
*/
data class LazyStreamDownloadResponse(
val bytes: ByteArray,
val startByte: Long,
Expand All @@ -221,4 +248,4 @@ object DownloadObjects {
return Objects.hash(startByte, endByte)
}
}
}
}
Loading