Real first video page, reusing music's .dash-grid/.dash-card CSS for an identical look — but every value is driven by isolated video JS, no music code referenced. Sections mirror the music dashboard, adapted: - Service Status: Media Server / Download Client / Metadata Source - System Stats: swaps 'Active Syncs' -> 'Disk Usage'; keeps download/speed/ uptime/memory - Library: Movies / Shows / Episodes / Disk Size - Recent Syncs -> Recent Downloads (empty state for now) - Quick Actions: Add Movie/Show, Watchlist, Downloads (navigate via data-video-goto) - Recent Activity - No enrichment section, no header sweep animation (per plan) Mechanics: - #video-page-host now holds .video-subpage sections; controller toggles one at a time and falls back to #video-placeholder-slot for unbuilt pages. - video-side.js dispatches soulsync:video-page-shown; video-dashboard.js (new isolated IIFE) listens and applies a zeroed STUB until video.db exists. Single seam to swap for a real /api/video/dashboard fetch later. - All wiring via data-attrs + addEventListener; no inline onclick (keeps the script-split integrity contract intact). 73 tests green.
76 lines
2.7 KiB
JavaScript
76 lines
2.7 KiB
JavaScript
/*
|
|
* SoulSync — Video dashboard data layer.
|
|
*
|
|
* ISOLATION CONTRACT: like video-side.js this is a self-contained IIFE (no
|
|
* globals, no inline handlers, lives under static/video/ which the script-split
|
|
* integrity scan does not touch). It NEVER references music code, and music
|
|
* never references it.
|
|
*
|
|
* It owns only the *data* of the video dashboard — the markup lives in
|
|
* index.html and reuses music's .dash-card CSS for an identical look. It learns
|
|
* when the dashboard becomes visible by listening for the
|
|
* 'soulsync:video-page-shown' event that video-side.js dispatches (so the two
|
|
* modules stay decoupled — no direct calls between them).
|
|
*
|
|
* TODO(video.db): STUB_STATS below is a placeholder. Once the video database +
|
|
* its /api/video/dashboard endpoint exist, replace loadStats() with a fetch and
|
|
* feed the same shape through applyStats(). Nothing else here needs to change.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var DASHBOARD_ID = 'video-dashboard';
|
|
|
|
// Zeroed placeholder until the video DB is wired. Keys match the markup's
|
|
// data-video-stat attributes.
|
|
var STUB_STATS = {
|
|
'active-downloads': '0',
|
|
'finished-downloads': '0',
|
|
'download-speed': '0 KB/s',
|
|
'disk-usage': '--',
|
|
'uptime': '0m',
|
|
'memory': '--',
|
|
'movies': '0',
|
|
'shows': '0',
|
|
'episodes': '0',
|
|
'library-size': '--'
|
|
};
|
|
|
|
function applyStats(stats) {
|
|
var nodes = document.querySelectorAll('[data-video-stat]');
|
|
for (var i = 0; i < nodes.length; i++) {
|
|
var key = nodes[i].getAttribute('data-video-stat');
|
|
if (Object.prototype.hasOwnProperty.call(stats, key)) {
|
|
nodes[i].textContent = stats[key];
|
|
}
|
|
}
|
|
}
|
|
|
|
function loadStats() {
|
|
// TODO(video.db): replace with fetch('/api/video/dashboard') -> applyStats(json).
|
|
applyStats(STUB_STATS);
|
|
}
|
|
|
|
// Service "Test" buttons are inert until the video services exist. Mark them
|
|
// honestly rather than firing a no-op that looks broken.
|
|
var testWired = false;
|
|
function wireTestButtons() {
|
|
if (testWired) return;
|
|
testWired = true;
|
|
var buttons = document.querySelectorAll('[data-video-test]');
|
|
for (var i = 0; i < buttons.length; i++) {
|
|
(function (btn) {
|
|
btn.disabled = true;
|
|
btn.title = 'Coming soon — video services not configured yet';
|
|
})(buttons[i]);
|
|
}
|
|
}
|
|
|
|
function onPageShown(e) {
|
|
if (!e || e.detail !== DASHBOARD_ID) return;
|
|
wireTestButtons();
|
|
loadStats();
|
|
}
|
|
|
|
document.addEventListener('soulsync:video-page-shown', onPageShown);
|
|
})();
|