ScreenTinker v2.4 - open-source digital signage, now with one-click updates and HQ/store playlist control

ScreenTinker v2.4 - open-source digital signage, now with one-click updates and HQ/store playlist control

ScreenTinker v2.4 - open-source digital signage, now with one-click updates and HQ/store playlist control

Dev here. ScreenTinker is a self-hostable signage CMS (Node/Express/SQLite, MIT, Docker image on ghcr). v2.4 is out:

- Update Now from the dashboard - a separate root-owned updater backs up and integrity-checks the DB, installs, restarts, verifies the new version answers, and rolls back (DB included) if it doesn't. Works for git installs (systemd path unit) and Docker (docker:cli sidecar). Never automatic.

- Head office playlists - mandate content org/workspace/group/screen-wide, with local slots store managers can fill.

- Smart playlists - rule-based, self-updating from your content library.

- Interactive kiosk mode for web pages - idle timeout wipes cookies/storage/history between visitors.

- Fixes from an internal security audit: tenant isolation, stored XSS in the dashboard, CSP sandboxing for HTML bundles, upload/deletion integrity.

- Native Pi installer fixes (Lite vs Desktop detection).

Players: Android/Fire TV (now in the Amazon Appstore), Tizen, webOS, BrightSign, Pi, Windows, browser.

Shoutout to visimpres-glitch for the Android temp telemetry PR and a pile of well-diagnosed issues, and to bwcgn, r00ks and JackyL for the Pi reports.

https://github.com/screentinker/screentinker/ | https://discord.gg/utTdsrqq4Z

u/dw5304 — 9 days ago

ScreenTinker 2.2 - self-hosted digital signage that now speaks MCP, so you can point an AI assistant at your own screens

ScreenTinker 2.2: MCP on your own server

I maintain ScreenTinker, an MIT-licensed digital signage server you run yourself. Point it at any TV, Pi, old Android box, or browser and you get a managed screen. No per-screen fees. No cloud. The players talk to your server.

2.2 is mostly one change: every instance now serves a Model Context Protocol endpoint at /mcp.

Point Claude, or anything that speaks MCP, at your own server with an API token and ask in plain English:

> "Which of my screens are offline?"
> Staff Room is offline, last heartbeat 1h ago, reason "silent". The other four are online.

> "Put the autumn campaign on the lobby screen."
> It finds the display, builds the playlist, publishes it, assigns it.

What I actually care about: the MCP layer is a client of your public API, not a second door into the database. Every tool call is an HTTP request with your token, through the same workspace isolation and rate limits a curl script would hit. There is no second permission model to drift out of step with the first.

The tool list is filtered by token scope. A read-only token sees 10 tools. A full token sees 21. The read-only token is never even told the write tools exist, so an assistant holding one doesn't burn turns discovering what it may not do. Twenty-one tools, chosen by hand, not generated from the 133-operation spec, because a model gets worse at picking the right one as the list grows.

An assistant cannot issue itself a token. A human makes one in the dashboard. The auth guide says so in the first paragraph, which stops an agent from hunting for a registration endpoint that doesn't exist and treating every 401 as "my token is wrong."

Also in 2.2

  • Markdown renditions of every public page (Accept: text/markdown, or append .md), an RFC 9727 API catalogue at /.well-known/api-catalog, and an auth guide written for something that reads rather than clicks.
  • E-paper / ESP32 signs, documented. The server dithers the image to the colours the panel actually has, packs it for the controller, and tells the board how long to deep sleep. No browser on the device.
  • Eleven platforms, each with a setup guide, and a /download page built from the players your instance actually has. If it has none, it says so instead of offering a dead link.
  • Apple TV is documented as not supported, with the reasoning, because people keep asking.
  • Device-side HTTP requests and a LAN control door for Crestron/AMX. Both are API-only right now. No dashboard page yet. The video says so rather than pretending otherwise.

Honest bit. Pointing an assistant at a real instance and reading what came back found three bugs in my own new feature:

  1. The media-library tool returned items with no names and its search matched nothing, which reads as "your library is empty" rather than as a fault.
  2. Renaming a screen sent back the whole device row, including its settings PIN.
  3. Asking for a week of uptime returned nothing for a valid date range. That was a date-parsing bug that had been silently skewing reports by the server's UTC offset on every self-hosted instance outside UTC.

All fixed in 2.2.1, which is out now. Reading the payload instead of the status code is the whole lesson.

GitHub: https://github.com/screentinker/screentinker
Docs / demo: https://screentinker.com

Disclosure: I'm the developer. Happy to answer anything, including what it doesn't do.

youtu.be
u/dw5304 — 19 days ago
▲ 11 r/BrightSign+1 crossposts

ScreenTinker 2.0.0 is out (MIT, self-hosted)

ScreenTinker 2.0.0 shipped last night.

It’s an open-source, self-hosted digital signage CMS. MIT. Node + SQLite. Same project as before - this is the 2.0 cut.

Already in 1.9.x

  • Playlists with draft/publish
  • Group scheduling and group playlist assignment
  • Multi-zone layouts and video walls
  • Android / Fire TV player, Pi, browser, Tizen, webOS
  • Offline playback if the server drops
  • Remote control, live screenshots, kiosk mode
  • Widgets, proof-of-play, OTA to players
  • Workspaces / multi-user

New in 2.0.0

  • Slides - template and fields stay separate, fonts travel with the slide
  • Triggers - HTTP/UDP, resolved on the player so an override still works if the WAN is down
  • Node mesh - server-to-server federation, off unless you turn it on
  • BrightSign player, and the server can run on a BrightSign version 5 or higher on bsos 10
  • Proof-of-play that queues through an outage and flushes on reconnect
  • Playlist inheritance that forks instead of overwriting the group playlist

Upgrade from 1.9.x is a normal upgrade. Migrations run on first boot.

Release notes: https://github.com/screentinker/screentinker/releases/tag/v2.0.0

Repo: https://github.com/screentinker/screentinker

If you’re running it, tell me what broke or what else is needed.

https://reddit.com/link/1w3zjka/video/6cxrjyxu6umh1/player

reddit.com
u/dw5304 — 1 month ago

ScreenTinker v1.9.13 - GPU transitions on Android/Tizen/web, live PiP overlays, group sync, proof-of-play, and an agency upload portal

Hey r/digitalsignage,

Quick disclosure up front: I'm the developer of ScreenTinker. It's MIT and open source, and I also run a paid hosted version of it, so treat me as a vendor here. Posting this as a release update under rule 8.

Back in June I posted v1.8 here and a bunch of you told me what was still missing. Most of this release came straight out of that thread and the issues that followed it - the agency portal (#73), dayparting and auto-expire (#74, #75), Android 7 panel support (#141), the OTA re-download loop (#139), and a pile of others are all things people here asked for. So thanks for that.

Since then: 14 point releases, 260 commits, 94 of them bug fixes. MIT, self-hostable, and there's no per-device player licence.

This got long because it's been six weeks. Skim the bold bits.

The big ones:

  • A real transition engine. 14 GLSL shaders running on web, Tizen, and Android off the same shader source. Image to image, image to video, video to video. It's all GLSL ES 1.0, so it runs unmodified on WebGL1 and Android GLES2 - which is the whole point. Fancy transitions are easy on a gaming laptop. Getting them to run on a $40 stick is the hard part. Every failure path hard-cuts instead of flashing black: lost GL context, throttled rAF on a backgrounded tab, bad shader, GPU that just can't keep up. You get an instant cut, never a blank screen. This is the piece I want torn apart the most, so if you've got a panel where it stutters, tell me the model.
  • PiP overlays. Push an image or a web overlay onto a single device or a whole group, live, on top of whatever's already playing. No playlist edit, no republish. This is the feature I've had the most fun with, and there are 14 open-source example recipes in the repo to show what it's for: news ticker, room-status calendar, QR rotator, event countdown, fundraiser thermometer, incident webhook, crypto ticker, announcement broadcast. The one I'd point at first is the weather radar overlay - a TV-news-style animated radar with live NWS warning polygons that runs in on_warning mode, so it sits dormant and only cuts to radar when a qualifying warning actually covers your location, then clears itself when the warning expires. Keyless, zero Node dependencies, Leaflet vendored locally. If you run screens anywhere weather matters, that one's worth a look on its own.
  • Group sync. A group's shared playlist now plays in lockstep across every display in it - items start and end together. Clock and schedule driven, so it's offline-native and doesn't fall apart when the network hiccups. Leader is auto-elected with an optional pin, and it re-elects if the leader drops. Built on the video-wall sync primitive with the spatial transform removed, so it's the same code path that was already proven on walls.
  • Agency portal. This one came from a feature request in the v1.8 thread and turned into the biggest chunk of work in the release. If you manage screens for clients: you issue a scoped token that lives completely off the normal role ladder, and you designate exactly which playlists it can touch. The agency gets a standalone upload page. No account in your CMS, no view of your device list, no way to wander outside their grant. Plus optional per-token auto-publish, per-token upload folders that auto-create and stay confined to their subtree, size guidance so they stop sending 4K vertical for a 1280x360 L-bar, and a batched email digest when they drop new assets.
  • Proof-of-play on Android and Tizen, not just the web player. Per-content and per-device, hourly and daily breakdowns, CSV export. If you're running ad inventory and need to hand someone a verification report, it's there now.

Android and Tizen mostly caught up to the web player:

This was the other big theme. Features that used to be web-only now work on real signage hardware.

  • Video walls on Android (wall:sync), and video walls plus multi-zone layouts on Tizen. Both were web-only in v1.8.
  • Samsung SSSP install, so you can deploy to commercial panels without sideloading, plus real Samsung B2B fleet control. Fair warning: the SSSP path is built but I'm still waiting on the partner cert from Samsung, so it isn't live yet. The unsigned route (point the TV's browser/URL launcher at your instance's /player) works today, same as it did in v1.8.
  • .wgt lifecycle parity on Tizen - keep-awake re-assert, suspend/resume handling, an app-level liveness watchdog.
  • minSdk dropped from 26 to 24, so Android 7.0 and 7.1 panels work now. If you've got a drawer of cheap older hardware, it's usable again.
  • Per-item mute that actually persists, ships to the device, and toggles in real time.
  • Multi-zone layouts composite correctly in screenshot capture instead of grabbing one zone.

Directory boards got a real pass, and a search widget to go with them:

The board widget shipped in v1.8, but it needed work, so: JSON/CSV import so you're not hand-typing 200 tenants, logo-replaces-title, panel-ring scroll with in-place refresh (edit an entry and it updates without the board restarting its scroll from the top), a per-device frame diagnostic, and fixes for the scroll stutter and the black flicker between boards. New this release is a directory-search widget - an interactive companion that live-syncs with a board. Put a touchscreen next to your lobby directory and people can search it instead of standing there waiting for the scroll to come back around to their name.

Security:

  • TOTP 2FA with encrypted secrets, hashed recovery codes, and verify lockout.
  • Email verification on signup.
  • Scoped API tokens with secure-by-exclusion mounts - a route is private unless it's explicitly published, rather than the other way around.

Device management, mostly born of actual pain:

  • Re-adopt. Delete a screen, re-pair it, and its settings come back. Fingerprint-keyed, so a reinstalled panel reclaims its own row instead of showing up as a stranger. This was a real customer bug and it drove me nuts for a week.
  • Hidden settings menu on Android behind a multi-tap and a PIN, so nobody at the venue reconfigures your screen for you.
  • OTA kill switch - global, per-device, and auto-detected when the device is MDM-managed. Plus a fix for the OTA re-download loop on devices that can't silently install.
  • Device-owner tier + QR provisioning for fleet setup, and Tier 0/1 system controls that work with no device-owner dependency at all.
  • Liveness contract v4 across server, APK, .wgt and the web player - uniform heartbeat-ack, throttle-aware watchdogs, and a 3-state liveness badge on the dashboard instead of a binary online/offline lie.
  • App-ending signal, so when a player exits you get a reason instead of a mystery, surfaced as an annotation and a filter you can drill into.
  • Device incident log. Tells you why a screen dropped: network loss vs. reboot vs. the display going to sleep. I built this because I got tired of the dashboard saying "offline" with no next question.
  • Version indicator + update check on the dashboard so you know when you're behind.

Content library got a pass:

Multi-file upload, multi-select with batch delete and move, server-side search + type filter + sort (so a 5,000-item library doesn't melt the browser), subtitle and caption tracks as a content property, YouTube Shorts rendering in 9:16 instead of a letterboxed landscape frame, and an unstable-connection mode that caps YouTube at 720p for screens sitting on bad venue WiFi.

Scheduling, playlists, dashboard:

Per-item schedule blocks, so dayparting and auto-expire work at the item level instead of only the playlist. Duplicate and replace playlist items in place. Draft-aware playlist preview that runs without assigning a device to it. Drag-to-reorder display tiles. Designer-made widgets are editable back in the designer.

Self-hosting and ops:

Debian 13 install script for player and server. SMTP as an alternative to Microsoft Graph for email, so you're not forced into a Microsoft tenant to send alerts. A HIDE_BILLING flag for self-hosters who don't want to look at subscription UI. Event-loop lag telemetry and throughput counters on /api/status for anyone who wants to actually watch their instance under load. 7 UI languages.

Runs on Android TV, Fire TV, Tizen, webOS, Amazon Vega OS, Raspberry Pi, Windows, ChromeOS, or any browser.

GitHub: https://github.com/screentinker/screentinker Discord: https://discord.gg/utTdsrqq4Z

Same ask as last time - tear it apart. The transitions are the thing I'm least sure about across weird hardware, so if you've got an odd panel and five minutes, I'd love a model number and a "yeah it stuttered."

And the question I'll actually act on: what's still keeping you from using this in production?

reddit.com
u/dw5304 — 3 months ago

ScreenTinker v1.8 - two months after launching here: Docker, Samsung Tizen player, AI content designer, and everything else you asked for

Hey r/digitalsignage,

Two months ago I launched ScreenTinker here - an open-source (MIT) digital signage CMS - and this sub gave it the best reception I could have hoped for. Real feedback, real architectural criticism, and real users. A bunch of you filed issues, and most of what shipped since then came directly from those.

Today I tagged v1.8, and it felt right to come back to the sub where this started and share what's changed.

The big ones:

  • Docker. This was the number one ask at launch and it's done properly: multi-arch images at ghcr.io/screentinker/screentinker, built by CI, tagged per release. There's also a tag-based upgrade flow with an upgrade.sh for the bare-metal folks.
  • Samsung Tizen TV player. New native web player (.wgt) for Tizen TVs. You can sign it with your own Samsung cert, or skip signing entirely and just point the TV's browser/URL launcher at your instance's /player. That brings the platform count to Android TV, Fire TV, Raspberry Pi, Windows, ChromeOS, LG webOS, Samsung Tizen, and any browser.
  • AI Content Designer. Describe a sign, get a layout - backgrounds, foreground images, text placement. The part I think this sub will actually care about: it's bring-your-own-endpoint. Point it at OpenAI, a local model, whatever you run. No required cloud dependency, no per-generation fees to me, and there's a local AI setup guide in the docs.
  • A real release pipeline. CI with unit tests and boot smoke tests, signed Android APKs, versioned tarballs, nightly backup script with point-in-time content history. The "v1, things will break" era is officially over - releases are now boring and reproducible, which is exactly what signage infrastructure should be.

Android player grew up a lot:

  • OTA updates now verify the APK signature before install, and kiosk devices auto-confirm updates (no more walking to a screen with a remote)
  • Reliable boot-launch including Android TV
  • Android 14+ compliance fixes (MediaProjection / foreground services)
  • The YouTube embed errors (152/153) that several people hit are fixed
  • Software orientation - portrait and flipped - on both the Android and web players, for all the menu boards mounted sideways out there

Multi-zone got meaningfully better:

  • Per-zone fit mode (contain/cover per zone)
  • Independent per-zone rotation
  • Widgets render in any zone now, not just dedicated widget zones
  • Atomic zone saves (no more template zone duplication)

For the MSP / multi-client crowd:

  • Normalized platform role model with a cross-org operator role, deny-by-default
  • Admin-provisioned users with a first-login gate, workspace membership management
  • Create/delete organizations with proper cascade
  • Instance-level default white-label branding

Security: I had the codebase reviewed and fixed everything it found, including a stored XSS in the public widget render. If you self-host, please update.

Same deal as before: MIT licensed, self-host for free forever (DISABLE_REGISTRATION flag is documented now too), hosted version exists if you don't want to run it. Single developer, so when you file an issue you're talking to the person who will fix it - usually that week, as the issue numbers in this changelog show.

Links:

To everyone from the launch thread who filed issues, joined the Discord, or put this in front of real screens: thank you. What should v1.9 focus on?

u/dw5304 — 4 months ago