From f1b6fd5e3112ba55690c6f79d8503edd23b1fae1 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Tue, 23 Jun 2026 00:11:56 -0700 Subject: [PATCH] video discover: language preference UI (multi-select chips) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A 🌐 multi-select chip row in the Discover toolbar (EN/KO/JA/ES/FR/HI/DE/IT) to pick which original languages appear in the general/curated rails. Loads the current preference from /discover/languages, toggling a chip POSTs the new set and rebuilds the rails (never empty — at least one stays on). Extracted reloadRails() (now shared by the hide-owned toggle + language chips). Default EN, so the rails are English unless you opt more in. --- webui/index.html | 11 ++++++++ webui/static/video/video-discover.js | 38 +++++++++++++++++++++++----- webui/static/video/video-side.css | 10 ++++++++ 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/webui/index.html b/webui/index.html index ee3b7304..1d875e8a 100644 --- a/webui/index.html +++ b/webui/index.html @@ -1051,6 +1051,17 @@ Hide owned +
+ 🌐 + + + + + + + + +
diff --git a/webui/static/video/video-discover.js b/webui/static/video/video-discover.js index e7239b86..c574d013 100644 --- a/webui/static/video/video-discover.js +++ b/webui/static/video/video-discover.js @@ -333,6 +333,14 @@ .catch(function () { /* best-effort */ }); } + // Rebuild the whole rail stack (genre/curated shelves + the prepended personalized rows). + function reloadRails() { + renderShelves(); + loadMoreLike(); + loadGaps(); + loadForYou(); + } + // ── shelves (lazy rails) ────────────────────────────────────────────────── function renderShelves() { var host = $('[data-vdsc-shelves]'); if (!host) return; @@ -546,12 +554,30 @@ hide.addEventListener('change', function () { page.classList.toggle('vdsc-hide-owned', hide.checked); try { localStorage.setItem('vdsc_hideowned', hide.checked ? '1' : '0'); } catch (e) { /* ignore */ } - // The rails are now server-filtered for owned (and page deeper), so rebuild - // them with the new state instead of just CSS-hiding cards in place. - renderShelves(); - loadMoreLike(); - loadGaps(); - loadForYou(); + reloadRails(); // rails are server-filtered now (owned + paged deeper) — rebuild + }); + } + // Rail language preference — multi-select chips, persisted server-side; rebuilds the rails. + var langWrap = $('[data-vdsc-langs]'); + if (langWrap) { + fetch('/api/video/discover/languages', { headers: { Accept: 'application/json' } }) + .then(function (r) { return r.ok ? r.json() : null; }) + .then(function (d) { + var set = {}; ((d && d.languages) || ['en']).forEach(function (c) { set[c] = 1; }); + langWrap.querySelectorAll('.vdsc-lang').forEach(function (b) { + b.classList.toggle('vdsc-lang--on', !!set[b.getAttribute('data-lang')]); + }); + }).catch(function () { /* default chip state stands */ }); + langWrap.addEventListener('click', function (e) { + var btn = e.target.closest('.vdsc-lang'); if (!btn) return; + btn.classList.toggle('vdsc-lang--on'); + var langs = Array.prototype.map.call(langWrap.querySelectorAll('.vdsc-lang--on'), + function (b) { return b.getAttribute('data-lang'); }); + if (!langs.length) { btn.classList.add('vdsc-lang--on'); return; } // never allow empty + fetch('/api/video/discover/languages', { + method: 'POST', headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ languages: langs }), + }).then(function () { reloadRails(); }).catch(function () { /* ignore */ }); }); } // Infinite scroll: a sentinel near the grid bottom pulls the next page. diff --git a/webui/static/video/video-side.css b/webui/static/video/video-side.css index 7b86701d..1830d196 100644 --- a/webui/static/video/video-side.css +++ b/webui/static/video/video-side.css @@ -2354,6 +2354,16 @@ body[data-side="video"] #soulsync-toggle { display: none; } .vdsc-toggle input { accent-color: rgb(var(--accent-rgb, 88 101 242)); width: 16px; height: 16px; cursor: pointer; } .vdsc-hide-owned .vsr-card--owned { display: none; } +/* rail-language preference chips — which original languages show in the general rails */ +.vdsc-langs { display: inline-flex; align-items: center; gap: 4px; flex-wrap: wrap; margin-left: 14px; } +.vdsc-langs-label { font-size: 13px; opacity: 0.6; } +.vdsc-lang { font-size: 11px; font-weight: 700; letter-spacing: 0.3px; padding: 3px 8px; border-radius: 999px; + border: 1px solid rgba(255, 255, 255, 0.12); background: rgba(255, 255, 255, 0.04); + color: rgba(255, 255, 255, 0.5); cursor: pointer; + transition: color 0.15s ease, background 0.15s ease, border-color 0.15s ease; } +.vdsc-lang:hover { color: rgba(255, 255, 255, 0.85); } +.vdsc-lang--on { color: #fff; background: rgba(var(--accent-rgb, 88 101 242), 0.85); border-color: transparent; } + /* rails: a gentle fade-in when filled + per-title hue on hover */ .vdsc-shelf--in .vdsc-rail { animation: vdscFade 0.45s ease both; } @keyframes vdscFade { from { opacity: 0.35; } to { opacity: 1; } }