ananas/app/src/main/java/dev/jdtech/jellyfin/utils/DownloadUtilities.kt
Michael Arkhangelskiy 786e4d21a0
Add switch to toggle downloads over mobile network (#85)
* Added switch to toggle downloads over mobile network

* Add roaming and mobile data functions
2022-02-19 14:58:46 +01:00

231 lines
No EOL
7.4 KiB
Kotlin

package dev.jdtech.jellyfin.utils
import android.app.DownloadManager
import android.content.Context
import android.net.Uri
import android.os.Environment
import androidx.core.content.getSystemService
import androidx.preference.PreferenceManager
import dev.jdtech.jellyfin.database.DownloadDatabaseDao
import dev.jdtech.jellyfin.models.DownloadItem
import dev.jdtech.jellyfin.models.DownloadRequestItem
import dev.jdtech.jellyfin.models.PlayerItem
import dev.jdtech.jellyfin.repository.JellyfinRepository
import org.jellyfin.sdk.model.api.BaseItemDto
import org.jellyfin.sdk.model.api.UserItemDataDto
import timber.log.Timber
import java.io.File
import java.util.UUID
var defaultStorage: File? = null
fun requestDownload(
downloadDatabase: DownloadDatabaseDao,
uri: Uri,
downloadRequestItem: DownloadRequestItem,
context: Context
) {
val downloadRequest = DownloadManager.Request(uri)
.setTitle(downloadRequestItem.item.name)
.setDescription("Downloading")
.setDestinationUri(
Uri.fromFile(
File(
defaultStorage,
downloadRequestItem.itemId.toString()
)
)
)
.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
try {
downloadDatabase.insertItem(downloadRequestItem.item)
if (!File(defaultStorage, downloadRequestItem.itemId.toString()).exists()) {
val downloadId = downloadFile(downloadRequest, context)
Timber.d("$downloadId")
downloadDatabase.updateDownloadId(downloadRequestItem.itemId, downloadId)
}
} catch (e: Exception) {
Timber.e(e)
}
}
private fun downloadFile(request: DownloadManager.Request, context: Context): Long {
val preferences = PreferenceManager.getDefaultSharedPreferences(context)
val downloadOverData = preferences.getBoolean("download_mobile_data", false)
val downloadWhenRoaming = preferences.getBoolean("download_roaming", false)
request.apply {
setAllowedOverMetered(downloadOverData)
setAllowedOverRoaming(downloadWhenRoaming)
}
return context.getSystemService<DownloadManager>()!!.enqueue(request)
}
fun loadDownloadLocation(context: Context) {
defaultStorage = context.getExternalFilesDir(Environment.DIRECTORY_MOVIES)
}
fun loadDownloadedEpisodes(downloadDatabase: DownloadDatabaseDao): List<PlayerItem> {
val items = downloadDatabase.loadItems()
return items.map {
PlayerItem(
name = it.name,
itemId = it.id,
mediaSourceId = "",
playbackPosition = it.playbackPosition ?: 0,
mediaSourceUri = File(defaultStorage, it.id.toString()).absolutePath,
parentIndexNumber = it.parentIndexNumber,
indexNumber = it.indexNumber,
item = it
)
}
}
fun isItemAvailable(itemId: UUID): Boolean {
return File(defaultStorage, itemId.toString()).exists()
}
fun isItemDownloaded(downloadDatabaseDao: DownloadDatabaseDao, itemId: UUID): Boolean {
val item = downloadDatabaseDao.loadItem(itemId)
return item != null
}
fun getDownloadPlayerItem(downloadDatabase: DownloadDatabaseDao, itemId: UUID): PlayerItem? {
val file = File(defaultStorage!!, itemId.toString())
try {
val metadata = downloadDatabase.loadItem(itemId)
if (metadata != null) {
return PlayerItem(
metadata.name,
UUID.fromString(file.name),
"",
metadata.playbackPosition!!,
file.absolutePath,
metadata.parentIndexNumber,
metadata.indexNumber,
metadata
)
}
} catch (e: Exception) {
file.delete()
Timber.e(e)
}
return null
}
fun deleteDownloadedEpisode(downloadDatabase: DownloadDatabaseDao, itemId: UUID) {
try {
downloadDatabase.deleteItem(itemId)
File(defaultStorage, itemId.toString()).delete()
} catch (e: Exception) {
Timber.e(e)
}
}
fun postDownloadPlaybackProgress(
downloadDatabase: DownloadDatabaseDao,
itemId: UUID,
playbackPosition: Long,
playedPercentage: Double
) {
try {
downloadDatabase.updatePlaybackPosition(itemId, playbackPosition, playedPercentage)
} catch (e: Exception) {
Timber.e(e)
}
}
fun downloadMetadataToBaseItemDto(item: DownloadItem): BaseItemDto {
val userData = UserItemDataDto(
playbackPositionTicks = item.playbackPosition ?: 0,
playedPercentage = item.playedPercentage,
isFavorite = false,
playCount = 0,
played = false
)
return BaseItemDto(
id = item.id,
type = item.type.type,
seriesName = item.seriesName,
name = item.name,
parentIndexNumber = item.parentIndexNumber,
indexNumber = item.indexNumber,
userData = userData,
seriesId = item.seriesId,
overview = item.overview
)
}
fun baseItemDtoToDownloadMetadata(item: BaseItemDto): DownloadItem {
return DownloadItem(
id = item.id,
type = item.contentType(),
name = item.name.orEmpty(),
played = item.userData?.played ?: false,
seriesId = item.seriesId,
seriesName = item.seriesName,
parentIndexNumber = item.parentIndexNumber,
indexNumber = item.indexNumber,
playbackPosition = item.userData?.playbackPositionTicks ?: 0,
playedPercentage = item.userData?.playedPercentage,
overview = item.overview
)
}
suspend fun syncPlaybackProgress(
downloadDatabase: DownloadDatabaseDao,
jellyfinRepository: JellyfinRepository
) {
val items = loadDownloadedEpisodes(downloadDatabase)
items.forEach {
try {
val localPlaybackProgress = it.item?.playbackPosition
val localPlayedPercentage = it.item?.playedPercentage
val item = jellyfinRepository.getItem(it.itemId)
val remotePlaybackProgress = item.userData?.playbackPositionTicks?.div(10000)
val remotePlayedPercentage = item.userData?.playedPercentage
var playbackProgress: Long = 0
var playedPercentage = 0.0
if (it.item?.played == true || item.userData?.played == true) {
return@forEach
}
if (localPlaybackProgress != null) {
if (localPlaybackProgress > playbackProgress) {
playbackProgress = localPlaybackProgress
playedPercentage = localPlayedPercentage!!
}
}
if (remotePlaybackProgress != null) {
if (remotePlaybackProgress > playbackProgress) {
playbackProgress = remotePlaybackProgress
playedPercentage = remotePlayedPercentage!!
}
}
if (playbackProgress != 0L) {
postDownloadPlaybackProgress(
downloadDatabase,
it.itemId,
playbackProgress,
playedPercentage
)
jellyfinRepository.postPlaybackProgress(
it.itemId,
playbackProgress.times(10000),
true
)
Timber.d("Percentage: $playedPercentage")
}
} catch (e: Exception) {
Timber.e(e)
}
}
}