mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-04 20:03:11 +02:00
Replace the server-side HTML builder in the `search` admin-ajax action with a
structured JSON contract: each result item now carries `{id, url, text, entity,
data}` and the client renders the card. Permission checks, status resolution and
category/server lookups stay server-side; only markup moves to the browser. This
unblocks the upcoming redesign, where the embedded HTML builder was in the way.
- SearchAjaxController::search() now emits structured items (per-entity `data`
payloads for stream/movie/channel/radio/episode, series, user, line, mag,
enigma) plus a `no_results` item for empty responses. Data-gathering is
unchanged (byte-identical to the previous fuzzy full-text gather).
- New client renderer `assets/admin/js/search.js` (`renderSearchItem`), loaded
before common.js; the Select2 quick-search `templateResult` now calls it
(with a loading-state guard) instead of consuming a server `html` field.
- ADR docs/adr/search-json-contract.md documents the envelope, item shape,
self-describing actions and per-entity payloads.
Note: this changes only the search render path, not search matching. Live
streams missing from results are a stale streams FULLTEXT index on the DB
(rebuild with `ALTER TABLE streams ENGINE=InnoDB`), unrelated to this change.
84 lines
3.9 KiB
Markdown
84 lines
3.9 KiB
Markdown
# Search JSON contract
|
|
|
|
Goal: the `search` endpoint returns **structured data**, not server-rendered HTML, so the new design (and any future client) renders cards itself. Permission checks, status resolution, category/server lookups stay server-side; only markup moves to the client.
|
|
|
|
Endpoint: `?action=search` ({@see \XcVm\Public\Controllers\Admin\Ajax\SearchAjaxController}). The client renderer is `src/Public/assets/admin/js/search.js` (`renderSearchItem(item)`), wired into the Select2 quick-search box in `common.js`.
|
|
|
|
## Envelope
|
|
|
|
```jsonc
|
|
{ "result": true, "total_count": 12, "items": [ Item, … ] }
|
|
```
|
|
|
|
## Item (common)
|
|
|
|
```jsonc
|
|
{
|
|
"id": "streams#512", // stable identity (kept for Select2)
|
|
"url": "stream_view?id=512",// primary navigation target
|
|
"text": "CNN HD", // plain label (kept for Select2 matching)
|
|
"entity": "stream", // stream|movie|channel|radio|episode|series|user|line|mag|enigma
|
|
"data": { … } // entity-specific payload (below)
|
|
}
|
|
```
|
|
|
|
Every `data.actions[]` entry is **self-describing** so the client needs no per-action logic:
|
|
|
|
```jsonc
|
|
{ "kind": "navigate", "target": "movie?id=512", "icon": "mdi-pencil", "title": "Edit" }
|
|
{ "kind": "api", "entity": "stream", "sub": "stop", "icon": "mdi-stop", "title": "Stop", "enabled": true }
|
|
{ "kind": "fingerprint", "id": 512, "context": "stream", "icon": "mdi-fingerprint", "enabled": true }
|
|
{ "kind": "credits", "id": 5, "icon": "mdi-coin", "title": "Add credits" }
|
|
```
|
|
`kind` → client call: `navigate(target)` · `searchAPI(entity,id,sub)` · `modalFingerprint(id,context)` · `addCredits(id)`. `enabled:false` renders a disabled button.
|
|
|
|
## data by entity
|
|
|
|
### stream / movie / channel / radio / episode
|
|
```jsonc
|
|
{
|
|
"layout": "live" | "vod",
|
|
"title": "CNN HD", "title_link": "stream_view?id=512" | null,
|
|
"category": "News (+2)",
|
|
"server": "EU-1 (+1)" | "",
|
|
"image": { "url": "cnn.png", "size": 96 }, // live 96 (stream_icon) / vod 512 (movie_image)
|
|
"badge": { "text": "STREAM", "variant": "success" },
|
|
"connections": 128, "connections_link": "live_connections?stream_id=512",
|
|
"status": { "kind": "uptime", "text": "01h 02m 03s" }
|
|
| { "kind": "progress", "percent": 42 }
|
|
| { "kind": "status", "code": 5, "label": "DIRECT", "variant": "purple" },
|
|
"rating": { "stars_full": 3, "half": true, "empty": 1, "year": "2021" } | null, // movies
|
|
"actions": [ Action, … ]
|
|
}
|
|
```
|
|
|
|
### series
|
|
```jsonc
|
|
{ "title": "Breaking Bad", "category": "Drama", "image": {"url":"cover.jpg","size":512},
|
|
"rating": {"stars_full":4,"half":false,"empty":1,"year":"2008"},
|
|
"badge": {"text":"TV SERIES","variant":"danger"}, "seasons": 5, "episodes": 62,
|
|
"actions": [ … ] }
|
|
```
|
|
|
|
### user
|
|
```jsonc
|
|
{ "username":"reseller1", "group":"Resellers", "owner":"admin", "is_reseller":true, "credits":1000,
|
|
"status":{"label":"Active","variant":"info"}, "users_count":12, "lines_count":340,
|
|
"badge":{"text":"USER","variant":"warning"}, "actions":[ … ] }
|
|
```
|
|
|
|
### line / mag / enigma
|
|
```jsonc
|
|
{ "title": "line123" | "AA:BB:CC:…", // username for line, mac for device
|
|
"device_type": "mag" | "enigma" | null,
|
|
"status": {"label":"Active"|"Banned"|"Disabled","variant":"info"|"danger"|"warning"},
|
|
"owner": "admin", "expires": "2025-01-01 00:00:00" | null,
|
|
"last_active": {"online":true,"stream_id":512,"stream_name":"CNN","online_for":"01h 00m 00s"}
|
|
| {"online":false,"date":"2024-12-01 10:00:00"|null},
|
|
"connections": 5, "flags": {"restreamer":false,"trial":true},
|
|
"badge": {"variant":"pink"}, "actions":[ … ] }
|
|
```
|
|
|
|
## Status codes (streams)
|
|
Server resolves `$rActualStatus` (-1…10) exactly as today; label + variant are derived from the existing `$rSearchStatusArray` constant, so they stay the single source of truth. Codes `1` (running → uptime) and `6` (created-channel encode → progress) are special-cased into the `uptime` / `progress` kinds.
|