Owner's manual
This is the documentation every Fortesonic license ships with — read it before you buy, use it after. If it isn't answered here, email us.
1. Installation & requirements
Fortesonic is built on a minimalist, high-performance flat-file philosophy. There is no installer wizard because none is needed.
- Zero database. No MySQL, PostgreSQL or Redis. All dynamic data comes from JSON APIs (AzuraCast, iTunes, Open-Meteo) at request time.
- No Node.js on the server. The frontend is pure vanilla JavaScript, CSS
and HTML — nothing to build, nothing to
npm install. - Plain PHP 8+. PHP is used only for shared includes and safe server-side cURL requests (which also solves CORS for you). HTTPS and the cURL extension are the only host requirements.
Install via FTP or cPanel
1. Unzip the downloaded package on your computer. 2. Open your FTP client (FileZilla) or cPanel File Manager. 3. Connect to your hosting and open the web root (public_html / www). 4. Drag and drop all files and folders into the web root. 5. Done. The site is live — now connect your stream (next section).
Works on ordinary shared hosting — if your host runs PHP 8+ with HTTPS, you're covered.

public_html and the site is live.2. Configuration
Almost everything is managed in a single file: js/app.js. You never need to
edit HTML or CSS to change your stream, station name, colors or features.
Where to find your AzuraCast data
- Now Playing API URL — log into your AzuraCast panel, open your
station dashboard and look for the “Now Playing API” link. It looks like
https://your-server.com/api/nowplaying/your_station. - Stream URLs — under Broadcasting → Mount Points, right-click the Download/Play button of a mount point and copy the link. Create multiple mount points (320/128/64 kbps) to enable the quality switcher.
const AppConfig = {
STREAM_URL: 'https://your-server.com/listen/station/radio.mp3',
API_URL: 'https://your-server.com/api/nowplaying/your-station',
COLORS: {
light: { background: '#f6f8f9', text: '#000000', /* ... */ },
dark: { background: '#20232e', text: '#ffffff', /* ... */ }
},
HISTORY_COUNT: 6, // Recently Played count
REFRESH_INTERVAL: 15000, // now-playing poll, ms
MAINTENANCE_MODE: false
};

Feature toggles
Turn whole features on or off with booleans in the same file:
- SHOW_MAP — the Global Reach listener map section.
- SHOW_REQUESTS — the Request a Track block, modal and footer action.
- SHOW_LISTEN_IN_PLAYER — downloadable player playlist links (.pls).
- CHAT_ASSISTANT_ENABLED — the listener assistant widget.
- SCHEDULE_CURATED_LOOKAHEAD_HOURS / RADIO_SHOW_LOOKAHEAD_HOURS — how far the Curated Selections and Radio Shows calendars look ahead (24 = today, 48 = +tomorrow).
- HISTORY_COUNT — base Recently Played count; the list grows automatically when sidebar sections are hidden.
Full configuration reference
The toggles above are the ones most people touch. For completeness, here is the whole
AppConfig object grouped by purpose — every key is documented inline in
js/app.js:
const AppConfig = {
// Player & stream
STREAM_URL, API_URL, QUEUE_URL, LISTENERS_URL,
DEFAULT_VOLUME, AUTOPLAY, REFRESH_INTERVAL,
// Requests & sharing
REQUESTS_URL, REQUEST_SUBMIT_URL, SHARE_MESSAGE,
// Schedule & podcasts
SCHEDULE_PLAYLISTS_URL, PODCASTS_URL,
SCHEDULE_CURATED_LOOKAHEAD_HOURS, RADIO_SHOW_LOOKAHEAD_HOURS,
SCHEDULE_COUNTDOWN_THRESHOLD_MINUTES, SCHEDULE_LIVE_LABEL,
// History & section visibility
HISTORY_COUNT, HISTORY_LAYOUT_COUNTS,
SHOW_MAP, SHOW_REQUESTS, SHOW_LISTEN_IN_PLAYER,
SHOW_HEADER_SECTION, SHOW_HEADER_WEATHER, SHOW_HEADER_THEME,
SHOW_HEADER_POPUP, SHOW_HEADER_TV_MODE,
// Styling & branding
COLORS, QUALITY_LABELS, LOGO, COVER_PLACEHOLDER_LETTER,
COVER, COVER_INFO_TICKER_SPEED,
// UI & features
ANIMATIONS, STATIC_PLAYER_LABELS, CHAT_ASSISTANT_ENABLED,
INSTAGRAM_FOLLOW_URL, INSTAGRAM_FOLLOW_WIDGET_ENABLED,
MAINTENANCE_MODE
};
Colors, quality labels and logo sizing are objects with their own
sub-keys — open js/app.js to see the full shape and defaults.
3. Integrations & APIs
Everything below works out of the box — no paid API keys required.
- AzuraCast Now Playing — the core data source, polled every 15 seconds for track, artwork, listeners and stream metadata.
- iTunes + Song.link (Odesli) — resolves universal listen links (Spotify, Apple Music, YouTube Music, Deezer…) per track. Results are cached in the browser to respect API limits.
- Schedule & podcasts — the local API proxy exposes AzuraCast playlist schedules and podcast episodes; the frontend renders Curated Selections with live countdowns and the latest Radio Show episode.
- GetSongBPM / Key (optional) — server-side enrichment for tempo and musical key pills; falls back to your stream metadata when unset.
- Open-Meteo — privacy-first local weather widget, no tracking.
- Flagpedia — country flags for the listener map.

Not a developer? Let AI configure it
Copy this prompt into ChatGPT, Claude or Gemini together with your station details, and
paste the result into js/app.js:
"I purchased the Fortesonic radio platform. Help me configure js/app.js. My station details: - AzuraCast Now Playing JSON URL: [YOUR JSON API URL] - High quality (320kbps) stream URL: [YOUR 320kbps URL] - Low quality (64kbps) stream URL: [YOUR 64kbps URL] Generate the exact AppConfig object to replace in js/app.js. No explanation needed - just the finalized object to copy-paste."
Guided setup with an AI agent
Working in an AI coding agent instead (Claude Code, Cursor, Windsurf…) with the unzipped package open? Paste this — the agent will interview you step by step and apply your answers for you:
"You are my setup assistant for the Fortesonic radio platform I purchased. The package is unzipped in this project folder. Guide me through the setup step by step - one question at a time, and never invent values for me. 1. Check the install: confirm the files are in the web root and the host runs PHP 8+ with HTTPS. If not, walk me through the FTP/cPanel upload. 2. Connect my station: ask me for my AzuraCast Now Playing API URL and my stream mount URLs (320/128/64 kbps), then put them into js/app.js. 3. Optional extras: ask if I have a GetSongBPM key and whether I want the listener assistant (chatbot) enabled. 4. Walk me through every true/false toggle in the AppConfig object in js/app.js one by one: explain in one sentence what it shows, ask me yes or no, and set it accordingly (SHOW_MAP, SHOW_REQUESTS, SHOW_LISTEN_IN_PLAYER, the SHOW_HEADER_* toggles, AUTOPLAY, ANIMATIONS, CHAT_ASSISTANT_ENABLED...). 5. Only edit js/app.js (and .env for the chatbot switch). Show me every change before you save it. Anything beyond that - design, CSS, server config - point me to the documentation instead of changing it."
The agent configures — you decide. It installs the basics, adds your own URLs and keys, and switches features on or off exactly as you answer.
4. Player features
Beyond play/stop, the player ships a set of listener-facing extras. Each one is either on by
default or gated behind a single AppConfig toggle, so you decide what your audience
sees.
TV mode
A full-screen “lounge” display — giant cover art, live status and Up Next,
nothing else. Perfect for a screen in a bar, studio or waiting room. Toggled with
SHOW_HEADER_TV_MODE; listeners enter from the header button and leave with
Esc.
Sleep timer
A countdown dropdown — 15, 30 or 45 minutes, or 1 hour (plus Off to cancel) — that gently fades the volume down over the final stretch and then stops the stream, so listeners can fall asleep to the radio without it running all night. When it stops, a dismissible notice confirms it (“Good night”) and the fade-start volume is restored, so the next play never begins silent. The countdown is remembered in the browser, so it keeps running even if the listener reloads the page or moves around the app shell. On by default; no configuration needed.
Quality switcher
A dropdown fed by your AzuraCast mount points (320 / 128 / 64 kbps and anything else you
create). QUALITY_LABELS sets the human-readable text per bitrate, and the listener's
choice is remembered in the browser between visits.
Lock-screen & hardware controls (MediaSession)
Using the browser MediaSession API, the current cover art, title and artist appear on the phone lock screen and in the OS media panel, and the hardware play/pause and media keys control the stream. No configuration required — it works wherever the browser supports it.
Pop-out player
Gated behind SHOW_HEADER_POPUP: opens the player in a small dedicated window
(about 450×700) that keeps playing while the listener browses other sites. The header button
spawns it; closing the window stops that instance.
Listener map & weather
- Global Reach map (
SHOW_MAP) — country flags with live listener counts pulled from AzuraCast. Listener coordinates are rounded before display, so the map shows reach without pinpointing anyone. - Local weather (
SHOW_HEADER_WEATHER) — a privacy-first widget powered by Open-Meteo with no tracking and no API key.
5. Listener assistant
The chatbot ships as an isolated plugin under ai/chatbot/, loaded through one
include line in inc/footer.php. It answers from a local knowledge base on your
server — no OpenAI account, no API keys, no per-message costs. Unknown
questions get a controlled fallback instead of an invented answer.
Enable / disable
CHAT_ASSISTANT_ENABLED: falseinjs/app.js— hides the widget.RADIO_CHAT_ENABLED=falsein.env— disables the widget and the endpoint.- Remove the include line from
inc/footer.php— removes it completely.
Edit ai/chatbot/knowledge.php to teach it about your station: shows, hosts,
how to request songs, contact info.

6. App Shell & PWA
Fortesonic keeps the live stream alive while listeners move between internal pages: eligible links swap only the content region, so the audio engine is never destroyed by a reload. A compact mini player appears on subpages and follows the same play/stop state as the main player.
Preview playback rules
- Recently Played and Broadcast History rows offer 30–60s previews.
- If the live stream is playing, a preview pauses it and resumes it afterwards.
- Up Next never renders preview controls (you can't preview the future).


PWA cache versioning
When you customize cached JS/CSS assets, bump CACHE_NAME in
assets/pwa/service-worker.js (convention: radio-vNN) so installed
apps pick up your changes.
7. Mobile UX & popups
The mobile layout is tuned separately: 50/50 Quality and Sleep dropdowns below the play controls, centered request button, and touch targets sized for thumbs.
Popup sequence
1. Visitor lands on the page. 2. Cookie consent banner slides up after 1 second. 3. On "Got it!" (or after 6s) the consent cookie is saved for 365 days. 4. 3 seconds later, phones see the Data Saver banner: the player switched to 64 kbps to save bandwidth. It auto-hides after 12s; the choice is remembered for 30 days.

8. Security & server config
- XSS prevention — all API strings (artist, title) are sanitized before touching the DOM.
- Rate limiting + CSRF — song requests and the assistant endpoint are
rate-limited per client (by IP address and per endpoint scope) inside a rolling time window,
returning a
429when the limit is exceeded. Every write is checked for a matching origin/referer before it runs. - Fail-safes — if the stream API goes offline, the UI switches to a clean offline state instead of spamming errors.
The included .htaccess handles
- Force HTTPS + HSTS (AutoSSL validation paths excluded).
- www → non-www redirect against duplicate indexing.
- Clean URLs —
/impressumloadsimpressum.php. - GZIP/deflate compression and 1–12 month browser caching for static assets.
- Custom 404 routing to the styled
404.phptemplate.

Ready to put your station on air?
One license, live in minutes. Installation (49 €) and CDN setup are add-ons on the order form.
Order Fortesonic — from 99 €Questions? maestro@fortesonic.com