Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
190ade4
CAP WIP
vpetersson Dec 6, 2025
0b1c557
More tweaks
vpetersson Dec 6, 2025
d3ea3c4
Merge branch 'master' into cap
nicomiguelino Dec 26, 2025
47880db
chore(cap-alerting): add a `configVersion` field in `bun.lock`
nicomiguelino Dec 26, 2025
b3669f0
chore(cap-alerting): remove app IDs from manifest files
nicomiguelino Dec 26, 2025
3d51c1f
chore(cap-alerting): ignore generated JS and CSS files in Git
nicomiguelino Dec 26, 2025
3f0057f
chore(cap-alerting): change formatting rules
nicomiguelino Dec 26, 2025
b733519
chore(cap-alerting): add a `package.json` script for only checking fo…
nicomiguelino Dec 26, 2025
28f31e4
chore(cap-alerting): fix failures in CI checks
nicomiguelino Dec 26, 2025
e8893c1
refactor: add watch mode for build scripts in cap-alerting
nicomiguelino Dec 26, 2025
3c80359
chore(cap-alerting): reorganize fields in manifest files
nicomiguelino Dec 26, 2025
09d1a67
fix: improve Anywhere screen detection
nicomiguelino Dec 26, 2025
b6ab84b
chore(cap-alerting): refactor interface declarations into a separate …
nicomiguelino Dec 26, 2025
0d0f179
refactor: organize cap-alerting and improve code quality
nicomiguelino Dec 27, 2025
a573831
refactor(cap-alerting): consolidate demo_mode and test_mode into mode…
nicomiguelino Dec 27, 2025
437a3bd
refactor(cap-alerting): remove unused legacy code and orphaned fetcher
nicomiguelino Dec 27, 2025
04ad763
refactor(cap-alerting): extract fetching logic into new CAPFetcher class
nicomiguelino Dec 27, 2025
b3f186a
chore(cap-alerting): remove `.js` extension from imports
nicomiguelino Dec 27, 2025
efc6251
refactor(cap-alerting): extract parsing logic into dedicated parser m…
nicomiguelino Dec 27, 2025
86fb6b6
chore(cap-alerting): use `getSettingWithDefault` in `main.ts`
nicomiguelino Dec 27, 2025
ac14706
refactor: extract utility functions and improve settings handling
nicomiguelino Dec 27, 2025
9f4a659
refactor: rename audio_alert setting to mute_sound with inverted logic
nicomiguelino Dec 27, 2025
fa3f271
refactor: standardize manifest help_text structure
nicomiguelino Dec 28, 2025
fb72816
Merge branch 'cap' of github.com:Screenly/Playground into cap
nicomiguelino Dec 28, 2025
7011718
Merge branch 'master' into cap
nicomiguelino Dec 28, 2025
721f048
chore: start a local CORS proxy server when `bun run dev` runs
nicomiguelino Dec 28, 2025
2d4da43
chore(cap-alerting): set the default max alters to infinity
nicomiguelino Dec 28, 2025
cb021c7
Merge branch 'master' into cap
nicomiguelino Dec 29, 2025
4418cd8
Merge branch 'master' into cap
nicomiguelino Dec 31, 2025
a4da454
Merge branch 'master' into cap
nicomiguelino Jan 2, 2026
5e1f830
chore(cap-alerting): add a `prepare` hook in `package.json`
nicomiguelino Jan 2, 2026
303c30c
chore(cap-alerting): use `eslint` for linting code instead of `tsc`
nicomiguelino Jan 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
**/*.min.js
edge-apps/cap-alerting/
edge-apps/edge-apps-library/
edge-apps/powerbi-legacy/
edge-apps/powerbi-legacy/**
Expand Down
10 changes: 10 additions & 0 deletions edge-apps/cap-alerting/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
node_modules/
dist/
*.log
.DS_Store
mock-data.yml
instance.yml
bun.lockb
static/js/*.js
static/js/*.js.map
static/style.css
1 change: 1 addition & 0 deletions edge-apps/cap-alerting/.ignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules/
6 changes: 6 additions & 0 deletions edge-apps/cap-alerting/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"semi": false,
"singleQuote": true,
"printWidth": 100,
"trailingComma": "es5"
}
35 changes: 35 additions & 0 deletions edge-apps/cap-alerting/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# CAP Alerting Edge App

Display Common Alerting Protocol (CAP) emergency alerts on Screenly digital signage screens. Designed to work with [Override Playlist](https://developer.screenly.io/api-reference/v4/#tag/Playlists/operation/override_playlist) to automatically interrupt regular content when alerts are active.

## Settings

- **CAP Feed URL**: URL to your CAP XML feed
- **Refresh Interval**: Minutes between feed updates (default: 5)
- **Default Language**: Preferred language code (default: en)
- **Maximum Alerts**: Max alerts to display (default: 3)
- **Play Audio Alerts**: Enable audio playback from CAP `<resource>` elements with audio MIME types (default: false)
- **Offline Mode**: Use cached data when network unavailable
- **Test Mode**: Load bundled test CAP file
- **Demo Mode**: Show random demo alerts

## Audio Support

The app automatically detects and plays audio resources from CAP alerts when the "Play Audio Alerts" setting is enabled. Audio resources are identified by MIME types starting with `audio/` (e.g., `audio/mpeg`, `audio/wav`, `audio/ogg`). The audio player will attempt to autoplay when an alert is displayed, though browser autoplay policies may require user interaction in some cases.

## Nearest Exit Tags

Add tags to your Screenly screens (e.g., `exit:North Lobby`) to provide location-aware exit directions. The app substitutes `{{closest_exit}}` or `[[closest_exit]]` placeholders in alert instructions.

## Override Playlist Integration

This app is designed to use Screenly's [Override Playlist API](https://developer.screenly.io/api-reference/v4/#tag/Playlists/operation/override_playlist) to automatically interrupt regular content when alerts are active. Configure your backend to call the API when new CAP alerts are detected.

## Development

```bash
cd edge-apps/cap-alerting
bun install
bun run dev
bun test
```
709 changes: 709 additions & 0 deletions edge-apps/cap-alerting/bun.lock

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions edge-apps/cap-alerting/eslint.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import eslint from '@eslint/js'
import tseslint from 'typescript-eslint'

export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
{
languageOptions: {
parserOptions: {
project: true,
tsconfigRootDir: import.meta.dirname,
},
},
},
{
ignores: ['dist/', 'node_modules/']
}
)
16 changes: 16 additions & 0 deletions edge-apps/cap-alerting/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>CAP Alerting - Screenly Edge App</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="static/style.css" />
</head>
<body class="m-0 p-0 overflow-hidden">
<div id="app" class="w-full h-screen flex items-center justify-center">
<div id="alerts" class="w-full h-full flex flex-col"></div>
</div>
<script src="screenly.js?version=1"></script>
<script src="static/js/main.js"></script>
</body>
</html>
53 changes: 53 additions & 0 deletions edge-apps/cap-alerting/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "cap-alerting",
"version": "1.0.0",
"private": true,
"type": "module",
"scripts": {
"generate-mock-data": "screenly edge-app run --generate-mock-data",
"predev": "bun run generate-mock-data",
"dev": "run-p build:css:dev build:js:dev edge-app-server cors-proxy-server",
"cors-proxy-server": "bun ../blueprint/scripts/cors-proxy-server.ts",
"edge-app-server": "screenly edge-app run",
"build": "run-p build:css:prod build:js:prod",
"build:css:common": "bunx @tailwindcss/cli -i ./src/input.css -o ./static/style.css",
"build:css:prod": "bun run build:css:common -- --minify",
"build:css:dev": "bun run build:css:common -- --watch",
"build:js:common": "bun build src/main.ts --outdir static/js --target browser --format iife",
"build:js:prod": "bun run build:js:common",
"build:js:dev": "bun run build:js:common -- --watch",
"test": "bun test",
"test:unit": "bun test",
"test:watch": "bun test --watch",
"type-check": "tsc --noEmit",
"lint": "edge-apps-scripts lint --fix",
"format:common": "prettier src/ README.md index.html",
"format": "bun run format:common --write",
"format:check": "bun run format:common --check",
"deploy": "bun run build && screenly edge-app deploy",
"prepare": "cd ../edge-apps-library && bun install && bun run build"
},
"dependencies": {
"@photostructure/tz-lookup": "^11.3.0",
"country-locale-map": "^1.9.11",
"fast-xml-parser": "^5.3.2",
"offline-geocode-city": "^1.0.2"
Comment on lines +31 to +34
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The dependencies @photostructure/tz-lookup, country-locale-map, and offline-geocode-city are declared but not imported or used anywhere in the codebase. Consider removing these unused dependencies to reduce bundle size and maintenance overhead.

Suggested change
"@photostructure/tz-lookup": "^11.3.0",
"country-locale-map": "^1.9.11",
"fast-xml-parser": "^5.3.2",
"offline-geocode-city": "^1.0.2"
"fast-xml-parser": "^5.3.2"

Copilot uses AI. Check for mistakes.
},
"prettier": "../edge-apps-library/.prettierrc.json",
"devDependencies": {
"@eslint/js": "^9.39.1",
"@screenly/edge-apps": "workspace:../edge-apps-library",
"@tailwindcss/cli": "^4.0.0",
"@types/bun": "^1.3.3",
"@types/node": "^24.10.1",
"autoprefixer": "^10.4.22",
"bun-types": "^1.3.3",
"eslint": "^9.39.1",
"jiti": "^2.6.1",
"npm-run-all2": "^8.0.4",
"prettier": "^3.7.4",
"tailwindcss": "^4.1.17",
"typescript": "^5.9.3",
"typescript-eslint": "^8.48.1"
}
}
86 changes: 86 additions & 0 deletions edge-apps/cap-alerting/screenly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
syntax: manifest_v1
description: Display CAP emergency alerts on Screenly screens. Supports offline mode and uses screen tags (e.g., exit:North Lobby) to highlight the nearest exit.
icon: https://playground.srly.io/edge-apps/cap-alerting/static/cap-icon.svg
author: Screenly, Inc.
entrypoint:
type: file
ready_signal: true
settings:
cap_feed_url:
type: string
default_value: ''
title: CAP Feed URL
optional: true
help_text:
properties:
help_text: URL or relative path to a CAP XML feed. Leave blank to use demo mode.
type: string
schema_version: 1
language:
type: string
default_value: en
title: Default Language
optional: true
help_text:
properties:
help_text: Choose the preferred language when multiple info blocks exist (e.g., en, es, fr).
type: string
schema_version: 1
max_alerts:
type: string
default_value: Infinity
title: Maximum Alerts
optional: true
help_text:
properties:
help_text: Maximum number of alerts to display simultaneously.
type: number
schema_version: 1
mode:
type: string
default_value: production
title: Mode
optional: true
help_text:
properties:
help_text: Select the operation mode for the app.
options:
- label: Production
value: production
- label: Demo
value: demo
- label: Test
value: test
type: select
schema_version: 1
mute_sound:
type: string
default_value: 'false'
title: Mute Sound
optional: true
help_text:
properties:
help_text: Mute audio alerts from CAP resources. Not available for Screenly Anywhere.
type: boolean
schema_version: 1
offline_mode:
type: string
default_value: 'false'
title: Offline Mode
optional: true
help_text:
properties:
help_text: When enabled, avoid network fetches and use cached data.
type: boolean
schema_version: 1
refresh_interval:
type: string
default_value: '5'
title: Refresh Interval (minutes)
optional: true
help_text:
properties:
help_text: Time in minutes between feed updates.
type: number
schema_version: 1
86 changes: 86 additions & 0 deletions edge-apps/cap-alerting/screenly_qc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
---
syntax: manifest_v1
description: Display CAP emergency alerts on Screenly screens. Supports offline mode and uses screen tags (e.g., exit:North Lobby) to highlight the nearest exit.
icon: https://playground.srly.io/edge-apps/cap-alerting/static/cap-icon.svg
author: Screenly, Inc.
entrypoint:
type: file
ready_signal: true
settings:
cap_feed_url:
type: string
default_value: ''
title: CAP Feed URL
optional: true
help_text:
properties:
help_text: URL or relative path to a CAP XML feed. Leave blank to use demo mode.
type: string
schema_version: 1
language:
type: string
default_value: en
title: Default Language
optional: true
help_text:
properties:
help_text: Choose the preferred language when multiple info blocks exist (e.g., en, es, fr).
type: string
schema_version: 1
max_alerts:
type: string
default_value: Infinity
title: Maximum Alerts
optional: true
help_text:
properties:
help_text: Maximum number of alerts to display simultaneously.
type: number
schema_version: 1
mode:
type: string
default_value: production
title: Mode
optional: true
help_text:
properties:
help_text: Select the operation mode for the app.
options:
- label: Production
value: production
- label: Demo
value: demo
- label: Test
value: test
type: select
schema_version: 1
mute_sound:
type: string
default_value: 'false'
title: Mute Sound
optional: true
help_text:
properties:
help_text: Mute audio alerts from CAP resources. Not available for Screenly Anywhere.
type: boolean
schema_version: 1
offline_mode:
type: string
default_value: 'false'
title: Offline Mode
optional: true
help_text:
properties:
help_text: When enabled, avoid network fetches and use cached data.
type: boolean
schema_version: 1
refresh_interval:
type: string
default_value: '5'
title: Refresh Interval (minutes)
optional: true
help_text:
properties:
help_text: Time in minutes between feed updates.
type: number
schema_version: 1
Loading