mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 22:03:13 -06:00
The dashboard offered every control to every display, so on a Tizen panel the volume
slider and screen_off did nothing and read as bugs. Two of them were genuinely dead:
- set_volume fell through STDeviceControl.run()'s default case and was answered
"unknown command". It is not a Samsung fleet action and must work on every build,
so it is handled in app.js instead: tizen.tvaudiocontrol where the TV profile
provides it (that is the TV's own volume, the only thing that reaches AVPlay video
on the hardware plane), otherwise the media elements. The level is remembered and
re-applied on 'play' — media elements are created per item, so a one-shot set
lasted only until the playlist advanced.
- screen_off was a z-index overlay, which covers the web layer only. Portrait and
flipped video runs through AVPlay on a separate hardware plane the DOM cannot draw
over, so the overlay went up and the video played straight through it. It now tears
the AVPlay session down as well; screen_on re-mounts via playCurrent(), because a
torn-down session cannot be resumed and gotoIndex() early-returns on an unchanged
index.
js/capabilities.js declares the rest at runtime rather than from a static table,
because on Tizen the answer varies by build: reboot exists only through the B2B
surface injected on a partner-signed .wgt, and tizen.tvaudiocontrol is absent in a
browser context. Against the server baseline this adds display.power, remote.screenshot
and remote.stream (all backed by real handlers) and drops offline.cache — the payload
is cached, but media bytes are still fetched from the network, so content does not
survive an outage and claiming it would overstate.
Adds the tv.audio privilege; without it tvaudiocontrol throws SecurityError.
95 lines
4.9 KiB
JavaScript
95 lines
4.9 KiB
JavaScript
/* ScreenTinker — Tizen capability declaration.
|
|
*
|
|
* The dashboard used to offer every control to every display, so buttons a platform cannot honour
|
|
* did nothing and read as bugs. The player now DECLARES what it can actually do
|
|
* (server/lib/player-capabilities.js holds the vocabulary) and the frontend hides the rest.
|
|
*
|
|
* Declared at RUNTIME rather than from a static table, because on Tizen the answer genuinely
|
|
* varies by build and panel:
|
|
* - reboot and real panel power exist only through webapis.systemcontrol / b2bapis.b2bcontrol,
|
|
* which are injected ONLY on a Samsung panel running a .wgt signed with a Partner distributor
|
|
* certificate. The same code on an unsigned dev build, the URL-Launcher path, or a consumer TV
|
|
* has no such surface (see device-control.js).
|
|
* - tizen.tvaudiocontrol is a TV-profile API; it is absent in a plain browser context.
|
|
* A hardcoded list would claim these on every Tizen device and be wrong on most of them.
|
|
*
|
|
* ⚠️ Names must match server/lib/player-capabilities.js exactly. An unknown string is DROPPED by the
|
|
* server's parser, so a typo silently removes a control rather than failing loudly.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
/* Native TV audio. Present on the TV profile; absent in a browser/URL-Launcher context, which is
|
|
* why this is probed rather than assumed. */
|
|
function tvAudio() {
|
|
return (window.tizen && tizen.tvaudiocontrol && typeof tizen.tvaudiocontrol.setVolume === 'function')
|
|
? tizen.tvaudiocontrol : null;
|
|
}
|
|
|
|
/* The Samsung fleet-control surface, via the module that already owns those probes. Re-asked on
|
|
* every call because the platform can inject these objects after the first script pass. */
|
|
function fleet() {
|
|
try { return window.STDeviceControl ? window.STDeviceControl.capabilities() : null; }
|
|
catch (e) { return null; }
|
|
}
|
|
|
|
function detect() {
|
|
var caps = [
|
|
// Playback surface — all implemented in player.js on every Tizen build.
|
|
'playback.video', 'playback.image', 'playback.widget', 'playback.youtube',
|
|
'playback.zones', 'playback.transitions', 'playback.pip',
|
|
|
|
// Per-item mute, honouring the shared rule in server/lib/media-mute.js (including the
|
|
// YouTube embed, which used to be hardcoded muted and unmutable).
|
|
'audio.mute',
|
|
|
|
// Volume always resolves to SOMETHING: the native TV control where the profile provides it,
|
|
// otherwise the media elements. Both change what a viewer hears, so the control is honest.
|
|
'audio.volume',
|
|
|
|
// CSS for graphics, and AVPlay's setDisplayRotation for portrait/flipped video — the Tizen
|
|
// HTML5 <video> sits on a hardware plane that ignores CSS rotate.
|
|
'display.rotation',
|
|
|
|
// Blanking works on every build: a real panel API where one exists, and otherwise the black
|
|
// overlay PLUS hardware-plane teardown (app.js showScreenOff). Declared because the screen
|
|
// genuinely goes dark either way — hiding a working control is the opposite failure to the
|
|
// one this whole model exists to fix. Which mechanism ran is reported in the device log.
|
|
'display.power',
|
|
|
|
// Images capture for real; video and YouTube return an honest status card saying live preview
|
|
// is unavailable on this platform. Declared because the operator gets a truthful frame rather
|
|
// than a dead button.
|
|
'remote.screenshot', 'remote.stream', 'remote.input',
|
|
|
|
// location.reload() — the URL-Launcher path also re-pulls content this way.
|
|
'system.restart_player',
|
|
|
|
// Clock/schedule-derived group sync, no leader.
|
|
'sync.clock'
|
|
];
|
|
|
|
var f = fleet();
|
|
// Only on a partner-signed panel with the B2B/system surface present.
|
|
if (f && f.reboot) caps.push('system.reboot');
|
|
|
|
// NOT declared, deliberately, each for a concrete reason:
|
|
// display.resolution — no web-accessible mode setting on the TV profile.
|
|
// system.self_update — a .wgt is installed by the panel, not by the app; there is no
|
|
// in-app OTA (device-control.js reports the same).
|
|
// system.kiosk — Tizen has no device-owner equivalent reachable from a web app.
|
|
// system.brightness / system.screen_timeout / system.time / system.install_apk /
|
|
// system.shell — no substantiated API on this surface. Claiming them would put back
|
|
// exactly the dead buttons this change removes.
|
|
// sync.native — no cross-player frame sync (that is BrightSign's SyncManager).
|
|
// offline.cache — app.js caches the PAYLOAD so a reboot during an outage replays the
|
|
// last playlist, but the media bytes are still fetched from the
|
|
// network. Content does not survive an outage, so claiming offline
|
|
// capability would overstate it.
|
|
|
|
return caps;
|
|
}
|
|
|
|
window.STCapabilities = { detect: detect, tvAudio: tvAudio };
|
|
})();
|