diff --git a/application/vlc-android/res/layout-land/audio_player.xml b/application/vlc-android/res/layout-land/audio_player.xml
index 4f8640a0f96d0f783c22e3d20fcd29a032a3c839..aa3855c54e69c624e57bd8d21a61d6313300098a 100644
--- a/application/vlc-android/res/layout-land/audio_player.xml
+++ b/application/vlc-android/res/layout-land/audio_player.xml
@@ -296,7 +296,7 @@
                     android:visibility="gone"
                     app:layout_constraintBottom_toBottomOf="parent"
                     app:layout_constraintEnd_toEndOf="@+id/header_play_pause"
-                    app:layout_constraintStart_toEndOf="@+id/playlist_playasaudio_off"
+                    app:layout_constraintStart_toStartOf="parent"
                     app:layout_constraintTop_toTopOf="parent">
 
                 <EditText
diff --git a/application/vlc-android/res/layout/playlist_item.xml b/application/vlc-android/res/layout/playlist_item.xml
index 4ce37114e20ec80e45c1783b79681f291b17f5e1..5f7afb290aba4657642e9226e50d2bd525c4ea71 100644
--- a/application/vlc-android/res/layout/playlist_item.xml
+++ b/application/vlc-android/res/layout/playlist_item.xml
@@ -39,6 +39,10 @@
                 name="showTrackNumbers"
                 type="java.lang.Boolean" />
 
+        <variable
+                name="showReorderButtons"
+                type="java.lang.Boolean" />
+
         <variable
                 name="masked"
                 type="java.lang.Boolean" />
@@ -214,6 +218,7 @@
                 android:layout_gravity="center"
                 android:layout_marginEnd="8dp"
                 android:background="?attr/selectableItemBackgroundBorderless"
+                android:visibility="@{showReorderButtons ? View.VISIBLE : View.GONE}"
                 android:clickable="true"
                 android:focusable="true"
                 android:onClick="@{holder::onMoveDownClick}"
@@ -236,6 +241,7 @@
                 android:clickable="true"
                 android:focusable="true"
                 android:onClick="@{holder::onMoveUpClick}"
+                android:visibility="@{showReorderButtons ? View.VISIBLE : View.GONE}"
                 android:padding="8dp"
                 android:scaleType="center"
                 app:layout_constraintBottom_toBottomOf="parent"
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt
index c56dcc147e39fc59ceb53714f02d1f88fe7f6397..1c70ccb3d14a0a5ce015fb52d393f3576e4ee447 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayer.kt
@@ -68,6 +68,7 @@ import org.videolan.medialibrary.Tools
 import org.videolan.medialibrary.interfaces.media.Bookmark
 import org.videolan.medialibrary.interfaces.media.MediaWrapper
 import org.videolan.medialibrary.media.MediaLibraryItem
+import org.videolan.resources.AndroidDevices
 import org.videolan.resources.AppContextProvider
 import org.videolan.resources.TAG_ITEM
 import org.videolan.resources.util.parcelable
@@ -164,6 +165,7 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
     private var lastEndsAt = -1L
     private var isDragging = false
     private var currentChapters: Pair<MediaWrapper,  List<MediaPlayer.Chapter>?>? = null
+    private lateinit var callback: SwipeDragItemTouchHelperCallback
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
@@ -177,6 +179,13 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
         playlistModel = PlaylistModel.get(this)
         playlistModel.progress.observe(this@AudioPlayer) { it?.let { updateProgress(it) } }
         playlistModel.speed.observe(this@AudioPlayer) { showChips() }
+        playlistModel.filteringState.observe(this@AudioPlayer) {
+            callback.longPressDragEnable = !it
+            if (isTablet() || AndroidDevices.isTv) {
+                playlistAdapter.showReorderButtons = !it
+                playlistAdapter.notifyDataSetChanged()
+            }
+        }
         playlistAdapter.setModel(playlistModel)
         playlistModel.dataset.asFlow().conflate().onEach {
             doUpdate()
@@ -232,7 +241,7 @@ class AudioPlayer : Fragment(), PlaylistAdapter.IPlayer, TextWatcher, IAudioPlay
             coverMediaSwitcherListener.onChapterSwitching(false)
         }
 
-        val callback = SwipeDragItemTouchHelperCallback(playlistAdapter, true)
+        callback = SwipeDragItemTouchHelperCallback(playlistAdapter, true)
         val touchHelper = ItemTouchHelper(callback)
         touchHelper.attachToRecyclerView(binding.songsList)
 
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayerAnimator.kt b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayerAnimator.kt
index 1e8745c63235ab7541b493b7852d79ee82a82946..d98f5d122eb17e1bd6e836c36004124ee4d4c0b7 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayerAnimator.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/audio/AudioPlayerAnimator.kt
@@ -219,7 +219,10 @@ internal class AudioPlayerAnimator : IAudioPlayerAnimator, LifecycleObserver {
     override suspend fun updateBackground() {
         if (Settings.getInstance(audioPlayer.requireActivity()).getBoolean("blurred_cover_background", true)) {
             val mw = audioPlayer.playlistModel.currentMediaWrapper ?: return
-            if (currentCoverArt == mw.artworkMrl) return
+            if (currentCoverArt == mw.artworkMrl) {
+                if (currentCoverArt == null) setDefaultBackground()
+                return
+            }
             currentCoverArt = mw.artworkMrl
             if (mw.artworkMrl.isNullOrEmpty()) setDefaultBackground()
             else {
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/audio/PlaylistAdapter.kt b/application/vlc-android/src/org/videolan/vlc/gui/audio/PlaylistAdapter.kt
index 7d341f3a20b7a48c67fb07356248fc7badd2489e..7046e54b80ae12aeb55cfc00e145e3897e3baaa2 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/audio/PlaylistAdapter.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/audio/PlaylistAdapter.kt
@@ -72,6 +72,7 @@ private const val ACTION_MOVED = "action_moved"
 class PlaylistAdapter(private val player: IPlayer) : DiffUtilAdapter<MediaWrapper, PlaylistAdapter.ViewHolder>(), SwipeDragHelperAdapter, SchedulerCallback {
 
     var showTrackNumbers: Boolean = false
+    var showReorderButtons: Boolean = true
     private var defaultCoverVideo: BitmapDrawable
     private var defaultCoverAudio: BitmapDrawable
     private var model: PlaylistModel? = null
@@ -156,8 +157,7 @@ class PlaylistAdapter(private val player: IPlayer) : DiffUtilAdapter<MediaWrappe
 
         val tablet = holder.binding.itemDelete.context.isTablet() || AndroidDevices.isTv
         if (tablet) holder.binding.itemDelete.setVisible() else holder.binding.itemDelete.setGone()
-        if (tablet) holder.binding.itemMoveDown.setVisible() else holder.binding.itemMoveDown.setGone()
-        if (tablet) holder.binding.itemMoveUp.setVisible() else holder.binding.itemMoveUp.setGone()
+        holder.binding.showReorderButtons = showReorderButtons && tablet
 
         holder.binding.executePendingBindings()
     }
@@ -203,18 +203,21 @@ class PlaylistAdapter(private val player: IPlayer) : DiffUtilAdapter<MediaWrappe
     }
 
     override fun onItemDismiss(position: Int) {
-        val media = getItem(position)
-        val message = String.format(AppContextProvider.appResources.getString(R.string.remove_playlist_item), media.title)
-        if (player is Fragment) {
-            UiTools.snackerWithCancel(player.requireActivity(), message, overAudioPlayer = true, action = {}) {
-                 model?.run { insertMedia(position, media) }
-            }
-        } else if (player is Activity) {
-            UiTools.snackerWithCancel(player, message, action = {}) {
-                model?.run { insertMedia(position, media) }
+        model?.let {
+            val media = getItem(position)
+            val message = String.format(AppContextProvider.appResources.getString(R.string.remove_playlist_item), media.title)
+            val originalPosition = it.getOriginalPosition(position)
+            if (player is Fragment) {
+                UiTools.snackerWithCancel(player.requireActivity(), message, overAudioPlayer = true, action = {}) {
+                    model?.run { insertMedia(originalPosition, media) }
+                }
+            } else if (player is Activity) {
+                UiTools.snackerWithCancel(player, message, action = {}) {
+                    model?.run { insertMedia(originalPosition, media) }
+                }
             }
+            remove(position)
         }
-        remove(position)
     }
 
     fun setModel(model: PlaylistModel) {
diff --git a/application/vlc-android/src/org/videolan/vlc/gui/helpers/SwipeDragItemTouchHelperCallback.kt b/application/vlc-android/src/org/videolan/vlc/gui/helpers/SwipeDragItemTouchHelperCallback.kt
index 6fc4601cff09a630141da21c4dc88a6213e4b602..5c1f2f7fe5da1deb4f2bca836ea09fc87666201c 100644
--- a/application/vlc-android/src/org/videolan/vlc/gui/helpers/SwipeDragItemTouchHelperCallback.kt
+++ b/application/vlc-android/src/org/videolan/vlc/gui/helpers/SwipeDragItemTouchHelperCallback.kt
@@ -28,7 +28,7 @@ import androidx.recyclerview.widget.RecyclerView
 import org.videolan.vlc.gui.helpers.hf.PinCodeDelegate
 import org.videolan.vlc.interfaces.SwipeDragHelperAdapter
 
-class SwipeDragItemTouchHelperCallback(private val mAdapter: SwipeDragHelperAdapter, private val longPressDragEnable: Boolean = false, private val lockedInSafeMode: Boolean = false) : ItemTouchHelper.Callback() {
+class SwipeDragItemTouchHelperCallback(private val mAdapter: SwipeDragHelperAdapter, var longPressDragEnable: Boolean = false, private val lockedInSafeMode: Boolean = false) : ItemTouchHelper.Callback() {
     private var dragFrom = -1
     private var dragTo = -1
     var swipeEnabled = true
diff --git a/application/vlc-android/src/org/videolan/vlc/util/FilterDelegate.kt b/application/vlc-android/src/org/videolan/vlc/util/FilterDelegate.kt
index 8d6774ec8e8ef78beb04caab02ba72782d817010..8b173c9735f8055e1a8be582cca1d9b1ed12d517 100644
--- a/application/vlc-android/src/org/videolan/vlc/util/FilterDelegate.kt
+++ b/application/vlc-android/src/org/videolan/vlc/util/FilterDelegate.kt
@@ -7,10 +7,10 @@ import org.videolan.medialibrary.interfaces.media.MediaWrapper
 import org.videolan.medialibrary.media.MediaLibraryItem
 import org.videolan.resources.AppContextProvider
 import org.videolan.vlc.media.MediaUtils
-import java.util.*
+import java.util.Locale
 
-open class FilterDelegate<T : MediaLibraryItem>(protected val dataset: MutableLiveData<out List<T>>) {
-    private var sourceSet: List<T>? = null
+open class FilterDelegate<T : MediaLibraryItem>(val dataset: MutableLiveData<out List<T>>) {
+    var sourceSet: List<T>? = null
 
     protected fun initSource() : List<T>? {
         if (sourceSet === null) sourceSet = (dataset.value)
diff --git a/application/vlc-android/src/org/videolan/vlc/viewmodels/PlaylistModel.kt b/application/vlc-android/src/org/videolan/vlc/viewmodels/PlaylistModel.kt
index ca046bb7fa16de6810d7fa4711191df93a0696f9..799615bdd17534f7200e52bcf690f8f0b472b467 100644
--- a/application/vlc-android/src/org/videolan/vlc/viewmodels/PlaylistModel.kt
+++ b/application/vlc-android/src/org/videolan/vlc/viewmodels/PlaylistModel.kt
@@ -24,7 +24,11 @@ import android.support.v4.media.session.PlaybackStateCompat
 import androidx.annotation.MainThread
 import androidx.fragment.app.Fragment
 import androidx.fragment.app.FragmentActivity
-import androidx.lifecycle.*
+import androidx.lifecycle.MediatorLiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.ViewModelProvider
+import androidx.lifecycle.viewModelScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ObsoleteCoroutinesApi
 import kotlinx.coroutines.channels.actor
@@ -47,12 +51,18 @@ class PlaylistModel : ViewModel(), PlaybackService.Callback by EmptyPBSCallback
     private var originalDataset : MutableList<MediaWrapper>? = null
     val selection : Int
         get() = if (filtering) -1 else service?.playlistManager?.currentIndex ?: -1
-    private var filtering = false
+    var filtering = false
+        set(value) {
+            field = value
+            filteringState.value = value
+        }
+    val filteringState = MutableLiveData<Boolean>()
     val progress = MediatorLiveData<PlaybackProgress>()
     val speed = MediatorLiveData<Float>()
     val playerState = MutableLiveData<PlayerState>()
     val connected : Boolean
         get() = service !== null
+    var lastQuery: CharSequence? = null
 
     private val filter by lazy(LazyThreadSafetyMode.NONE) { PlaylistFilterDelegate(dataset) }
 
@@ -76,7 +86,13 @@ class PlaylistModel : ViewModel(), PlaybackService.Callback by EmptyPBSCallback
 
     override fun update() {
         service?.run {
-            dataset.value = media.toMutableList()
+            if (filtering) {
+                originalDataset = media.toMutableList()
+                filter.sourceSet = originalDataset
+                dataset.value = filter.dataset.value?.toMutableList() ?: media.toMutableList()
+                filterActor.trySend(lastQuery)
+            } else
+                dataset.value = media.toMutableList()
             playerState.value = PlayerState(isPlaying, title, artist)
         }
     }
@@ -84,14 +100,33 @@ class PlaylistModel : ViewModel(), PlaybackService.Callback by EmptyPBSCallback
     val hasMedia
         get() = service?.hasMedia() ?: false
 
-    fun insertMedia(position: Int, media: MediaWrapper) = service?.insertItem(position, media)
+    fun insertMedia(position: Int, media: MediaWrapper) {
+        service?.insertItem(position, media)
+        if (filtering) {
+            service?.let {
+                originalDataset = it.media.toMutableList()
+                filter.sourceSet = originalDataset
+            }
+        }
+    }
+
+    /**
+     * Get original position even if current list is filtered
+     *
+     * @param position the current position in the filtered list or not
+     * @return the original position (in the unfiltered list)
+     */
+    fun getOriginalPosition(position: Int) = if (filtering && originalDataset != null) {
+        originalDataset!!.indexOf(dataset.get(position))
+    } else position
 
-    fun remove(position: Int) = service?.remove(position)
+    fun remove(position: Int) = service?.remove(getOriginalPosition(position))
 
     fun move(from: Int, to: Int) = service?.moveItem(from, to)
 
     @MainThread
     fun filter(query: CharSequence?) {
+        lastQuery = query
         val filtering = query != null
         if (this.filtering != filtering) {
             this.filtering = filtering