diff --git a/src/renderer/components/playlist-info/playlist-info.js b/src/renderer/components/playlist-info/playlist-info.js
index 7deaf2d387100..22cf724666799 100644
--- a/src/renderer/components/playlist-info/playlist-info.js
+++ b/src/renderer/components/playlist-info/playlist-info.js
@@ -5,9 +5,11 @@ import FtFlexBox from '../ft-flex-box/ft-flex-box.vue'
import FtIconButton from '../ft-icon-button/ft-icon-button.vue'
import FtInput from '../ft-input/ft-input.vue'
import FtPrompt from '../ft-prompt/ft-prompt.vue'
+import FtButton from '../ft-button/ft-button.vue'
import {
showToast,
} from '../../helpers/utils'
+import debounce from 'lodash.debounce'
export default defineComponent({
name: 'PlaylistInfo',
@@ -17,6 +19,7 @@ export default defineComponent({
'ft-icon-button': FtIconButton,
'ft-input': FtInput,
'ft-prompt': FtPrompt,
+ 'ft-button': FtButton,
},
props: {
id: {
@@ -82,6 +85,9 @@ export default defineComponent({
},
data: function () {
return {
+ searchVideoMode: false,
+ query: '',
+ updateQueryDebounce: function() {},
editMode: false,
showDeletePlaylistPrompt: false,
showRemoveVideosOnWatchPrompt: false,
@@ -223,6 +229,8 @@ export default defineComponent({
created: function () {
this.newTitle = this.title
this.newDescription = this.description
+
+ this.updateQueryDebounce = debounce(this.updateQuery, 500)
},
methods: {
toggleCopyVideosPrompt: function (force = false) {
@@ -364,6 +372,25 @@ export default defineComponent({
showToast(this.$t('User Playlists.SinglePlaylistView.Toast.Quick bookmark disabled'))
},
+ updateQuery(query) {
+ this.query = query
+ this.$emit('search-video-query-change', query)
+ },
+ enableVideoSearchMode() {
+ this.searchVideoMode = true
+ this.$emit('search-video-mode-on')
+
+ nextTick(() => {
+ // Some elements only present after rendering update
+ this.$refs.searchInput.focus()
+ })
+ },
+ disableVideoSearchMode() {
+ this.searchVideoMode = false
+ this.updateQuery('')
+ this.$emit('search-video-mode-off')
+ },
+
...mapActions([
'showAddToPlaylistPromptForManyVideos',
'updatePlaylist',
diff --git a/src/renderer/components/playlist-info/playlist-info.scss b/src/renderer/components/playlist-info/playlist-info.scss
index 3fb13c0c0fe8a..be8766bfa89c2 100644
--- a/src/renderer/components/playlist-info/playlist-info.scss
+++ b/src/renderer/components/playlist-info/playlist-info.scss
@@ -72,3 +72,13 @@
column-gap: 8px;
justify-content: flex-end;
}
+
+.searchInputsRow {
+ margin-block-start: 8px;
+
+ display: grid;
+
+ /* 2 columns */
+ grid-template-columns: 1fr auto;
+ column-gap: 8px;
+}
diff --git a/src/renderer/components/playlist-info/playlist-info.vue b/src/renderer/components/playlist-info/playlist-info.vue
index 4dd1f1e95bb01..249a017aa347f 100644
--- a/src/renderer/components/playlist-info/playlist-info.vue
+++ b/src/renderer/components/playlist-info/playlist-info.vue
@@ -76,6 +76,7 @@
+
+
+
+ updateQueryDebounce(input)"
+ @clear="updateQueryDebounce('')"
+ />
+
+
diff --git a/src/renderer/views/Playlist/Playlist.js b/src/renderer/views/Playlist/Playlist.js
index 601284fd9a891..42f374faa5d97 100644
--- a/src/renderer/views/Playlist/Playlist.js
+++ b/src/renderer/views/Playlist/Playlist.js
@@ -60,6 +60,9 @@ export default defineComponent({
getPlaylistInfoDebounce: function() {},
playlistInEditMode: false,
+ playlistInVideoSearchMode: false,
+ videoSearchQuery: '',
+
promptOpen: false,
}
},
@@ -123,17 +126,29 @@ export default defineComponent({
return this.selectedUserPlaylist?._id !== this.quickBookmarkPlaylistId
},
+ sometimesFilteredUserPlaylistItems() {
+ if (!this.isUserPlaylistRequested) { return this.playlistItems }
+ if (this.processedVideoSearchQuery === '') { return this.playlistItems }
+
+ return this.playlistItems.filter((v) => {
+ return v.title.toLowerCase().includes(this.processedVideoSearchQuery)
+ })
+ },
visiblePlaylistItems: function () {
if (!this.isUserPlaylistRequested) {
+ // No filtering for non user playlists yet
return this.playlistItems
}
if (this.userPlaylistVisibleLimit < this.videoCount) {
- return this.playlistItems.slice(0, this.userPlaylistVisibleLimit)
+ return this.sometimesFilteredUserPlaylistItems.slice(0, this.userPlaylistVisibleLimit)
} else {
- return this.playlistItems
+ return this.sometimesFilteredUserPlaylistItems
}
- }
+ },
+ processedVideoSearchQuery() {
+ return this.videoSearchQuery.trim().toLowerCase()
+ },
},
watch: {
$route () {
diff --git a/src/renderer/views/Playlist/Playlist.vue b/src/renderer/views/Playlist/Playlist.vue
index 81d022609632b..40c6ae5682673 100644
--- a/src/renderer/views/Playlist/Playlist.vue
+++ b/src/renderer/views/Playlist/Playlist.vue
@@ -28,6 +28,9 @@
}"
@enter-edit-mode="playlistInEditMode = true"
@exit-edit-mode="playlistInEditMode = false"
+ @search-video-mode-on="playlistInVideoSearchMode = true"
+ @search-video-mode-off="playlistInVideoSearchMode = false"
+ @search-video-query-change="(v) => videoSearchQuery = v"
@prompt-open="promptOpen = true"
@prompt-close="promptOpen = false"
/>
@@ -55,8 +58,8 @@
appearance="result"
:always-show-add-to-playlist-button="true"
:quick-bookmark-button-enabled="quickBookmarkButtonEnabled"
- :can-move-video-up="index > 0"
- :can-move-video-down="index < visiblePlaylistItems.length - 1"
+ :can-move-video-up="index > 0 && !playlistInVideoSearchMode"
+ :can-move-video-down="index < playlistItems.length - 1 && !playlistInVideoSearchMode"
:can-remove-from-playlist="true"
:video-index="index"
:initial-visible-state="index < 10"
diff --git a/static/locales/en-US.yaml b/static/locales/en-US.yaml
index b8fc52b81a3b5..78a7ad475be6a 100644
--- a/static/locales/en-US.yaml
+++ b/static/locales/en-US.yaml
@@ -186,6 +186,8 @@ User Playlists:
EarliestPlayedFirst: 'Earliest Played'
SinglePlaylistView:
+ Search for Videos: Search for Videos
+
Toast:
This video cannot be moved up.: This video cannot be moved up.
This video cannot be moved down.: This video cannot be moved down.