Index transcripts into library search (FTS), both UIs
The 🔍 library search now matches spoken words, not just titles /
channels / descriptions.
- database.rs: add a `transcript` column to the `video_search` FTS5 index.
Fresh DBs get it directly; existing ones are migrated (FTS5 has no ADD
COLUMN, so the table is recreated and search_meta cleared to force a
one-time reindex). `sync_search_index` reads each video's first subtitle
(mtime-gated like the description), flattens it via the shared `vtt`
parser (`transcript_text`, capped at 256 KB), and indexes it. Search
snippets now use column -1 so the excerpt comes from whichever column
matched (description or transcript).
- library.rs: `build_search_entries` passes the first subtitle path.
- Both UIs: search copy updated to mention transcripts.
Tests: a unit test (a word only in the .vtt is found), a migration test
(seed an old 5-column index + stale meta, open, confirm the recreated
index indexes transcript text), and the search integration test now seeds
a subtitle and asserts a spoken-only word hits. Also bumped the test
server's startup budget so the ffmpeg-heavy dedup test can't starve a
sibling server into a flaky timeout. 120 tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
4136a9468b
commit
e840d55332
5 changed files with 132 additions and 18 deletions
|
|
@ -205,7 +205,7 @@
|
|||
<option value="size-desc">Largest</option>
|
||||
</select>
|
||||
<span id="hdr-stats"></span>
|
||||
<button onclick="openSearch()" title="Search titles + descriptions (f)">🔍</button>
|
||||
<button onclick="openSearch()" title="Search titles, descriptions & transcripts (f)">🔍</button>
|
||||
<button onclick="shufflePlay()" title="Play a random unwatched video">🎲</button>
|
||||
<button onclick="rescan()" title="Rescan library">⟳</button>
|
||||
<button id="dl-btn" onclick="openDownloads()" title="Downloads">⬇<span id="dl-badge">0</span></button>
|
||||
|
|
@ -1516,7 +1516,7 @@ function openSearch(){
|
|||
bg.onclick=e=>{if(e.target===bg)bg.remove()};
|
||||
bg.innerHTML=`<div class="modal" style="max-width:720px;width:100%">
|
||||
<div class="modal-hdr"><h2>🔍 Search library</h2><button onclick="this.closest('.modal-bg').remove()">✕</button></div>
|
||||
<input id="fts-input" type="search" placeholder="Search titles, channels, descriptions…" autocomplete="off"
|
||||
<input id="fts-input" type="search" placeholder="Search titles, channels, descriptions, transcripts…" autocomplete="off"
|
||||
style="width:100%;padding:8px 10px;background:var(--bg);border:1px solid var(--border);border-radius:4px;color:var(--text);font-size:14px">
|
||||
<div id="fts-status" style="font-size:11px;color:var(--muted);padding:6px 2px"></div>
|
||||
<div id="fts-results" style="overflow-y:auto;max-height:64vh"></div>
|
||||
|
|
@ -2495,7 +2495,7 @@ function showShortcutsHelp(){
|
|||
<div class="modal-hdr"><h2>Keyboard shortcuts</h2><button onclick="this.closest('.modal-bg').remove()">✕</button></div>
|
||||
<table><tbody>
|
||||
${row('/','Focus filter box')}
|
||||
${row('f','Search titles + descriptions')}
|
||||
${row('f','Search titles, descriptions & transcripts')}
|
||||
${row('r','Rescan library')}
|
||||
${row('d','Open downloads')}
|
||||
${row('Esc','Close modal / cancel')}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue