mirror of
https://github.com/screentinker/screentinker.git
synced 2026-08-13 13:53:12 -06:00
Two halves of the same problem. A screen has to keep playing when the link is gone, and it must not keep playing the wrong thing once the link is back. CACHING FOR OFFLINE, on the players that could not: - Tizen cached nothing but the playlist, so a panel came back from a reboot knowing exactly what to show and fetched every frame of it from a server that was not there. tizen/js/media-cache.js caches the media itself to wgt-private (the store Tizen documents as surviving reboots), resumable via Range and If-Range, with the transfer async so a stalled chunk cannot freeze the player. offline.cache moves from "absent" to a runtime claim: a build with no writable private storage still says nothing. - The web player's worker stored only what a single fetch() happened to complete, which on a marginal link is nothing at all — a 200MB asset never finishes in one go and every retry starts from zero. It now accumulates in resumable chunks, driven by the player's playlist rather than by playback, so the prefetch is not competing with the video that is currently on screen for the same scarce bandwidth. BrightSign inherits this. STILL UPDATING, which caching quietly breaks: PUT /api/content/:id/replace changes an asset's bytes under a stable id. Every cache keys on that id, so before this the new bytes could not reach a panel that already held the old ones — not until the next refresh, but never. Content now carries a revision, stamped onto each item at send time like widget revs, and every player keys its cache on it. The same send-time refresh fixes a second bug: a replace writes a new randomly-named file and unlinks the old one, so the filepath in a published snapshot pointed at a deleted file and web panels 404'd on the item until somebody republished the playlist. The route now also pushes to affected devices, which it never did. Bytes are kept only where they can be built upon: no validator means no safe resume, so the partial is discarded and the attempt backs off as the failure it is rather than re-fetching the same prefix forever. Server needed no new transfer support — res.sendFile already does Range, If-Range and 416. The Tizen cache and the service worker are both driven in Node against fakes, because neither can be exercised without hardware and "the chunks assemble correctly" is not something to discover from a panel showing a corrupt video. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL
47 lines
2.8 KiB
XML
47 lines
2.8 KiB
XML
<?xml version="1.0" encoding="UTF-8"?>
|
|
<widget xmlns="http://www.w3.org/ns/widgets" xmlns:tizen="http://tizen.org/ns/widgets"
|
|
id="http://screentinker.com/player" version="1.9.29" viewmodes="maximized">
|
|
<tizen:application id="ScrnTinkr1.ScreenTinker" package="ScrnTinkr1" required_version="2.4"/>
|
|
<tizen:profile name="tv"/>
|
|
<name>ScreenTinker</name>
|
|
<author email="support@screentinker.net">ScreenTinker</author>
|
|
<description>ScreenTinker digital signage player</description>
|
|
<icon src="icon.png"/>
|
|
<content src="index.html"/>
|
|
|
|
<!-- Landscape signage, no context menu, allow background, keep app full-screen -->
|
|
<tizen:setting screen-orientation="landscape" context-menu="disable"
|
|
background-support="enable" encryption="disable"
|
|
install-location="auto" hwkey-event="enable"/>
|
|
|
|
<feature name="http://tizen.org/feature/screen.size.all"/>
|
|
|
|
<!-- Allow the player to reach any signage server + load remote media / YouTube -->
|
|
<access origin="*" subdomains="true"/>
|
|
<tizen:allow-navigation>*</tizen:allow-navigation>
|
|
|
|
<tizen:privilege name="http://tizen.org/privilege/internet"/>
|
|
<tizen:privilege name="http://tizen.org/privilege/application.launch"/>
|
|
<tizen:privilege name="http://tizen.org/privilege/display"/>
|
|
<!-- tizen.tvaudiocontrol: sets the TV's OWN volume, which is what reaches AVPlay video on the
|
|
hardware plane. Without this privilege the API throws SecurityError and the player falls
|
|
back to per-element media volume, which cannot touch that plane. -->
|
|
<tizen:privilege name="http://tizen.org/privilege/tv.audio"/>
|
|
<!-- Offline media cache (js/media-cache.js). Content is written to wgt-private, which is the
|
|
store Tizen documents as surviving reboots and app updates — without these the player can
|
|
hold a playlist through an outage but none of the media it points at, which from the floor
|
|
is the same as holding nothing. -->
|
|
<tizen:privilege name="http://tizen.org/privilege/filesystem.read"/>
|
|
<tizen:privilege name="http://tizen.org/privilege/filesystem.write"/>
|
|
<tizen:privilege name="http://developer.samsung.com/privilege/network.public"/>
|
|
|
|
<!-- #125: Samsung B2B fleet control (reboot / panel power via b2bcontrol /
|
|
systemcontrol). These are PARTNER-level privileges: they only take effect
|
|
when the .wgt is signed with a Samsung Partner distributor certificate on a
|
|
real SSSP panel. On unsigned / URL-Launcher / web / consumer-TV builds they
|
|
are ignored (not fatal) — the APIs are simply absent and device-control.js
|
|
reports "unsupported". -->
|
|
<tizen:privilege name="http://developer.samsung.com/privilege/b2bcontrol"/>
|
|
<tizen:privilege name="http://developer.samsung.com/privilege/systemcontrol"/>
|
|
</widget>
|