Implemented a generic plugin header indicator system in FPP core that allows any plugin to display status indicators in the main FPP header. Previously, the BackgroundMusic plugin used a custom JavaScript solution that only worked on its own page. Now, any plugin can register indicators that appear globally across all FPP pages.
Purpose: Central controller for plugin header indicators
Functionality:
- Queries all installed plugins for their
headerIndicatorendpoints - Aggregates indicator configurations from all plugins
- Returns array of indicator objects
- Handles timeouts and errors gracefully (200ms timeout per plugin)
Endpoint: GET /api/plugin/headerIndicators
Response Format:
[
{
"visible": true,
"icon": "fa-music",
"color": "#8b5cf6",
"tooltip": "Background Music: Track Name",
"link": "/plugin-page.php",
"animate": "pulse",
"pluginName": "fpp-plugin-BackgroundMusic"
}
]Change: Added route for plugin header indicators
Line 117 (inserted):
dispatch_get('/plugin/headerIndicators', 'GetPluginHeaderIndicators');Backup: /opt/fpp/www/api/index.php.backup
Change: Modified finalizeStatusJson() to include plugin indicators in status API
Lines 390-394 (added):
// Add plugin header indicators
if (!isset($_GET['noplugins'])) {
$obj['pluginHeaderIndicators'] = json_decode(GetPluginHeaderIndicators(), true);
}Integration: Plugin indicators now included in /api/system/status response, automatically refreshed with all status updates
Backup: /opt/fpp/www/api/controllers/system.php.backup
Change: Added client-side rendering of plugin indicators
Lines 8661-8687 (inserted after header_player update):
// Render plugin header indicators
if (data.pluginHeaderIndicators != undefined) {
var indicators = [];
data.pluginHeaderIndicators.forEach(function(indicator) {
if (indicator && indicator.visible) {
var icon = indicator.icon || 'fa-puzzle-piece';
var color = indicator.color || '#999';
var tooltip = indicator.tooltip || 'Plugin Indicator';
var link = indicator.link || '#';
var animate = indicator.animate || '';
var animStyle = animate ? ' style="animation: ' + animate + ' 2s infinite;"' : '';
var row = '<span class="pluginIndicator headerBox" data-plugin="' + indicator.pluginName + '"' +
' style="cursor: pointer; color: ' + color + '; margin-left: 5px; transition: color 0.3s ease;"' +
' title="' + tooltip + '"' +
' onclick="window.location.href=\'' + link + '\'">' +
'<i class="fas ' + icon + '"' + animStyle + '></i>' +
'</span>';
indicators.push(row);
}
});
var indicatorsJoined = indicators.join('');
if (headerCache.PluginIndicators != indicatorsJoined) {
$('#header_plugin_indicators').html(indicatorsJoined);
headerCache.PluginIndicators = indicatorsJoined;
}
}Backup: /opt/fpp/www/js/fpp.js.backup
Change: Added placeholder span for plugin indicators in header HTML
Line 110 (inserted):
<span class="headerBox" id="header_plugin_indicators"></span>Location: Between header_player and header_sensors spans
Backup: /opt/fpp/www/menu.inc.backup
Change: Added CSS styles for plugin indicators and pulse animation
Lines appended:
/* Plugin Header Indicators */
.pluginIndicator {
display: inline-block;
margin-left: 5px;
transition: color 0.3s ease, transform 0.2s ease;
}
.pluginIndicator:hover {
transform: scale(1.1);
opacity: 0.8;
}
@keyframes pulse {
0%, 100% {
transform: scale(1);
opacity: 1;
}
50% {
transform: scale(1.15);
opacity: 0.85;
}
}Plugins add a headerIndicator endpoint to their API:
- Register the endpoint in
getEndpoints{PluginName}():
$ep = array(
'method' => 'GET',
'endpoint' => 'headerIndicator',
'callback' => 'pluginHeaderIndicator'
);
array_push($result, $ep);- Implement the callback returning indicator config:
function pluginHeaderIndicator() {
if (!$featureActive) {
return json(null); // Don't show indicator
}
return json(array(
'visible' => true,
'icon' => 'fa-icon-name',
'color' => '#hexcolor',
'tooltip' => 'Status text',
'link' => '/plugin-page.php',
'animate' => 'pulse' // optional
));
}The BackgroundMusic plugin now uses this system instead of its custom header-indicator.js:
File: /home/fpp/media/plugins/fpp-plugin-BackgroundMusic/api.php
Implementation:
- Added
headerIndicatorendpoint (line ~20) - Implemented
fppBackgroundMusicHeaderIndicator()function (lines ~383-445) - Returns purple pulsing music icon when playing
- Tooltip shows current track or stream title
- Links to plugin controller page
- Client Status Request: Browser requests
/api/system/status - Plugin Discovery:
finalizeStatusJson()callsGetPluginHeaderIndicators() - Plugin Queries: Each plugin's
headerIndicatorendpoint is queried (200ms timeout) - Aggregation: All indicator configs collected into array
- Response: Status JSON includes
pluginHeaderIndicatorsfield - Rendering: JavaScript in fpp.js renders indicators into
header_plugin_indicatorsspan - Auto-Refresh: Process repeats on each status refresh cycle
- Caching: Indicators cached in status response (no separate queries needed)
- Timeout: 200ms per plugin prevents slowdowns
- Non-blocking: Failed plugins don't affect others
- Efficient: Only queries plugins that have an
api.phpfile - Scalable: Multiple plugins can have indicators without performance impact
- ✅ Simple API - just return JSON configuration
- ✅ No JavaScript required
- ✅ Auto-discovery - FPP finds your endpoint
- ✅ Centrally managed styling and positioning
- ✅ Works on all FPP pages automatically
- ✅ Consistent indicator location and behavior
- ✅ No configuration needed
- ✅ Multiple plugin indicators supported
- ✅ Responsive and accessible
- ✅ Updates in real-time with status
- ✅ Extensible architecture
- ✅ Backwards compatible (opt-in for plugins)
- ✅ Minimal performance impact
- ✅ Generic - works for any plugin type
- Main endpoint:
http://localhost/api/plugin/headerIndicators - Status with indicators:
http://localhost/api/system/status | jq '.pluginHeaderIndicators' - Example plugin:
http://localhost/api/plugin/fpp-plugin-BackgroundMusic/headerIndicator
- Check indicator appears in FPP header when BackgroundMusic is playing
- Verify tooltip shows current track
- Click indicator navigates to plugin page
- Check pulse animation is smooth
- Verify works on all FPP pages (index, settings, etc.)
Potential improvements:
- Add indicator priority/ordering system
- Support for badges/counters on indicators
- Indicator grouping for related plugins
- User preferences for which indicators to show
- Indicator animation customization options
If issues arise, restore from backups:
cp /opt/fpp/www/api/index.php.backup /opt/fpp/www/api/index.php
cp /opt/fpp/www/api/controllers/system.php.backup /opt/fpp/www/api/controllers/system.php
cp /opt/fpp/www/js/fpp.js.backup /opt/fpp/www/js/fpp.js
cp /opt/fpp/www/menu.inc.backup /opt/fpp/www/menu.inc
rm /opt/fpp/www/api/controllers/pluginHeaders.phpRemove CSS additions from /opt/fpp/www/css/fpp.css (last ~20 lines)
Implementation Date: November 27, 2025 Implemented For: BackgroundMusic Plugin header indicator feature FPP Version: Compatible with FPP 8.x+ Implementation: Added generic framework to FPP core for all plugins to use