Add master display UI with audio output management and styling
- Implement main.js for the master display functionality, including WebSocket connection, audio output management, and state handling. - Create style.css for the master display's visual design, ensuring a cohesive look and feel with a dark theme and responsive layout. - Integrate device management with a fallback for non-Electron environments, allowing users to select audio outputs. - Add features for managing favorites, including toggling favorites and filtering by genre. - Enhance user experience with a responsive favorites grid and drag-to-scroll functionality.
This commit is contained in:
@@ -34,6 +34,12 @@ function runMigrations(db) {
|
||||
if (!stationCols.has('category')) {
|
||||
db.exec('ALTER TABLE stations ADD COLUMN category TEXT');
|
||||
}
|
||||
if (!stationCols.has('image_path')) {
|
||||
db.exec('ALTER TABLE stations ADD COLUMN image_path TEXT');
|
||||
}
|
||||
if (!stationCols.has('image_source')) {
|
||||
db.exec('ALTER TABLE stations ADD COLUMN image_source TEXT');
|
||||
}
|
||||
const streamCols = new Set(db.prepare("PRAGMA table_info(streams)").all().map((c) => c.name));
|
||||
if (!streamCols.has('uuid')) {
|
||||
db.exec('ALTER TABLE streams ADD COLUMN uuid TEXT');
|
||||
@@ -55,5 +61,15 @@ function runMigrations(db) {
|
||||
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_stations_uuid ON stations(uuid)');
|
||||
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_streams_uuid ON streams(uuid)');
|
||||
db.exec('CREATE INDEX IF NOT EXISTS idx_stations_category ON stations(category)');
|
||||
|
||||
// station_plays gained session/listen-time aggregates so the leaderboard
|
||||
// can rank by actual playtime, not just play-button taps.
|
||||
const playCols = new Set(db.prepare("PRAGMA table_info(station_plays)").all().map((c) => c.name));
|
||||
if (!playCols.has('sessions')) {
|
||||
db.exec('ALTER TABLE station_plays ADD COLUMN sessions INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
if (!playCols.has('total_play_ms')) {
|
||||
db.exec('ALTER TABLE station_plays ADD COLUMN total_play_ms INTEGER NOT NULL DEFAULT 0');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -30,6 +30,8 @@ CREATE TABLE IF NOT EXISTS stations (
|
||||
genres TEXT, -- JSON array
|
||||
description TEXT,
|
||||
image_url TEXT,
|
||||
image_path TEXT, -- relative path under data/images, e.g. "stations/12.jpg"
|
||||
image_source TEXT, -- 'remote' | 'scraped' | 'upload'
|
||||
source TEXT NOT NULL CHECK (source IN ('seed','radiobrowser','manual')),
|
||||
source_ref TEXT,
|
||||
category TEXT,
|
||||
@@ -93,8 +95,43 @@ CREATE INDEX IF NOT EXISTS idx_votes_station ON station_votes(station_id);
|
||||
|
||||
-- Aggregate play counter. Cheaper than COUNT(*) over play_history every render
|
||||
-- and lets anonymous/public listing show play counts without exposing history.
|
||||
-- `total_play_ms` and `sessions` accumulate from closed play_history rows so
|
||||
-- the leaderboard can rank by actual listen time, not just play-button taps.
|
||||
CREATE TABLE IF NOT EXISTS station_plays (
|
||||
station_id INTEGER PRIMARY KEY REFERENCES stations(id) ON DELETE CASCADE,
|
||||
plays INTEGER NOT NULL DEFAULT 0,
|
||||
sessions INTEGER NOT NULL DEFAULT 0,
|
||||
total_play_ms INTEGER NOT NULL DEFAULT 0,
|
||||
last_played_at TEXT
|
||||
);
|
||||
|
||||
-- Named listening rooms. One "display" client + many controller/panel clients
|
||||
-- per room share state (now-playing, volume, votes). A personal room is
|
||||
-- auto-provisioned per user so single-user kiosks Just Work.
|
||||
CREATE TABLE IF NOT EXISTS rooms (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
slug TEXT NOT NULL UNIQUE,
|
||||
name TEXT NOT NULL,
|
||||
created_by INTEGER REFERENCES users(id) ON DELETE SET NULL,
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS room_members (
|
||||
room_id INTEGER NOT NULL REFERENCES rooms(id) ON DELETE CASCADE,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
role TEXT NOT NULL DEFAULT 'member' CHECK (role IN ('owner','member','guest')),
|
||||
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
PRIMARY KEY (room_id, user_id)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_room_members_user ON room_members(user_id);
|
||||
|
||||
-- Last-known playback state per room. Persisted so clients reconnecting see
|
||||
-- the same now-playing card immediately, even after a server restart.
|
||||
CREATE TABLE IF NOT EXISTS room_state (
|
||||
room_id INTEGER PRIMARY KEY REFERENCES rooms(id) ON DELETE CASCADE,
|
||||
station_id INTEGER REFERENCES stations(id) ON DELETE SET NULL,
|
||||
playing INTEGER NOT NULL DEFAULT 0,
|
||||
volume REAL NOT NULL DEFAULT 0.7,
|
||||
updated_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user