package com.github.libretube.api.obj import android.os.Parcelable import com.github.libretube.db.obj.DownloadItem import com.github.libretube.enums.FileType import com.github.libretube.extensions.toLocalDate import com.github.libretube.json.SafeInstantSerializer import com.github.libretube.parcelable.DownloadData import kotlinx.datetime.Instant import kotlinx.parcelize.IgnoredOnParcel import kotlinx.parcelize.Parcelize import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable @Serializable @Parcelize data class Streams( var title: String, val description: String, @Serializable(SafeInstantSerializer::class) @SerialName("uploadDate") @IgnoredOnParcel val uploadTimestamp: Instant? = null, val uploaded: Long? = null, val uploader: String, val uploaderUrl: String?, val uploaderAvatar: String? = null, var thumbnailUrl: String, val category: String, val license: String = "YouTube licence", val visibility: String = "public", val tags: List = emptyList(), val metaInfo: List = emptyList(), val hls: String? = null, val dash: String? = null, val uploaderVerified: Boolean, val duration: Long, val views: Long = 0, val likes: Long = 0, val dislikes: Long = 0, val audioStreams: List = emptyList(), val videoStreams: List = emptyList(), var relatedStreams: List = emptyList(), val subtitles: List = emptyList(), val livestream: Boolean = false, val proxyUrl: String? = null, val chapters: List = emptyList(), val uploaderSubscriberCount: Long = 0, val previewFrames: List = emptyList(), var isShort: Boolean = false ): Parcelable { @IgnoredOnParcel val isLive = livestream || duration <= 0 fun toDownloadItems(downloadData: DownloadData): List { val (id, videoFormat, videoQuality, audioFormat, audioQuality, audioTrackLocale, subCode) = downloadData val items = mutableListOf() if (!videoQuality.isNullOrEmpty() && !videoFormat.isNullOrEmpty()) { val stream = videoStreams.find { it.quality == videoQuality && it.format == videoFormat } stream?.toDownloadItem(FileType.VIDEO, id)?.let { items.add(it) } } if (!audioQuality.isNullOrEmpty() && !audioFormat.isNullOrEmpty()) { val stream = audioStreams.find { it.quality == audioQuality && it.format == audioFormat && it.audioTrackLocale == audioTrackLocale } ?: audioStreams.find { // Some backends omit/change the locale on a regenerated stream URL. Keep the // selected quality/format instead of silently creating no audio download. it.quality == audioQuality && it.format == audioFormat } stream?.toDownloadItem(FileType.AUDIO, id)?.let { items.add(it) } } if (!subCode.isNullOrEmpty()) { val subtitle = subtitles.find { it.code == subCode } subtitle?.toDownloadItem(id)?.let { items.add(it) } } return items } fun toStreamItem(videoId: String): StreamItem { return StreamItem( url = videoId, title = title, thumbnail = thumbnailUrl, uploaderName = uploader, uploaderUrl = uploaderUrl, uploaderAvatar = uploaderAvatar, uploadedDate = uploadTimestamp?.toLocalDate()?.toString(), uploaded = uploaded ?: uploadTimestamp?.toEpochMilliseconds() ?: 0, duration = duration, views = views, uploaderVerified = uploaderVerified, shortDescription = description ) } companion object { const val CATEGORY_MUSIC = "Music" } }