[Android] Force the ML metadata update for the browser when needed
Nicolas Pomepuy
git at videolan.org
Tue Aug 2 15:14:59 UTC 2022
vlc-android | branch: master | Nicolas Pomepuy <nicolas at videolabs.io> | Tue Aug 2 09:29:47 2022 +0200| [6b044dc0cee2988c677dd9f8169df9a6d5f289b7] | committer: Duncan McNamara
Force the ML metadata update for the browser when needed
Fixes #2601
> https://code.videolan.org/videolan/vlc-android/commit/6b044dc0cee2988c677dd9f8169df9a6d5f289b7
---
.../vlc/gui/browser/BaseBrowserFragment.kt | 75 ++++++++++++++++------
1 file changed, 57 insertions(+), 18 deletions(-)
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt b/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
index 99462acf7..aa0417b02 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/browser/BaseBrowserFragment.kt
@@ -41,12 +41,18 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.*
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import org.videolan.libvlc.MediaPlayer
+import org.videolan.libvlc.interfaces.IMedia
import org.videolan.medialibrary.MLServiceLocator
import org.videolan.medialibrary.interfaces.media.MediaWrapper
import org.videolan.medialibrary.media.MediaLibraryItem
import org.videolan.resources.*
+import org.videolan.resources.util.getFromMl
import org.videolan.tools.*
import org.videolan.vlc.BuildConfig
+import org.videolan.vlc.PlaybackService
import org.videolan.vlc.R
import org.videolan.vlc.databinding.DirectoryBrowserBinding
import org.videolan.vlc.gui.AudioPlayerContainerActivity
@@ -102,6 +108,7 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
protected abstract fun createFragment(): Fragment
protected abstract fun browseRoot()
+ private var needToRefreshMeta = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -116,6 +123,19 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
showHiddenFiles = Settings.getInstance(requireContext()).getBoolean("browser_show_hidden_files", false)
isRootDirectory = defineIsRoot()
browserFavRepository = BrowserFavRepository.getInstance(requireContext())
+ PlaybackService.serviceFlow.onEach {
+ it?.addCallback(object :PlaybackService.Callback {
+ override fun update() { }
+
+ override fun onMediaEvent(event: IMedia.Event) { }
+
+ override fun onMediaPlayerEvent(event: MediaPlayer.Event) {
+ //any event of the playback service will force the media metadata to be reloaded upon future playbacks
+ needToRefreshMeta = true
+ }
+
+ })
+ }.launchIn(MainScope())
}
override fun onPrepareOptionsMenu(menu: Menu) {
@@ -373,12 +393,12 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
handler.sendEmptyMessageDelayed(MSG_SHOW_ENQUEUING, 1000)
withContext(Dispatchers.IO) {
val files = if (viewModel.url?.startsWith("file") == true) viewModel.provider.browseUrl(viewModel.url!!) else viewModel.dataset.getList()
- for (file in files.filterIsInstance(MediaWrapper::class.java))
- if (file.type == MediaWrapper.TYPE_VIDEO || file.type == MediaWrapper.TYPE_AUDIO) {
- mediaLocations.add(file)
- if (mw != null && file.equals(mw))
- positionInPlaylist = mediaLocations.size - 1
- }
+ for (file in files.filterIsInstance(MediaWrapper::class.java))
+ if (file.type == MediaWrapper.TYPE_VIDEO || file.type == MediaWrapper.TYPE_AUDIO) {
+ mediaLocations.add(getMediaWithMeta(file))
+ if (mw != null && file.equals(mw))
+ positionInPlaylist = mediaLocations.size - 1
+ }
}
handler.sendEmptyMessage(MSG_HIDE_ENQUEUING)
activity?.let { MediaUtils.openList(it, mediaLocations, positionInPlaylist) }
@@ -416,8 +436,8 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
?: return false
if (list.isNotEmpty()) {
when (item.itemId) {
- R.id.action_mode_file_play -> MediaUtils.openList(activity, list, 0)
- R.id.action_mode_file_append -> MediaUtils.appendMedia(activity, list)
+ R.id.action_mode_file_play -> lifecycleScope.launch { MediaUtils.openList(activity, list.map { getMediaWithMeta(it) }, 0) }
+ R.id.action_mode_file_append -> lifecycleScope.launch { MediaUtils.appendMedia(activity, list.map { getMediaWithMeta(it) }) }
R.id.action_mode_file_add_playlist -> requireActivity().addToPlaylist(list)
R.id.action_mode_file_info -> requireActivity().showMediaInfo(list[0])
R.id.action_mode_file_delete -> removeItems(list)
@@ -508,13 +528,15 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
if (mediaWrapper.type == MediaWrapper.TYPE_DIR) browse(mediaWrapper, true)
else {
if (!Settings.getInstance(requireContext()).getBoolean(FORCE_PLAY_ALL, false)) {
- MediaUtils.openMedia(requireContext(), item)
+ lifecycleScope.launch {
+ MediaUtils.openMedia(requireContext(), getMediaWithMeta(item))
+ }
} else {
- MediaUtils.openList(v.context,
- viewModel.dataset.getList().filter { it.itemType != MediaWrapper.TYPE_DIR }
- .map { it as MediaWrapper },
- position
- )
+ lifecycleScope.launch {
+ val media = viewModel.dataset.getList().filter { it.itemType != MediaWrapper.TYPE_DIR }
+ .map { getMediaWithMeta(it as MediaWrapper) }
+ MediaUtils.openList(v.context, media, position)
+ }
}
}
}
@@ -571,21 +593,38 @@ abstract class BaseBrowserFragment : MediaBrowserFragment<BrowserModel>(), IRefr
}
}
+ /**
+ * Get the media metadata from ML if needed
+ * This is useful in case a playback has already been running since this fragment has been started
+ * As the ML events are not listened to refresh the browser content, it will reload the ML metadata
+ * for this media to ensure the progress (and other metadata) are up to date
+ *
+ * @param mw the [MediaWrapper] to look into
+ * @return a [MediaWrapper] with up to date ML metadata
+ */
+ private suspend fun getMediaWithMeta(mw:MediaWrapper):MediaWrapper {
+ return if (!needToRefreshMeta) mw else requireActivity().getFromMl {
+ getMedia(mw.uri) ?: mw
+ }
+ }
+
override fun onCtxAction(position: Int, option: Long) {
val mw = adapter.getItem(position) as? MediaWrapper
?: return
when (option) {
- CTX_PLAY -> MediaUtils.openMedia(activity, mw)
+ CTX_PLAY -> lifecycleScope.launch { MediaUtils.openMedia(activity, getMediaWithMeta(mw)) }
CTX_PLAY_ALL -> {
mw.removeFlags(MediaWrapper.MEDIA_FORCE_AUDIO)
playAll(mw)
}
- CTX_APPEND -> MediaUtils.appendMedia(activity, mw)
+ CTX_APPEND -> lifecycleScope.launch {
+ MediaUtils.appendMedia(activity, getMediaWithMeta(mw))
+ }
CTX_DELETE -> removeItem(mw)
CTX_INFORMATION -> requireActivity().showMediaInfo(mw)
- CTX_PLAY_AS_AUDIO -> {
+ CTX_PLAY_AS_AUDIO -> lifecycleScope.launch {
mw.addFlags(MediaWrapper.MEDIA_FORCE_AUDIO)
- MediaUtils.openMedia(activity, mw)
+ MediaUtils.openMedia(activity, getMediaWithMeta(mw))
}
CTX_ADD_TO_PLAYLIST -> requireActivity().addToPlaylist(mw.tracks, SavePlaylistDialog.KEY_NEW_TRACKS)
CTX_DOWNLOAD_SUBTITLES -> MediaUtils.getSubs(requireActivity(), mw)
More information about the Android
mailing list