How Folia's Now Playing Integration Works with External Players
Folia's Now Playing integration exposes real-time track metadata through a local HTTP endpoint and WebSocket server, allowing external players like OBS, media controllers, and scrobblers to consume JSON payloads containing title, artist, album, and cover art.
Folia-major is an open-source music player designed to bridge local playback with streaming workflows. The Now Playing feature creates a lightweight metadata service that external applications can poll to display current track information without accessing Folia's internal state directly.
Core Architecture: The Now Playing Provider Service
The integration centers on src/services/nowPlayingProvider.ts, which implements a self-contained metadata server. When Folia's playback state changes, this provider generates a JSON payload containing track metadata and notifies connected clients through an embedded WebSocket server.
The provider exposes a simple HTTP GET endpoint at /now-playing that returns the current track object. This endpoint is reachable at http://localhost:<port>/now-playing once Folia initializes the service on startup.
State Isolation and Fallback Handling
To prevent UI glitches during visualization, Folia isolates the Now Playing snapshot from the main playback controller. The hook at src/hooks/useStagePlaybackController.ts maintains this separation through a dedicated state container, ensuring that external queries receive stable data even when the primary player pauses or buffers.
When metadata is incomplete, the provider implements fallback logic across lines 708–719 of useStagePlaybackController.ts. If the track information cannot be determined, the system defaults to "Now Playing" for both the title and artist fields (lines 194–195), guaranteeing that external clients always receive a valid, parseable object rather than null values.
Consuming Now Playing Data from External Applications
External players integrate by polling the HTTP endpoint or subscribing to WebSocket updates. The service returns standardized JSON containing title, artist, album, and coverUrl fields.
HTTP Endpoint Specification
The Now Playing service binds to a configurable local port (defaulting to 3170) and responds to GET requests at the /now-playing path. The response schema remains consistent regardless of playback state, ensuring predictable parsing in external scripts.
Node.js Client Implementation
You can fetch the current track from any external script using standard HTTP libraries:
import fetch from 'node-fetch';
async function getNowPlaying() {
const resp = await fetch('http://localhost:3170/now-playing');
if (!resp.ok) throw new Error('Now Playing service unavailable');
const data = await resp.json();
console.log(`🎶 ${data.title} – ${data.artist}`);
}
getNowPlaying();
OBS Browser Source Integration
For streamers, Folia provides direct OBS support through src/utils/obsBrowserSource.ts. You can embed the Now Playing data as a browser source using periodic fetch requests:
<script>
async function updateNowPlaying() {
const r = await fetch('http://localhost:3170/now-playing');
const { title, artist, album, coverUrl } = await r.json();
document.getElementById('title').textContent = title;
document.getElementById('artist').textContent = artist;
document.getElementById('album').textContent = album;
document.getElementById('cover').src = coverUrl;
}
setInterval(updateNowPlaying, 3000); // refresh every 3 s
</script>
<div id="nowplaying">
<img id="cover" src="" alt="Cover" />
<p><span id="title"></span> – <span id="artist"></span></p>
<small id="album"></small>
</div>
Configuration and Access Control
Users access the integration settings through Folia's command palette. The registry at src/components/command-palette/commandRegistry.ts (line 256) exposes a "Now Playing" command that opens the configuration panel, allowing you to modify the local server port and authentication parameters.
The provider supports runtime port configuration through the settings store, requiring a service restart when the port changes. This design prevents port conflicts with other local development servers while maintaining a stable endpoint for long-running external applications.
Summary
src/services/nowPlayingProvider.tsimplements the core HTTP server and WebSocket broadcaster for track metadata.src/hooks/useStagePlaybackController.tsisolates Now Playing state from the main player and handles fallback values (lines 194–195, 708–719).- External clients consume JSON via
GET http://localhost:3170/now-playingcontaining standardized fields for title, artist, album, and cover art. src/utils/obsBrowserSource.tsprovides helpers for streaming software integration.- The command palette entry (line 256 of
commandRegistry.ts) exposes port configuration and service controls.
Frequently Asked Questions
What port does Folia's Now Playing server use by default?
The service defaults to port 3170, though you can configure this through the command palette settings. If the port is unavailable during startup, Folia will log a binding error and you must select an alternative port through the integration settings.
How does Folia handle missing metadata in Now Playing responses?
When track metadata is incomplete, the provider falls back to "Now Playing" as both the title and artist (lines 194–195 of nowPlayingProvider.ts). The useStagePlaybackController.ts hook (lines 708–719) further normalizes the payload by checking the most recent track object and lyric data to ensure all fields contain usable strings rather than null values.
Can multiple external applications connect to Folia's Now Playing service simultaneously?
Yes. The WebSocket server embedded in nowPlayingProvider.ts broadcasts state changes to all connected clients, while the HTTP endpoint supports concurrent polling. This architecture allows you to run OBS browser sources, Discord rich presence tools, and scrobblers simultaneously without conflicts.
Is the Now Playing endpoint available when Folia is paused or stopped?
The HTTP endpoint remains active while Folia runs, returning the last known track data with fallback values when no track is loaded. The JSON payload always contains valid strings for required fields, though the cover URL may be empty if no artwork was cached for the previous track.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →