mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-20 01:28:57 +02:00
Autoformatting files
This commit is contained in:
parent
9492975a74
commit
b2ebeafed5
6 changed files with 1411 additions and 893 deletions
|
|
@ -12,6 +12,7 @@ import com.audiobookshelf.app.BuildConfig
|
||||||
import com.audiobookshelf.app.R
|
import com.audiobookshelf.app.R
|
||||||
import com.audiobookshelf.app.device.DeviceManager
|
import com.audiobookshelf.app.device.DeviceManager
|
||||||
import com.audiobookshelf.app.media.MediaProgressSyncData
|
import com.audiobookshelf.app.media.MediaProgressSyncData
|
||||||
|
import com.audiobookshelf.app.player.*
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties
|
||||||
import com.google.android.exoplayer2.MediaItem
|
import com.google.android.exoplayer2.MediaItem
|
||||||
|
|
@ -19,7 +20,6 @@ import com.google.android.exoplayer2.MediaMetadata
|
||||||
import com.google.android.gms.cast.MediaInfo
|
import com.google.android.gms.cast.MediaInfo
|
||||||
import com.google.android.gms.cast.MediaQueueItem
|
import com.google.android.gms.cast.MediaQueueItem
|
||||||
import com.google.android.gms.common.images.WebImage
|
import com.google.android.gms.common.images.WebImage
|
||||||
import com.audiobookshelf.app.player.*
|
|
||||||
|
|
||||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||||
class PlaybackSession(
|
class PlaybackSession(
|
||||||
|
|
@ -50,27 +50,42 @@ class PlaybackSession(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val isHLS get() = playMethod == PLAYMETHOD_TRANSCODE
|
val isHLS
|
||||||
|
get() = playMethod == PLAYMETHOD_TRANSCODE
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val isDirectPlay get() = playMethod == PLAYMETHOD_DIRECTPLAY
|
val isDirectPlay
|
||||||
|
get() = playMethod == PLAYMETHOD_DIRECTPLAY
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val isLocal get() = playMethod == PLAYMETHOD_LOCAL
|
val isLocal
|
||||||
|
get() = playMethod == PLAYMETHOD_LOCAL
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val isPodcastEpisode get() = mediaType == "podcast"
|
val isPodcastEpisode
|
||||||
|
get() = mediaType == "podcast"
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val currentTimeMs get() = (currentTime * 1000L).toLong()
|
val currentTimeMs
|
||||||
|
get() = (currentTime * 1000L).toLong()
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val totalDurationMs get() = (getTotalDuration() * 1000L).toLong()
|
val totalDurationMs
|
||||||
|
get() = (getTotalDuration() * 1000L).toLong()
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val localLibraryItemId get() = localLibraryItem?.id ?: ""
|
val localLibraryItemId
|
||||||
|
get() = localLibraryItem?.id ?: ""
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val localMediaProgressId get() = if (localEpisodeId.isNullOrEmpty()) localLibraryItemId else "$localLibraryItemId-$localEpisodeId"
|
val localMediaProgressId
|
||||||
|
get() =
|
||||||
|
if (localEpisodeId.isNullOrEmpty()) localLibraryItemId
|
||||||
|
else "$localLibraryItemId-$localEpisodeId"
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val progress get() = currentTime / getTotalDuration()
|
val progress
|
||||||
|
get() = currentTime / getTotalDuration()
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val isLocalLibraryItemOnly get() = localLibraryItemId != "" && libraryItemId == null
|
val isLocalLibraryItemOnly
|
||||||
|
get() = localLibraryItemId != "" && libraryItemId == null
|
||||||
@get:JsonIgnore
|
@get:JsonIgnore
|
||||||
val mediaItemId get() = if (isLocalLibraryItemOnly) localMediaProgressId else if (episodeId.isNullOrEmpty()) libraryItemId ?: "" else "$libraryItemId-$episodeId"
|
val mediaItemId
|
||||||
|
get() =
|
||||||
|
if (isLocalLibraryItemOnly) localMediaProgressId
|
||||||
|
else if (episodeId.isNullOrEmpty()) libraryItemId ?: "" else "$libraryItemId-$episodeId"
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
fun getCurrentTrackIndex(): Int {
|
fun getCurrentTrackIndex(): Int {
|
||||||
|
|
@ -144,13 +159,20 @@ class PlaybackSession(
|
||||||
if (localLibraryItem?.coverContentUrl != null) {
|
if (localLibraryItem?.coverContentUrl != null) {
|
||||||
var coverUri = Uri.parse(localLibraryItem?.coverContentUrl.toString())
|
var coverUri = Uri.parse(localLibraryItem?.coverContentUrl.toString())
|
||||||
if (coverUri.toString().startsWith("file:")) {
|
if (coverUri.toString().startsWith("file:")) {
|
||||||
coverUri = FileProvider.getUriForFile(ctx, "${BuildConfig.APPLICATION_ID}.fileprovider", coverUri.toFile())
|
coverUri =
|
||||||
|
FileProvider.getUriForFile(
|
||||||
|
ctx,
|
||||||
|
"${BuildConfig.APPLICATION_ID}.fileprovider",
|
||||||
|
coverUri.toFile()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return coverUri ?: Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon)
|
return coverUri
|
||||||
|
?: Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (coverPath == null) return Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon)
|
if (coverPath == null)
|
||||||
|
return Uri.parse("android.resource://${BuildConfig.APPLICATION_ID}/" + R.drawable.icon)
|
||||||
return Uri.parse("$serverAddress/api/items/$libraryItemId/cover?token=${DeviceManager.token}")
|
return Uri.parse("$serverAddress/api/items/$libraryItemId/cover?token=${DeviceManager.token}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -164,7 +186,8 @@ class PlaybackSession(
|
||||||
fun getMediaMetadataCompat(ctx: Context): MediaMetadataCompat {
|
fun getMediaMetadataCompat(ctx: Context): MediaMetadataCompat {
|
||||||
val coverUri = getCoverUri(ctx)
|
val coverUri = getCoverUri(ctx)
|
||||||
|
|
||||||
val metadataBuilder = MediaMetadataCompat.Builder()
|
val metadataBuilder =
|
||||||
|
MediaMetadataCompat.Builder()
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, displayTitle)
|
.putString(MediaMetadataCompat.METADATA_KEY_TITLE, displayTitle)
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, displayTitle)
|
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, displayTitle)
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, displayAuthor)
|
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_SUBTITLE, displayAuthor)
|
||||||
|
|
@ -176,14 +199,19 @@ class PlaybackSession(
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id)
|
.putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, id)
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, coverUri.toString())
|
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, coverUri.toString())
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, coverUri.toString())
|
.putString(MediaMetadataCompat.METADATA_KEY_ART_URI, coverUri.toString())
|
||||||
.putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI, coverUri.toString())
|
.putString(
|
||||||
|
MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON_URI,
|
||||||
|
coverUri.toString()
|
||||||
|
)
|
||||||
|
|
||||||
// Local covers get bitmap
|
// Local covers get bitmap
|
||||||
if (localLibraryItem?.coverContentUrl != null) {
|
if (localLibraryItem?.coverContentUrl != null) {
|
||||||
val bitmap = if (Build.VERSION.SDK_INT < 28) {
|
val bitmap =
|
||||||
|
if (Build.VERSION.SDK_INT < 28) {
|
||||||
MediaStore.Images.Media.getBitmap(ctx.contentResolver, coverUri)
|
MediaStore.Images.Media.getBitmap(ctx.contentResolver, coverUri)
|
||||||
} else {
|
} else {
|
||||||
val source: ImageDecoder.Source = ImageDecoder.createSource(ctx.contentResolver, coverUri)
|
val source: ImageDecoder.Source =
|
||||||
|
ImageDecoder.createSource(ctx.contentResolver, coverUri)
|
||||||
ImageDecoder.decodeBitmap(source)
|
ImageDecoder.decodeBitmap(source)
|
||||||
}
|
}
|
||||||
metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
|
metadataBuilder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
|
||||||
|
|
@ -197,7 +225,8 @@ class PlaybackSession(
|
||||||
fun getExoMediaMetadata(ctx: Context): MediaMetadata {
|
fun getExoMediaMetadata(ctx: Context): MediaMetadata {
|
||||||
val coverUri = getCoverUri(ctx)
|
val coverUri = getCoverUri(ctx)
|
||||||
|
|
||||||
val metadataBuilder = MediaMetadata.Builder()
|
val metadataBuilder =
|
||||||
|
MediaMetadata.Builder()
|
||||||
.setTitle(displayTitle)
|
.setTitle(displayTitle)
|
||||||
.setDisplayTitle(displayTitle)
|
.setDisplayTitle(displayTitle)
|
||||||
.setArtist(displayAuthor)
|
.setArtist(displayAuthor)
|
||||||
|
|
@ -221,7 +250,13 @@ class PlaybackSession(
|
||||||
val mimeType = audioTrack.mimeType
|
val mimeType = audioTrack.mimeType
|
||||||
|
|
||||||
val queueItem = getQueueItem(audioTrack) // Queue item used in exo player CastManager
|
val queueItem = getQueueItem(audioTrack) // Queue item used in exo player CastManager
|
||||||
val mediaItem = MediaItem.Builder().setUri(mediaUri).setTag(queueItem).setMediaMetadata(mediaMetadata).setMimeType(mimeType).build()
|
val mediaItem =
|
||||||
|
MediaItem.Builder()
|
||||||
|
.setUri(mediaUri)
|
||||||
|
.setTag(queueItem)
|
||||||
|
.setMediaMetadata(mediaMetadata)
|
||||||
|
.setMimeType(mimeType)
|
||||||
|
.build()
|
||||||
mediaItems.add(mediaItem)
|
mediaItems.add(mediaItem)
|
||||||
}
|
}
|
||||||
return mediaItems
|
return mediaItems
|
||||||
|
|
@ -229,18 +264,39 @@ class PlaybackSession(
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
fun getCastMediaMetadata(audioTrack: AudioTrack): com.google.android.gms.cast.MediaMetadata {
|
fun getCastMediaMetadata(audioTrack: AudioTrack): com.google.android.gms.cast.MediaMetadata {
|
||||||
val castMetadata = com.google.android.gms.cast.MediaMetadata(com.google.android.gms.cast.MediaMetadata.MEDIA_TYPE_AUDIOBOOK_CHAPTER)
|
val castMetadata =
|
||||||
|
com.google.android.gms.cast.MediaMetadata(
|
||||||
|
com.google.android.gms.cast.MediaMetadata.MEDIA_TYPE_AUDIOBOOK_CHAPTER
|
||||||
|
)
|
||||||
|
|
||||||
coverPath?.let {
|
coverPath?.let {
|
||||||
castMetadata.addImage(WebImage(Uri.parse("$serverAddress/api/items/$libraryItemId/cover?token=${DeviceManager.token}")))
|
castMetadata.addImage(
|
||||||
|
WebImage(
|
||||||
|
Uri.parse(
|
||||||
|
"$serverAddress/api/items/$libraryItemId/cover?token=${DeviceManager.token}"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
castMetadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_TITLE, displayTitle ?: "")
|
castMetadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_TITLE, displayTitle ?: "")
|
||||||
castMetadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_ARTIST, displayAuthor ?: "")
|
castMetadata.putString(
|
||||||
castMetadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_ALBUM_TITLE, displayAuthor ?: "")
|
com.google.android.gms.cast.MediaMetadata.KEY_ARTIST,
|
||||||
castMetadata.putString(com.google.android.gms.cast.MediaMetadata.KEY_CHAPTER_TITLE, audioTrack.title)
|
displayAuthor ?: ""
|
||||||
|
)
|
||||||
|
castMetadata.putString(
|
||||||
|
com.google.android.gms.cast.MediaMetadata.KEY_ALBUM_TITLE,
|
||||||
|
displayAuthor ?: ""
|
||||||
|
)
|
||||||
|
castMetadata.putString(
|
||||||
|
com.google.android.gms.cast.MediaMetadata.KEY_CHAPTER_TITLE,
|
||||||
|
audioTrack.title
|
||||||
|
)
|
||||||
|
|
||||||
castMetadata.putInt(com.google.android.gms.cast.MediaMetadata.KEY_TRACK_NUMBER, audioTrack.index)
|
castMetadata.putInt(
|
||||||
|
com.google.android.gms.cast.MediaMetadata.KEY_TRACK_NUMBER,
|
||||||
|
audioTrack.index
|
||||||
|
)
|
||||||
return castMetadata
|
return castMetadata
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -250,21 +306,49 @@ class PlaybackSession(
|
||||||
|
|
||||||
val mediaUri = getContentUri(audioTrack)
|
val mediaUri = getContentUri(audioTrack)
|
||||||
|
|
||||||
val mediaInfo = MediaInfo.Builder(mediaUri.toString()).apply {
|
val mediaInfo =
|
||||||
|
MediaInfo.Builder(mediaUri.toString())
|
||||||
|
.apply {
|
||||||
setContentUrl(mediaUri.toString())
|
setContentUrl(mediaUri.toString())
|
||||||
setContentType(audioTrack.mimeType)
|
setContentType(audioTrack.mimeType)
|
||||||
setMetadata(castMetadata)
|
setMetadata(castMetadata)
|
||||||
setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||||
}.build()
|
}
|
||||||
|
.build()
|
||||||
|
|
||||||
return MediaQueueItem.Builder(mediaInfo).apply {
|
return MediaQueueItem.Builder(mediaInfo)
|
||||||
setPlaybackDuration(audioTrack.duration)
|
.apply { setPlaybackDuration(audioTrack.duration) }
|
||||||
}.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
fun clone(): PlaybackSession {
|
fun clone(): PlaybackSession {
|
||||||
return PlaybackSession(id,userId,libraryItemId,episodeId,mediaType,mediaMetadata,deviceInfo,chapters,displayTitle,displayAuthor,coverPath,duration,playMethod,startedAt,updatedAt,timeListening,audioTracks,currentTime,libraryItem,localLibraryItem,localEpisodeId,serverConnectionConfigId,serverAddress, mediaPlayer)
|
return PlaybackSession(
|
||||||
|
id,
|
||||||
|
userId,
|
||||||
|
libraryItemId,
|
||||||
|
episodeId,
|
||||||
|
mediaType,
|
||||||
|
mediaMetadata,
|
||||||
|
deviceInfo,
|
||||||
|
chapters,
|
||||||
|
displayTitle,
|
||||||
|
displayAuthor,
|
||||||
|
coverPath,
|
||||||
|
duration,
|
||||||
|
playMethod,
|
||||||
|
startedAt,
|
||||||
|
updatedAt,
|
||||||
|
timeListening,
|
||||||
|
audioTracks,
|
||||||
|
currentTime,
|
||||||
|
libraryItem,
|
||||||
|
localLibraryItem,
|
||||||
|
localEpisodeId,
|
||||||
|
serverConnectionConfigId,
|
||||||
|
serverAddress,
|
||||||
|
mediaPlayer
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
|
|
@ -276,6 +360,24 @@ class PlaybackSession(
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
fun getNewLocalMediaProgress(): LocalMediaProgress {
|
fun getNewLocalMediaProgress(): LocalMediaProgress {
|
||||||
return LocalMediaProgress(localMediaProgressId,localLibraryItemId,localEpisodeId,getTotalDuration(),progress,currentTime,false,null,null,updatedAt,startedAt,null,serverConnectionConfigId,serverAddress,userId,libraryItemId,episodeId)
|
return LocalMediaProgress(
|
||||||
|
localMediaProgressId,
|
||||||
|
localLibraryItemId,
|
||||||
|
localEpisodeId,
|
||||||
|
getTotalDuration(),
|
||||||
|
progress,
|
||||||
|
currentTime,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
updatedAt,
|
||||||
|
startedAt,
|
||||||
|
null,
|
||||||
|
serverConnectionConfigId,
|
||||||
|
serverAddress,
|
||||||
|
userId,
|
||||||
|
libraryItemId,
|
||||||
|
episodeId
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,8 @@ class DbManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDeviceData(): DeviceData {
|
fun getDeviceData(): DeviceData {
|
||||||
return Paper.book("device").read("data") ?: DeviceData(mutableListOf(), null, DeviceSettings.default(), null)
|
return Paper.book("device").read("data")
|
||||||
|
?: DeviceData(mutableListOf(), null, DeviceSettings.default(), null)
|
||||||
}
|
}
|
||||||
fun saveDeviceData(deviceData: DeviceData) {
|
fun saveDeviceData(deviceData: DeviceData) {
|
||||||
Paper.book("device").write("data", deviceData)
|
Paper.book("device").write("data", deviceData)
|
||||||
|
|
@ -32,7 +33,9 @@ class DbManager {
|
||||||
val localLibraryItems: MutableList<LocalLibraryItem> = mutableListOf()
|
val localLibraryItems: MutableList<LocalLibraryItem> = mutableListOf()
|
||||||
Paper.book("localLibraryItems").allKeys.forEach {
|
Paper.book("localLibraryItems").allKeys.forEach {
|
||||||
val localLibraryItem: LocalLibraryItem? = Paper.book("localLibraryItems").read(it)
|
val localLibraryItem: LocalLibraryItem? = Paper.book("localLibraryItems").read(it)
|
||||||
if (localLibraryItem != null && (mediaType.isNullOrEmpty() || mediaType == localLibraryItem.mediaType)) {
|
if (localLibraryItem != null &&
|
||||||
|
(mediaType.isNullOrEmpty() || mediaType == localLibraryItem.mediaType)
|
||||||
|
) {
|
||||||
localLibraryItems.add(localLibraryItem)
|
localLibraryItems.add(localLibraryItem)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -41,9 +44,7 @@ class DbManager {
|
||||||
|
|
||||||
fun getLocalLibraryItemsInFolder(folderId: String): List<LocalLibraryItem> {
|
fun getLocalLibraryItemsInFolder(folderId: String): List<LocalLibraryItem> {
|
||||||
val localLibraryItems = getLocalLibraryItems()
|
val localLibraryItems = getLocalLibraryItems()
|
||||||
return localLibraryItems.filter {
|
return localLibraryItems.filter { it.folderId == folderId }
|
||||||
it.folderId == folderId
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLocalLibraryItemByLId(libraryItemId: String): LocalLibraryItem? {
|
fun getLocalLibraryItemByLId(libraryItemId: String): LocalLibraryItem? {
|
||||||
|
|
@ -56,7 +57,8 @@ class DbManager {
|
||||||
|
|
||||||
fun getLocalLibraryItemWithEpisode(podcastEpisodeId: String): LibraryItemWithEpisode? {
|
fun getLocalLibraryItemWithEpisode(podcastEpisodeId: String): LibraryItemWithEpisode? {
|
||||||
var podcastEpisode: PodcastEpisode? = null
|
var podcastEpisode: PodcastEpisode? = null
|
||||||
val localLibraryItem = getLocalLibraryItems("podcast").find { localLibraryItem ->
|
val localLibraryItem =
|
||||||
|
getLocalLibraryItems("podcast").find { localLibraryItem ->
|
||||||
val podcast = localLibraryItem.media as Podcast
|
val podcast = localLibraryItem.media as Podcast
|
||||||
podcastEpisode = podcast.episodes?.find { it.id == podcastEpisodeId }
|
podcastEpisode = podcast.episodes?.find { it.id == podcastEpisodeId }
|
||||||
podcastEpisode != null
|
podcastEpisode != null
|
||||||
|
|
@ -73,9 +75,7 @@ class DbManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveLocalLibraryItems(localLibraryItems: List<LocalLibraryItem>) {
|
fun saveLocalLibraryItems(localLibraryItems: List<LocalLibraryItem>) {
|
||||||
localLibraryItems.map {
|
localLibraryItems.map { Paper.book("localLibraryItems").write(it.id, it) }
|
||||||
Paper.book("localLibraryItems").write(it.id, it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun saveLocalLibraryItem(localLibraryItem: LocalLibraryItem) {
|
fun saveLocalLibraryItem(localLibraryItem: LocalLibraryItem) {
|
||||||
|
|
@ -93,18 +93,14 @@ class DbManager {
|
||||||
fun getAllLocalFolders(): List<LocalFolder> {
|
fun getAllLocalFolders(): List<LocalFolder> {
|
||||||
val localFolders: MutableList<LocalFolder> = mutableListOf()
|
val localFolders: MutableList<LocalFolder> = mutableListOf()
|
||||||
Paper.book("localFolders").allKeys.forEach { localFolderId ->
|
Paper.book("localFolders").allKeys.forEach { localFolderId ->
|
||||||
Paper.book("localFolders").read<LocalFolder>(localFolderId)?.let {
|
Paper.book("localFolders").read<LocalFolder>(localFolderId)?.let { localFolders.add(it) }
|
||||||
localFolders.add(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return localFolders
|
return localFolders
|
||||||
}
|
}
|
||||||
|
|
||||||
fun removeLocalFolder(folderId: String) {
|
fun removeLocalFolder(folderId: String) {
|
||||||
val localLibraryItems = getLocalLibraryItemsInFolder(folderId)
|
val localLibraryItems = getLocalLibraryItemsInFolder(folderId)
|
||||||
localLibraryItems.forEach {
|
localLibraryItems.forEach { Paper.book("localLibraryItems").delete(it.id) }
|
||||||
Paper.book("localLibraryItems").delete(it.id)
|
|
||||||
}
|
|
||||||
Paper.book("localFolders").delete(folderId)
|
Paper.book("localFolders").delete(folderId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,9 +115,7 @@ class DbManager {
|
||||||
fun getDownloadItems(): List<DownloadItem> {
|
fun getDownloadItems(): List<DownloadItem> {
|
||||||
val downloadItems: MutableList<DownloadItem> = mutableListOf()
|
val downloadItems: MutableList<DownloadItem> = mutableListOf()
|
||||||
Paper.book("downloadItems").allKeys.forEach { downloadItemId ->
|
Paper.book("downloadItems").allKeys.forEach { downloadItemId ->
|
||||||
Paper.book("downloadItems").read<DownloadItem>(downloadItemId)?.let {
|
Paper.book("downloadItems").read<DownloadItem>(downloadItemId)?.let { downloadItems.add(it) }
|
||||||
downloadItems.add(it)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return downloadItems
|
return downloadItems
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +123,8 @@ class DbManager {
|
||||||
fun saveLocalMediaProgress(mediaProgress: LocalMediaProgress) {
|
fun saveLocalMediaProgress(mediaProgress: LocalMediaProgress) {
|
||||||
Paper.book("localMediaProgress").write(mediaProgress.id, mediaProgress)
|
Paper.book("localMediaProgress").write(mediaProgress.id, mediaProgress)
|
||||||
}
|
}
|
||||||
// For books this will just be the localLibraryItemId for podcast episodes this will be "{localLibraryItemId}-{episodeId}"
|
// For books this will just be the localLibraryItemId for podcast episodes this will be
|
||||||
|
// "{localLibraryItemId}-{episodeId}"
|
||||||
fun getLocalMediaProgress(localMediaProgressId: String): LocalMediaProgress? {
|
fun getLocalMediaProgress(localMediaProgressId: String): LocalMediaProgress? {
|
||||||
return Paper.book("localMediaProgress").read(localMediaProgressId)
|
return Paper.book("localMediaProgress").read(localMediaProgressId)
|
||||||
}
|
}
|
||||||
|
|
@ -158,35 +153,50 @@ class DbManager {
|
||||||
var hasUpdates = false
|
var hasUpdates = false
|
||||||
|
|
||||||
// Check local files
|
// Check local files
|
||||||
lli.localFiles = lli.localFiles.filter { localFile ->
|
lli.localFiles =
|
||||||
|
lli.localFiles.filter { localFile ->
|
||||||
val file = File(localFile.absolutePath)
|
val file = File(localFile.absolutePath)
|
||||||
if (!file.exists()) {
|
if (!file.exists()) {
|
||||||
Log.d(tag, "cleanLocalLibraryItems: Local file ${localFile.absolutePath} was removed from library item ${lli.media.metadata.title}")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalLibraryItems: Local file ${localFile.absolutePath} was removed from library item ${lli.media.metadata.title}"
|
||||||
|
)
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
file.exists()
|
file.exists()
|
||||||
} as MutableList<LocalFile>
|
} as
|
||||||
|
MutableList<LocalFile>
|
||||||
|
|
||||||
// Check audio tracks and episodes
|
// Check audio tracks and episodes
|
||||||
if (lli.isPodcast) {
|
if (lli.isPodcast) {
|
||||||
val podcast = lli.media as Podcast
|
val podcast = lli.media as Podcast
|
||||||
podcast.episodes = podcast.episodes?.filter { ep ->
|
podcast.episodes =
|
||||||
|
podcast.episodes?.filter { ep ->
|
||||||
if (lli.localFiles.find { lf -> lf.id == ep.audioTrack?.localFileId } == null) {
|
if (lli.localFiles.find { lf -> lf.id == ep.audioTrack?.localFileId } == null) {
|
||||||
Log.d(tag, "cleanLocalLibraryItems: Podcast episode ${ep.title} was removed from library item ${lli.media.metadata.title}")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalLibraryItems: Podcast episode ${ep.title} was removed from library item ${lli.media.metadata.title}"
|
||||||
|
)
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
ep.audioTrack != null && lli.localFiles.find { lf -> lf.id == ep.audioTrack?.localFileId } != null
|
ep.audioTrack != null &&
|
||||||
} as MutableList<PodcastEpisode>
|
lli.localFiles.find { lf -> lf.id == ep.audioTrack?.localFileId } != null
|
||||||
|
} as
|
||||||
|
MutableList<PodcastEpisode>
|
||||||
} else {
|
} else {
|
||||||
val book = lli.media as Book
|
val book = lli.media as Book
|
||||||
book.tracks = book.tracks?.filter { track ->
|
book.tracks =
|
||||||
|
book.tracks?.filter { track ->
|
||||||
if (lli.localFiles.find { lf -> lf.id == track.localFileId } == null) {
|
if (lli.localFiles.find { lf -> lf.id == track.localFileId } == null) {
|
||||||
Log.d(tag, "cleanLocalLibraryItems: Audio track ${track.title} was removed from library item ${lli.media.metadata.title}")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalLibraryItems: Audio track ${track.title} was removed from library item ${lli.media.metadata.title}"
|
||||||
|
)
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
}
|
}
|
||||||
lli.localFiles.find { lf -> lf.id == track.localFileId } != null
|
lli.localFiles.find { lf -> lf.id == track.localFileId } != null
|
||||||
} as MutableList<AudioTrack>
|
} as
|
||||||
|
MutableList<AudioTrack>
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check cover still there
|
// Check cover still there
|
||||||
|
|
@ -194,7 +204,10 @@ class DbManager {
|
||||||
val coverFile = File(it)
|
val coverFile = File(it)
|
||||||
|
|
||||||
if (!coverFile.exists()) {
|
if (!coverFile.exists()) {
|
||||||
Log.d(tag, "cleanLocalLibraryItems: Cover $it was removed from library item ${lli.media.metadata.title}")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalLibraryItems: Cover $it was removed from library item ${lli.media.metadata.title}"
|
||||||
|
)
|
||||||
lli.coverAbsolutePath = null
|
lli.coverAbsolutePath = null
|
||||||
lli.coverContentUrl = null
|
lli.coverContentUrl = null
|
||||||
hasUpdates = true
|
hasUpdates = true
|
||||||
|
|
@ -215,11 +228,18 @@ class DbManager {
|
||||||
localMediaProgress.forEach {
|
localMediaProgress.forEach {
|
||||||
val matchingLLI = localLibraryItems.find { lli -> lli.id == it.localLibraryItemId }
|
val matchingLLI = localLibraryItems.find { lli -> lli.id == it.localLibraryItemId }
|
||||||
if (!it.id.startsWith("local")) {
|
if (!it.id.startsWith("local")) {
|
||||||
// A bug on the server when syncing local media progress was replacing the media progress id causing duplicate progress. Remove them.
|
// A bug on the server when syncing local media progress was replacing the media progress id
|
||||||
Log.d(tag, "cleanLocalMediaProgress: Invalid local media progress does not start with 'local' (fixed on server 2.0.24)")
|
// causing duplicate progress. Remove them.
|
||||||
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalMediaProgress: Invalid local media progress does not start with 'local' (fixed on server 2.0.24)"
|
||||||
|
)
|
||||||
Paper.book("localMediaProgress").delete(it.id)
|
Paper.book("localMediaProgress").delete(it.id)
|
||||||
} else if (matchingLLI == null) {
|
} else if (matchingLLI == null) {
|
||||||
Log.d(tag, "cleanLocalMediaProgress: No matching local library item for local media progress ${it.id} - removing")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalMediaProgress: No matching local library item for local media progress ${it.id} - removing"
|
||||||
|
)
|
||||||
Paper.book("localMediaProgress").delete(it.id)
|
Paper.book("localMediaProgress").delete(it.id)
|
||||||
} else if (matchingLLI.isPodcast) {
|
} else if (matchingLLI.isPodcast) {
|
||||||
if (it.localEpisodeId.isNullOrEmpty()) {
|
if (it.localEpisodeId.isNullOrEmpty()) {
|
||||||
|
|
@ -229,7 +249,10 @@ class DbManager {
|
||||||
val podcast = matchingLLI.media as Podcast
|
val podcast = matchingLLI.media as Podcast
|
||||||
val matchingLEp = podcast.episodes?.find { ep -> ep.id == it.localEpisodeId }
|
val matchingLEp = podcast.episodes?.find { ep -> ep.id == it.localEpisodeId }
|
||||||
if (matchingLEp == null) {
|
if (matchingLEp == null) {
|
||||||
Log.d(tag, "cleanLocalMediaProgress: Podcast media progress for episode ${it.localEpisodeId} not found - removing")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"cleanLocalMediaProgress: Podcast media progress for episode ${it.localEpisodeId} not found - removing"
|
||||||
|
)
|
||||||
Paper.book("localMediaProgress").delete(it.id)
|
Paper.book("localMediaProgress").delete(it.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,23 +36,37 @@ object MediaEventManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun seekEvent(playbackSession: PlaybackSession, syncResult: SyncResult?) {
|
fun seekEvent(playbackSession: PlaybackSession, syncResult: SyncResult?) {
|
||||||
Log.i(tag, "Seek Event for media \"${playbackSession.displayTitle}\", currentTime=${playbackSession.currentTime}")
|
Log.i(
|
||||||
|
tag,
|
||||||
|
"Seek Event for media \"${playbackSession.displayTitle}\", currentTime=${playbackSession.currentTime}"
|
||||||
|
)
|
||||||
addPlaybackEvent("Seek", playbackSession, syncResult)
|
addPlaybackEvent("Seek", playbackSession, syncResult)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun syncEvent(mediaProgress: MediaProgressWrapper, description: String) {
|
fun syncEvent(mediaProgress: MediaProgressWrapper, description: String) {
|
||||||
Log.i(tag, "Sync Event for media item id \"${mediaProgress.mediaItemId}\", currentTime=${mediaProgress.currentTime}")
|
Log.i(
|
||||||
|
tag,
|
||||||
|
"Sync Event for media item id \"${mediaProgress.mediaItemId}\", currentTime=${mediaProgress.currentTime}"
|
||||||
|
)
|
||||||
addSyncEvent("Sync", mediaProgress, description)
|
addSyncEvent("Sync", mediaProgress, description)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addSyncEvent(eventName:String, mediaProgress:MediaProgressWrapper, description: String) {
|
private fun addSyncEvent(
|
||||||
|
eventName: String,
|
||||||
|
mediaProgress: MediaProgressWrapper,
|
||||||
|
description: String
|
||||||
|
) {
|
||||||
val mediaItemHistory = getMediaItemHistoryMediaItem(mediaProgress.mediaItemId)
|
val mediaItemHistory = getMediaItemHistoryMediaItem(mediaProgress.mediaItemId)
|
||||||
if (mediaItemHistory == null) {
|
if (mediaItemHistory == null) {
|
||||||
Log.w(tag, "addSyncEvent: Media Item History not created yet for media item id ${mediaProgress.mediaItemId}")
|
Log.w(
|
||||||
|
tag,
|
||||||
|
"addSyncEvent: Media Item History not created yet for media item id ${mediaProgress.mediaItemId}"
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val mediaItemEvent = MediaItemEvent(
|
val mediaItemEvent =
|
||||||
|
MediaItemEvent(
|
||||||
name = eventName,
|
name = eventName,
|
||||||
type = "Sync",
|
type = "Sync",
|
||||||
description = description,
|
description = description,
|
||||||
|
|
@ -68,10 +82,17 @@ object MediaEventManager {
|
||||||
clientEventEmitter?.onMediaItemHistoryUpdated(mediaItemHistory)
|
clientEventEmitter?.onMediaItemHistoryUpdated(mediaItemHistory)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addPlaybackEvent(eventName:String, playbackSession:PlaybackSession, syncResult: SyncResult?) {
|
private fun addPlaybackEvent(
|
||||||
val mediaItemHistory = getMediaItemHistoryMediaItem(playbackSession.mediaItemId) ?: createMediaItemHistoryForSession(playbackSession)
|
eventName: String,
|
||||||
|
playbackSession: PlaybackSession,
|
||||||
|
syncResult: SyncResult?
|
||||||
|
) {
|
||||||
|
val mediaItemHistory =
|
||||||
|
getMediaItemHistoryMediaItem(playbackSession.mediaItemId)
|
||||||
|
?: createMediaItemHistoryForSession(playbackSession)
|
||||||
|
|
||||||
val mediaItemEvent = MediaItemEvent(
|
val mediaItemEvent =
|
||||||
|
MediaItemEvent(
|
||||||
name = eventName,
|
name = eventName,
|
||||||
type = "Playback",
|
type = "Playback",
|
||||||
description = "",
|
description = "",
|
||||||
|
|
@ -94,8 +115,13 @@ object MediaEventManager {
|
||||||
private fun createMediaItemHistoryForSession(playbackSession: PlaybackSession): MediaItemHistory {
|
private fun createMediaItemHistoryForSession(playbackSession: PlaybackSession): MediaItemHistory {
|
||||||
Log.i(tag, "Creating new media item history for media \"${playbackSession.displayTitle}\"")
|
Log.i(tag, "Creating new media item history for media \"${playbackSession.displayTitle}\"")
|
||||||
val isLocalOnly = playbackSession.isLocalLibraryItemOnly
|
val isLocalOnly = playbackSession.isLocalLibraryItemOnly
|
||||||
val libraryItemId = if (isLocalOnly) playbackSession.localLibraryItemId else playbackSession.libraryItemId ?: ""
|
val libraryItemId =
|
||||||
val episodeId:String? = if (isLocalOnly && playbackSession.localEpisodeId != null) playbackSession.localEpisodeId else playbackSession.episodeId
|
if (isLocalOnly) playbackSession.localLibraryItemId
|
||||||
|
else playbackSession.libraryItemId ?: ""
|
||||||
|
val episodeId: String? =
|
||||||
|
if (isLocalOnly && playbackSession.localEpisodeId != null)
|
||||||
|
playbackSession.localEpisodeId
|
||||||
|
else playbackSession.episodeId
|
||||||
return MediaItemHistory(
|
return MediaItemHistory(
|
||||||
id = playbackSession.mediaItemId,
|
id = playbackSession.mediaItemId,
|
||||||
mediaDisplayTitle = playbackSession.displayTitle ?: "Unset",
|
mediaDisplayTitle = playbackSession.displayTitle ?: "Unset",
|
||||||
|
|
@ -106,6 +132,7 @@ object MediaEventManager {
|
||||||
playbackSession.serverAddress,
|
playbackSession.serverAddress,
|
||||||
playbackSession.userId,
|
playbackSession.userId,
|
||||||
createdAt = System.currentTimeMillis(),
|
createdAt = System.currentTimeMillis(),
|
||||||
events = mutableListOf())
|
events = mutableListOf()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,10 @@ data class SyncResult(
|
||||||
var serverSyncMessage: String?
|
var serverSyncMessage: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
class MediaProgressSyncer(val playerNotificationService: PlayerNotificationService, private val apiHandler: ApiHandler) {
|
class MediaProgressSyncer(
|
||||||
|
val playerNotificationService: PlayerNotificationService,
|
||||||
|
private val apiHandler: ApiHandler
|
||||||
|
) {
|
||||||
private val tag = "MediaProgressSync"
|
private val tag = "MediaProgressSync"
|
||||||
private val METERED_CONNECTION_SYNC_INTERVAL = 60000
|
private val METERED_CONNECTION_SYNC_INTERVAL = 60000
|
||||||
|
|
||||||
|
|
@ -37,10 +40,14 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
var currentPlaybackSession: PlaybackSession? = null // copy of pb session currently syncing
|
var currentPlaybackSession: PlaybackSession? = null // copy of pb session currently syncing
|
||||||
var currentLocalMediaProgress: LocalMediaProgress? = null
|
var currentLocalMediaProgress: LocalMediaProgress? = null
|
||||||
|
|
||||||
private val currentDisplayTitle get() = currentPlaybackSession?.displayTitle ?: "Unset"
|
private val currentDisplayTitle
|
||||||
val currentIsLocal get() = currentPlaybackSession?.isLocal == true
|
get() = currentPlaybackSession?.displayTitle ?: "Unset"
|
||||||
val currentSessionId get() = currentPlaybackSession?.id ?: ""
|
val currentIsLocal
|
||||||
private val currentPlaybackDuration get() = currentPlaybackSession?.duration ?: 0.0
|
get() = currentPlaybackSession?.isLocal == true
|
||||||
|
val currentSessionId
|
||||||
|
get() = currentPlaybackSession?.id ?: ""
|
||||||
|
private val currentPlaybackDuration
|
||||||
|
get() = currentPlaybackSession?.duration ?: 0.0
|
||||||
|
|
||||||
fun start(playbackSession: PlaybackSession) {
|
fun start(playbackSession: PlaybackSession) {
|
||||||
if (listeningTimerRunning) {
|
if (listeningTimerRunning) {
|
||||||
|
|
@ -62,16 +69,24 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
listeningTimerRunning = true
|
listeningTimerRunning = true
|
||||||
lastSyncTime = System.currentTimeMillis()
|
lastSyncTime = System.currentTimeMillis()
|
||||||
currentPlaybackSession = playbackSession.clone()
|
currentPlaybackSession = playbackSession.clone()
|
||||||
Log.d(tag, "start: init last sync time $lastSyncTime with playback session id=${currentPlaybackSession?.id}")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"start: init last sync time $lastSyncTime with playback session id=${currentPlaybackSession?.id}"
|
||||||
|
)
|
||||||
|
|
||||||
listeningTimerTask = Timer("ListeningTimer", false).schedule(15000L, 15000L) {
|
listeningTimerTask =
|
||||||
|
Timer("ListeningTimer", false).schedule(15000L, 15000L) {
|
||||||
Handler(Looper.getMainLooper()).post() {
|
Handler(Looper.getMainLooper()).post() {
|
||||||
if (playerNotificationService.currentPlayer.isPlaying) {
|
if (playerNotificationService.currentPlayer.isPlaying) {
|
||||||
// Set auto sleep timer if enabled and within start/end time
|
// Set auto sleep timer if enabled and within start/end time
|
||||||
playerNotificationService.sleepTimerManager.checkAutoSleepTimer()
|
playerNotificationService.sleepTimerManager.checkAutoSleepTimer()
|
||||||
|
|
||||||
// Only sync with server on unmetered connection every 15s OR sync with server if last sync time is >= 60s
|
// Only sync with server on unmetered connection every 15s OR sync with server if
|
||||||
val shouldSyncServer = PlayerNotificationService.isUnmeteredNetwork || System.currentTimeMillis() - lastSyncTime >= METERED_CONNECTION_SYNC_INTERVAL
|
// last sync time is >= 60s
|
||||||
|
val shouldSyncServer =
|
||||||
|
PlayerNotificationService.isUnmeteredNetwork ||
|
||||||
|
System.currentTimeMillis() - lastSyncTime >=
|
||||||
|
METERED_CONNECTION_SYNC_INTERVAL
|
||||||
|
|
||||||
val currentTime = playerNotificationService.getCurrentTimeSeconds()
|
val currentTime = playerNotificationService.getCurrentTimeSeconds()
|
||||||
if (currentTime > 0) {
|
if (currentTime > 0) {
|
||||||
|
|
@ -106,7 +121,8 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
listeningTimerRunning = false
|
listeningTimerRunning = false
|
||||||
Log.d(tag, "stop: Stopping listening for $currentDisplayTitle")
|
Log.d(tag, "stop: Stopping listening for $currentDisplayTitle")
|
||||||
|
|
||||||
val currentTime = if (shouldSync == true) playerNotificationService.getCurrentTimeSeconds() else 0.0
|
val currentTime =
|
||||||
|
if (shouldSync == true) playerNotificationService.getCurrentTimeSeconds() else 0.0
|
||||||
if (currentTime > 0) { // Current time should always be > 0 on stop
|
if (currentTime > 0) { // Current time should always be > 0 on stop
|
||||||
sync(true, currentTime) { syncResult ->
|
sync(true, currentTime) { syncResult ->
|
||||||
currentPlaybackSession?.let { playbackSession ->
|
currentPlaybackSession?.let { playbackSession ->
|
||||||
|
|
@ -197,7 +213,10 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
it.updatedAt = mediaProgress.lastUpdate
|
it.updatedAt = mediaProgress.lastUpdate
|
||||||
it.currentTime = mediaProgress.currentTime
|
it.currentTime = mediaProgress.currentTime
|
||||||
|
|
||||||
MediaEventManager.syncEvent(mediaProgress, "Received from server get media progress request while playback session open")
|
MediaEventManager.syncEvent(
|
||||||
|
mediaProgress,
|
||||||
|
"Received from server get media progress request while playback session open"
|
||||||
|
)
|
||||||
saveLocalProgress(it)
|
saveLocalProgress(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -218,7 +237,10 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
currentPlaybackSession?.syncData(syncData)
|
currentPlaybackSession?.syncData(syncData)
|
||||||
|
|
||||||
if (currentPlaybackSession?.progress?.isNaN() == true) {
|
if (currentPlaybackSession?.progress?.isNaN() == true) {
|
||||||
Log.e(tag, "Current Playback Session invalid progress ${currentPlaybackSession?.progress} | Current Time: ${currentPlaybackSession?.currentTime} | Duration: ${currentPlaybackSession?.getTotalDuration()}")
|
Log.e(
|
||||||
|
tag,
|
||||||
|
"Current Playback Session invalid progress ${currentPlaybackSession?.progress} | Current Time: ${currentPlaybackSession?.currentTime} | Duration: ${currentPlaybackSession?.getTotalDuration()}"
|
||||||
|
)
|
||||||
return cb(null)
|
return cb(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -238,11 +260,20 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
saveLocalProgress(it)
|
saveLocalProgress(it)
|
||||||
lastSyncTime = System.currentTimeMillis()
|
lastSyncTime = System.currentTimeMillis()
|
||||||
|
|
||||||
Log.d(tag, "Sync local device current serverConnectionConfigId=${DeviceManager.serverConnectionConfig?.id}")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"Sync local device current serverConnectionConfigId=${DeviceManager.serverConnectionConfig?.id}"
|
||||||
|
)
|
||||||
|
|
||||||
// Local library item is linked to a server library item
|
// Local library item is linked to a server library item
|
||||||
// Send sync to server also if connected to this server and local item belongs to this server
|
// Send sync to server also if connected to this server and local item belongs to this
|
||||||
if (hasNetworkConnection && shouldSyncServer && !it.libraryItemId.isNullOrEmpty() && it.serverConnectionConfigId != null && DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId) {
|
// server
|
||||||
|
if (hasNetworkConnection &&
|
||||||
|
shouldSyncServer &&
|
||||||
|
!it.libraryItemId.isNullOrEmpty() &&
|
||||||
|
it.serverConnectionConfigId != null &&
|
||||||
|
DeviceManager.serverConnectionConfig?.id == it.serverConnectionConfigId
|
||||||
|
) {
|
||||||
apiHandler.sendLocalProgressSync(it) { syncSuccess, errorMsg ->
|
apiHandler.sendLocalProgressSync(it) { syncSuccess, errorMsg ->
|
||||||
if (syncSuccess) {
|
if (syncSuccess) {
|
||||||
failedSyncs = 0
|
failedSyncs = 0
|
||||||
|
|
@ -254,7 +285,10 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
playerNotificationService.alertSyncFailing() // Show alert in client
|
playerNotificationService.alertSyncFailing() // Show alert in client
|
||||||
failedSyncs = 0
|
failedSyncs = 0
|
||||||
}
|
}
|
||||||
Log.e(tag, "Local Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime with session id=${it.id}")
|
Log.e(
|
||||||
|
tag,
|
||||||
|
"Local Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime with session id=${it.id}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
cb(SyncResult(true, syncSuccess, errorMsg))
|
cb(SyncResult(true, syncSuccess, errorMsg))
|
||||||
|
|
@ -278,7 +312,10 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
playerNotificationService.alertSyncFailing() // Show alert in client
|
playerNotificationService.alertSyncFailing() // Show alert in client
|
||||||
failedSyncs = 0
|
failedSyncs = 0
|
||||||
}
|
}
|
||||||
Log.e(tag, "Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime with session id=${currentSessionId}")
|
Log.e(
|
||||||
|
tag,
|
||||||
|
"Progress sync failed ($failedSyncs) to send to server $currentDisplayTitle for time $currentTime with session id=${currentSessionId}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
cb(SyncResult(true, syncSuccess, errorMsg))
|
cb(SyncResult(true, syncSuccess, errorMsg))
|
||||||
}
|
}
|
||||||
|
|
@ -289,7 +326,8 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
|
|
||||||
private fun saveLocalProgress(playbackSession: PlaybackSession) {
|
private fun saveLocalProgress(playbackSession: PlaybackSession) {
|
||||||
if (currentLocalMediaProgress == null) {
|
if (currentLocalMediaProgress == null) {
|
||||||
val mediaProgress = DeviceManager.dbManager.getLocalMediaProgress(playbackSession.localMediaProgressId)
|
val mediaProgress =
|
||||||
|
DeviceManager.dbManager.getLocalMediaProgress(playbackSession.localMediaProgressId)
|
||||||
if (mediaProgress == null) {
|
if (mediaProgress == null) {
|
||||||
currentLocalMediaProgress = playbackSession.getNewLocalMediaProgress()
|
currentLocalMediaProgress = playbackSession.getNewLocalMediaProgress()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -306,12 +344,14 @@ class MediaProgressSyncer(val playerNotificationService: PlayerNotificationServi
|
||||||
} else {
|
} else {
|
||||||
DeviceManager.dbManager.saveLocalMediaProgress(it)
|
DeviceManager.dbManager.saveLocalMediaProgress(it)
|
||||||
playerNotificationService.clientEventEmitter?.onLocalMediaProgressUpdate(it)
|
playerNotificationService.clientEventEmitter?.onLocalMediaProgressUpdate(it)
|
||||||
Log.d(tag, "Saved Local Progress Current Time: ID ${it.id} | ${it.currentTime} | Duration ${it.duration} | Progress ${it.progressPercent}%")
|
Log.d(
|
||||||
|
tag,
|
||||||
|
"Saved Local Progress Current Time: ID ${it.id} | ${it.currentTime} | Duration ${it.duration} | Progress ${it.progressPercent}%"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun reset() {
|
fun reset() {
|
||||||
currentPlaybackSession = null
|
currentPlaybackSession = null
|
||||||
currentLocalMediaProgress = null
|
currentLocalMediaProgress = null
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue