57 lines
3.3 KiB
PHP
57 lines
3.3 KiB
PHP
<?php
|
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
// PURPOSE
|
|
// Active media sessions endpoint. Normalised now-playing across every Emby, Jellyfin and
|
|
// Plex instance configured for this host, for the monitor page's session panel.
|
|
//
|
|
// OPERATIONAL MODEL
|
|
// Local is the default and stays the cheap path: one call per media server configured on this
|
|
// host. Mesh adds one bounded SSH hop per partner and is only requested while the operator is
|
|
// looking at the mesh view, so a dashboard left open on the default costs exactly what it did
|
|
// before the scope existed.
|
|
//
|
|
// DESIGN PRINCIPLES
|
|
// Thin transport. Discovery, per-server API dialects and normalisation all live in
|
|
// include/media.php; this file only sets the content type and encodes the result.
|
|
//
|
|
// The request chooses a scope, never a target. scope= selects local or mesh; which servers
|
|
// are asked, and which partners the mesh hop reaches, are both derived from conf. The browser
|
|
// can widen what it asks for, but it cannot point this endpoint at an arbitrary URL.
|
|
//
|
|
// OPERATIONAL SAFEGUARDS
|
|
// Bounded by the library's 3s per-request timeout.
|
|
// A wedged media server cannot hold this endpoint open, because every fetch inside
|
|
// vv_media_sessions() carries a stream-context timeout. This is the only thing between
|
|
// a hung Emby and a poll that never returns.
|
|
//
|
|
// Failure is an empty list, not an error.
|
|
// Unreachable servers, non-JSON bodies and unexpected shapes all resolve to [] inside
|
|
// the library. The panel renders empty and the rest of the monitor page is unaffected.
|
|
//
|
|
// Read-only. Sessions are observed. Nothing here stops a stream, forces a transcode, or
|
|
// messages a client.
|
|
//
|
|
// REQUEST
|
|
// GET this host's sessions
|
|
// GET ?scope=mesh every node's sessions, each row tagged with the host it is playing on
|
|
//
|
|
// RESPONSE
|
|
// local {"scope":"local","sessions":[…],"server_names":[…],"server_count":N}
|
|
// mesh {"scope":"mesh","nodes":[…],"sessions":[…],"server_names":[…],"server_count":N}
|
|
//
|
|
// sessions is the normalised list; in the mesh scope each row also carries the host it is
|
|
// playing on. server_count counts media servers, not sessions. There is no error shape — an
|
|
// unreachable server contributes nothing; see OPERATIONAL SAFEGUARDS.
|
|
//
|
|
// DEPENDS ON
|
|
// include/media.php vv_media_sessions(), vv_media_sessions_mesh()
|
|
// ═══════════════════════════════════════════════════════════════════════════════════════════════
|
|
header('Content-Type: application/json');
|
|
require_once dirname(__DIR__) . '/include/media.php';
|
|
|
|
// Anything that is not the literal "mesh" is local. Fail-closed on the expensive path, matching
|
|
// how every other toggle in this plugin reads its value.
|
|
echo json_encode(($_GET['scope'] ?? '') === 'mesh'
|
|
? vv_media_sessions_mesh()
|
|
: vv_media_sessions() + ['scope' => 'local']);
|