mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-16 14:16:16 -08:00
feat(search): add workspace global search with M3U support
Moves global search into a routed workspace view, adds M3U live/radio results, lazy pagination, and DB-backed matching improvements.
This commit is contained in:
1 parent
ffc07146fe
commit
89916af9d8
65 files changed
+3010
-391
No files matched your search
@@ -203,6 +203,56 @@ state handlers that still used direct main-thread SQLite access.
|
||||
6. `DB_GLOBAL_SEARCH`
|
||||
7. `DB_GET_GLOBAL_RECENTLY_ADDED`
|
||||
|
||||
`DB_GLOBAL_SEARCH` returns a shared global-search result union rather than an
|
||||
Xtream-only row shape:
|
||||
|
||||
1. `source_type = "xtream"` rows come from the normalized `content` and
|
||||
`categories` tables joined with `playlists`. Xtream title matching uses
|
||||
`content_title_fts`, an FTS5 trigram index over `content.title`, for search
|
||||
terms with at least one 3+ character token. Tokens are quoted before being
|
||||
passed to `MATCH`, so FTS reserved words such as `and` are treated as search
|
||||
text instead of degrading to the slow fallback path. SQL prefilters keep both
|
||||
raw lower-case tokens and accent-normalized tokens, so an accented query such
|
||||
as `Café` can still reach rows stored as either `Café` or `Cafe` before the
|
||||
worker's accent-insensitive ranking step. Existing databases rebuild this
|
||||
index once through the `migration:content-title-fts-trigram:v1` app-state
|
||||
marker before legacy content cleanup/normalization migrations run; fresh
|
||||
inserts, deletes, and title updates stay synchronized through SQLite triggers.
|
||||
2. `source_type = "m3u"` rows come from M3U playlist payloads stored in
|
||||
`playlists.payload`. The worker uses SQL `payload LIKE` against channel
|
||||
`name`/`title` JSON fields only as a coarse candidate prefilter, then parses
|
||||
candidate JSON payloads and matches channel name, TVG name, and group title
|
||||
case-insensitively in the worker. M3U payload prefilters also preserve raw
|
||||
accented token variants next to normalized variants. The SQL candidate query
|
||||
is capped by the same stable 5000-row candidate limit used for Xtream search,
|
||||
so large
|
||||
matching M3U payloads are not loaded without an upper bound.
|
||||
3. The optional `sources` argument can restrict search to `xtream` or `m3u`,
|
||||
but omitted callers keep the backward-compatible behavior of searching all
|
||||
supported global-search sources.
|
||||
4. The optional pagination argument accepts `{ limit, offset }`. The worker
|
||||
keeps the legacy default of 50 results when the argument is omitted, but the
|
||||
routed global-search view requests one extra row per page to implement
|
||||
lazy loading without requiring a separate count query. Candidate selection
|
||||
uses a stable max-size pool for every page so score-based in-memory ranking
|
||||
cannot shift already-rendered items into later pages.
|
||||
5. Candidate rows are ranked in the worker after the coarse SQL prefilter.
|
||||
Exact and prefix matches sort ahead of word-prefix and substring matches;
|
||||
short first tokens such as `tv` stay anchored to the start of the title, so
|
||||
`TV Sport` matches but `Test TV` does not. These short first-token queries
|
||||
bypass trigram FTS and use the `idx_content_title` prefix index path because
|
||||
trigram tokenization cannot match 1-2 character terms.
|
||||
6. `excludeHidden` still filters hidden Xtream categories and also filters M3U
|
||||
channels whose `group.title` is listed in the playlist payload's
|
||||
`hiddenGroupTitles`.
|
||||
7. M3U radio entries are returned as live results with `radio = "true"` and the
|
||||
serialized `Channel` attached for renderer playback routing. M3U global
|
||||
search rows are not Xtream content rows: they use `xtream_id = -1`, and
|
||||
Xtream-only metadata such as `rating`, `added`, and a missing `poster_url`
|
||||
is represented as `null`.
|
||||
8. EPG-program text is not part of this contract; EPG search remains a separate
|
||||
feature because it uses different persistence and freshness rules.
|
||||
|
||||
### Playlist metadata
|
||||
|
||||
1. `DB_CREATE_PLAYLIST`
|
||||
@@ -288,7 +338,8 @@ to `epg-worker.service.ts`.
|
||||
Xtream search now guards against stale async responses:
|
||||
|
||||
1. local playlist search uses a monotonically increasing request version
|
||||
2. global search uses a separate request version in the dialog component
|
||||
2. global search uses a separate request version in the routed workspace search
|
||||
component
|
||||
3. clearing search invalidates older pending results
|
||||
|
||||
This prevents an older worker response from repainting over a newer query or a
|
||||
|
||||
@@ -43,10 +43,12 @@ Current workspace routes:
|
||||
4. `/workspace/sources`
|
||||
5. `/workspace/playlists/:id/:view`
|
||||
6. `/workspace/global-favorites`
|
||||
7. `/workspace/downloads`
|
||||
8. `/workspace/settings`
|
||||
9. `/workspace/xtreams/:id/...`
|
||||
10. `/workspace/stalker/:id/...`
|
||||
7. `/workspace/global-recent`
|
||||
8. `/workspace/search`
|
||||
9. `/workspace/downloads`
|
||||
10. `/workspace/settings`
|
||||
11. `/workspace/xtreams/:id/...`
|
||||
12. `/workspace/stalker/:id/...`
|
||||
|
||||
Compatibility redirect:
|
||||
|
||||
@@ -74,7 +76,9 @@ Provider route integration:
|
||||
The shell is intentionally split into four persistent regions:
|
||||
|
||||
1. Left rail:
|
||||
1. Static workspace links for dashboard, sources, global favorites, and recently viewed.
|
||||
1. Static workspace links for dashboard, sources, global favorites, and
|
||||
recently viewed. The routed global-search rail link is Electron-only
|
||||
because its data source is the SQLite worker bridge.
|
||||
2. Provider-aware context links derived from the active or current playlist.
|
||||
3. Settings remains a persistent footer shortcut in the rail.
|
||||
2. Top header:
|
||||
@@ -142,17 +146,24 @@ Search is shell-owned and route-aware:
|
||||
|
||||
1. Disabled on settings routes.
|
||||
2. Enabled on sources routes.
|
||||
3. Enabled for supported Xtream and Stalker content/search views.
|
||||
4. Placeholder text and search handling vary by provider and section.
|
||||
5. Input changes are debounced before route/store updates are applied.
|
||||
3. Enabled for `/workspace/search`, which is the Electron-only routed
|
||||
global-search view. `Ctrl/Cmd+F` in Electron opens this route and
|
||||
focuses/selects the header search input instead of opening a fullscreen
|
||||
dialog.
|
||||
4. Enabled for supported Xtream and Stalker content/search views.
|
||||
5. Placeholder text and search handling vary by provider and section.
|
||||
6. Input changes are debounced before route/store updates are applied.
|
||||
7. Global search uses the header input as its primary input and writes the
|
||||
search phrase to the `q` query parameter, so history/back-forward behavior
|
||||
matches the rest of the workspace.
|
||||
|
||||
Rail navigation is also shell-owned:
|
||||
|
||||
1. Workspace-global entries are static.
|
||||
2. Provider entries come from `buildPortalRailLinks(...)`.
|
||||
3. On dashboard, sources, settings, and global favorites, the shell falls back
|
||||
to the currently selected playlist so provider navigation remains available
|
||||
even outside a provider route.
|
||||
3. On dashboard, sources, settings, global search, global favorites, and global
|
||||
recent, the shell falls back to the currently selected playlist so provider
|
||||
navigation remains available even outside a provider route.
|
||||
|
||||
Command palette behavior is shell-owned but view-extensible:
|
||||
|
||||
|
||||
Reference in new issue
Block a user