Add browser search/filter for media items

- Search bar appears when browsing inside a folder
- Client-side filtering with 200ms debounce
- Clear button and search icon
- Hides at root level, resets on navigation
- Localized placeholder (en/ru)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-09 02:44:31 +03:00
parent 98a33bca54
commit 5f474d6c9f
5 changed files with 136 additions and 1 deletions

View File

@@ -1460,6 +1460,8 @@ let totalItems = 0;
let mediaFolders = {};
let viewMode = localStorage.getItem('mediaBrowser.viewMode') || 'grid';
let cachedItems = null;
let browserSearchTerm = '';
let browserSearchTimer = null;
// Load media folders on page load
async function loadMediaFolders() {
@@ -1490,6 +1492,10 @@ function showRootFolders() {
currentFolderId = '';
currentPath = '';
currentOffset = 0;
cachedItems = null;
// Hide search at root level
showBrowserSearch(false);
// Render breadcrumb with just "Home" (not clickable at root)
const breadcrumb = document.getElementById('breadcrumb');
@@ -1550,6 +1556,9 @@ function showRootFolders() {
}
async function browsePath(folderId, path, offset = 0, nocache = false) {
// Clear search when navigating
showBrowserSearch(false);
try {
const token = localStorage.getItem('media_server_token');
if (!token) {
@@ -1582,6 +1591,9 @@ async function browsePath(folderId, path, offset = 0, nocache = false) {
renderBrowserItems(cachedItems);
renderPagination();
// Show search bar when inside a folder
showBrowserSearch(true);
// Show/hide Play All button based on whether media items exist
const hasMedia = data.items.some(item => item.is_media);
document.getElementById('playAllBtn').style.display = hasMedia ? '' : 'none';
@@ -2072,6 +2084,54 @@ function refreshBrowser() {
}
}
// Browser search
function onBrowserSearch() {
const input = document.getElementById('browserSearchInput');
const clearBtn = document.getElementById('browserSearchClear');
const term = input.value.trim();
clearBtn.style.display = term ? 'flex' : 'none';
// Debounce: wait 200ms after typing stops
if (browserSearchTimer) clearTimeout(browserSearchTimer);
browserSearchTimer = setTimeout(() => {
browserSearchTerm = term.toLowerCase();
applyBrowserSearch();
}, 200);
}
function clearBrowserSearch() {
const input = document.getElementById('browserSearchInput');
input.value = '';
document.getElementById('browserSearchClear').style.display = 'none';
browserSearchTerm = '';
applyBrowserSearch();
input.focus();
}
function applyBrowserSearch() {
if (!cachedItems) return;
if (!browserSearchTerm) {
renderBrowserItems(cachedItems);
return;
}
const filtered = cachedItems.filter(item =>
item.name.toLowerCase().includes(browserSearchTerm)
);
renderBrowserItems(filtered);
}
function showBrowserSearch(visible) {
document.getElementById('browserSearchWrapper').style.display = visible ? '' : 'none';
if (!visible) {
document.getElementById('browserSearchInput').value = '';
document.getElementById('browserSearchClear').style.display = 'none';
browserSearchTerm = '';
}
}
function setViewMode(mode) {
if (mode === viewMode) return;
viewMode = mode;
@@ -2084,7 +2144,7 @@ function setViewMode(mode) {
// Re-render current view from cache (no network request)
if (currentFolderId && cachedItems) {
renderBrowserItems(cachedItems);
applyBrowserSearch();
} else {
showRootFolders();
}