[Android] Tv: update next thumbnail after generation

Duncan McNamara git at videolan.org
Mon Dec 6 10:05:26 UTC 2021


vlc-android | branch: master | Duncan McNamara <dcn.mcnamara at gmail.com> | Fri Dec  3 18:17:54 2021 +0100| [b41ae2e5a88d1528ceab04d3f3285d4e98a3379e] | committer: Nicolas Pomepuy

Tv: update next thumbnail after generation

In some cases thumbnail generation can take some time, for a samba file
for example. This will update the thumbnail for the next channel once
the medialibrary calls the onMediaThumbnailReady callback, and the media
has a thumbnail generated.

> https://code.videolan.org/videolan/vlc-android/commit/b41ae2e5a88d1528ceab04d3f3285d4e98a3379e
---

 .../src/org/videolan/vlc/media/PlaylistManager.kt  |  6 +++-
 .../src/org/videolan/vlc/util/TvChannels.kt        | 38 ++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt b/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
index 5b0ab1e8d..f5fd77768 100644
--- a/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
+++ b/application/vlc-android/src/org/videolan/vlc/media/PlaylistManager.kt
@@ -289,6 +289,7 @@ class PlaylistManager(val service: PlaybackService) : MediaWrapperList.EventList
                 saveMediaMeta().join()
                 if (AndroidDevices.isAndroidTv && AndroidUtil.isOOrLater && video) {
                     setResumeProgram(service.applicationContext, it)
+                    updateNextProgramAfterThumbnailGeneration(service, service.applicationContext, it)
                 }
             }
         }
@@ -955,7 +956,10 @@ class PlaylistManager(val service: PlaybackService) : MediaWrapperList.EventList
                         if (isBenchmark) player.setCurrentStats()
                         determinePrevAndNextIndices(true)
                         if (!hasNext()) getCurrentMedia()?.let {
-                            if (AndroidDevices.isAndroidTv && AndroidUtil.isOOrLater && !isAudioList()) setResumeProgram(service.applicationContext, it)
+                            if (AndroidDevices.isAndroidTv && AndroidUtil.isOOrLater && !isAudioList()) {
+                                setResumeProgram(service.applicationContext, it)
+                                updateNextProgramAfterThumbnailGeneration(service, service.applicationContext, it)
+                            }
                         }
                         next()
                     }
diff --git a/application/vlc-android/src/org/videolan/vlc/util/TvChannels.kt b/application/vlc-android/src/org/videolan/vlc/util/TvChannels.kt
index 5533e6327..712863101 100644
--- a/application/vlc-android/src/org/videolan/vlc/util/TvChannels.kt
+++ b/application/vlc-android/src/org/videolan/vlc/util/TvChannels.kt
@@ -28,9 +28,12 @@ import android.os.Build
 import android.util.Log
 import androidx.annotation.RequiresApi
 import androidx.core.net.toUri
+import androidx.lifecycle.LifecycleOwner
+import androidx.lifecycle.lifecycleScope
 import androidx.tvprovider.media.tv.TvContractCompat
 import androidx.tvprovider.media.tv.WatchNextProgram
 import kotlinx.coroutines.*
+import org.videolan.medialibrary.interfaces.Medialibrary
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
 import org.videolan.resources.util.getFromMl
 import org.videolan.tools.AppScope
@@ -103,6 +106,41 @@ suspend fun insertWatchNext(context: Context, mw: MediaWrapper) {
     if (watchNextProgramUri == null || watchNextProgramUri == Uri.EMPTY) Log.e(TAG, "Insert watch next program failed")
 }
 
+ at ExperimentalCoroutinesApi
+ at ObsoleteCoroutinesApi
+suspend fun updateNextProgramAfterThumbnailGeneration(lifecycleOwner: LifecycleOwner, context: Context, mw: MediaWrapper) {
+    Medialibrary.lastThumb.observe(lifecycleOwner) { media ->
+        lifecycleOwner.lifecycleScope.launch(Dispatchers.IO) {
+            var cursor: Cursor? = null
+            try {
+                cursor = context.contentResolver.query(
+                    TvContractCompat.WatchNextPrograms.CONTENT_URI, WATCH_NEXT_MAP_PROJECTION, null,
+                    null, null)
+                cursor?.let {
+                    while (it.moveToNext()) {
+                        val wnp = WatchNextProgram.fromCursor(it)
+                        val existingProgram = WatchNextProgram.fromCursor(cursor)
+                        val watchNextProgramId = cursor.getLong(0)
+                        val content = wnp.toContentValues()
+                        val contentId = content.getAsString(TvContractCompat.PreviewPrograms.COLUMN_CONTENT_ID)
+                        if (contentId.toUri() == mw.uri && mw.uri == media.uri) {
+                            val desc = ProgramDesc(
+                                0L, media.id, media.title, media.description,
+                                media.artUri(), media.length.toInt(), media.time.toInt(),
+                                media.width, media.height, BuildConfig.APP_ID, media.uri.toString()
+                            )
+                            updateWatchNext(context, existingProgram, desc, watchNextProgramId)
+                        }
+                    }
+                }
+            } finally {
+                cursor?.close()
+            }
+        }
+        Medialibrary.lastThumb.removeObservers(lifecycleOwner)
+    }
+}
+
 suspend fun setResumeProgram(context: Context, mw: MediaWrapper) {
     var cursor: Cursor? = null
     var isProgramPresent =  false



More information about the Android mailing list