mirror of
git://f0xx.org/ac/ac-be-issues
synced 2026-07-29 05:58:39 +03:00
Add experimental Media pipelines console with Nuevo HLS player.
Developer-gated nav and UI for ac-ms-media-transcode control plane when media_pipelines.enabled is set in BE config. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
115
views/layout.php
115
views/layout.php
@@ -49,6 +49,19 @@
|
|||||||
<?php if (($view ?? '') === 'rbac'): ?>
|
<?php if (($view ?? '') === 'rbac'): ?>
|
||||||
<script src="<?= h(Auth::basePath()) ?>/assets/js/rbac_admin.js" defer></script>
|
<script src="<?= h(Auth::basePath()) ?>/assets/js/rbac_admin.js" defer></script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if (($view ?? '') === 'media_pipelines'): ?>
|
||||||
|
<link rel="stylesheet" href="<?= h(Auth::basePath()) ?>/assets/vendor/nuevo-player/vdjs/v10.0.0/skins/treso/videojs.min.css">
|
||||||
|
<style>
|
||||||
|
.media-pipelines-player-wrap { max-width: 960px; margin: 0.5rem 0 1rem; background: var(--surface-2, #111); border-radius: 8px; overflow: hidden; }
|
||||||
|
.media-pipelines-player-wrap .video-js { width: 100%; }
|
||||||
|
.tag-field--wide { flex: 2 1 280px; min-width: 200px; }
|
||||||
|
.btn--sm { font-size: 0.8rem; padding: 0.2rem 0.5rem; margin-right: 0.25rem; }
|
||||||
|
</style>
|
||||||
|
<script src="<?= h(Auth::basePath()) ?>/assets/vendor/nuevo-player/js/video.min.js" defer></script>
|
||||||
|
<script src="<?= h(Auth::basePath()) ?>/assets/vendor/nuevo-player/js/videojs-contrib-hls.min.js" defer></script>
|
||||||
|
<script src="<?= h(Auth::basePath()) ?>/assets/vendor/nuevo-player/js/nuevo.min.js" defer></script>
|
||||||
|
<script src="<?= h(Auth::basePath()) ?>/assets/js/media_pipelines.js" defer></script>
|
||||||
|
<?php endif; ?>
|
||||||
<?php AnalyticsHead::render('crashes'); ?>
|
<?php AnalyticsHead::render('crashes'); ?>
|
||||||
</head>
|
</head>
|
||||||
<body data-base-path="<?= h(console_base_path($view ?? null)) ?>"
|
<body data-base-path="<?= h(console_base_path($view ?? null)) ?>"
|
||||||
@@ -60,7 +73,8 @@
|
|||||||
<?= Rbac::can('remote_access_admin') ? ' data-can-ra-admin="1"' : '' ?>
|
<?= Rbac::can('remote_access_admin') ? ' data-can-ra-admin="1"' : '' ?>
|
||||||
<?= Rbac::can('short_links_operate') ? ' data-can-sl-operate="1"' : '' ?>
|
<?= Rbac::can('short_links_operate') ? ' data-can-sl-operate="1"' : '' ?>
|
||||||
<?= Rbac::isGlobalAdmin() ? ' data-can-sl-admin="1"' : '' ?>
|
<?= Rbac::isGlobalAdmin() ? ' data-can-sl-admin="1"' : '' ?>
|
||||||
<?= Rbac::isRoot() ? ' data-can-rbac-root="1"' : '' ?>>
|
<?= Rbac::isRoot() ? ' data-can-rbac-root="1"' : '' ?>
|
||||||
|
<?= (cfg('media_pipelines.enabled', false) && (Rbac::isGlobalAdmin() || Rbac::can('media_pipelines_operate'))) ? ' data-can-mp-operate="1"' : '' ?>>
|
||||||
<header class="top-menu" hidden aria-hidden="true"></header>
|
<header class="top-menu" hidden aria-hidden="true"></header>
|
||||||
<div class="shell<?= ($view ?? '') === 'graphs' ? ' shell--graphs-full' : '' ?>">
|
<div class="shell<?= ($view ?? '') === 'graphs' ? ' shell--graphs-full' : '' ?>">
|
||||||
<nav class="nav-pane" id="nav-pane" aria-label="Console navigation">
|
<nav class="nav-pane" id="nav-pane" aria-label="Console navigation">
|
||||||
@@ -143,6 +157,20 @@
|
|||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<?php if (cfg('media_pipelines.enabled', false) && (Rbac::isGlobalAdmin() || Rbac::can('media_pipelines_view') || Rbac::can('media_pipelines_operate'))): ?>
|
||||||
|
<li>
|
||||||
|
<a href="<?= h(Auth::basePath()) ?>/?view=media_pipelines"
|
||||||
|
class="nav-link <?= ($view ?? '') === 'media_pipelines' ? 'active' : '' ?>"
|
||||||
|
aria-label="Media pipelines"
|
||||||
|
title="Media pipelines (experimental)">
|
||||||
|
<span class="nav-icon nav-icon--graphs" aria-hidden="true"></span>
|
||||||
|
<span class="nav-text">
|
||||||
|
<span class="nav-label">Media pipelines</span>
|
||||||
|
<span class="nav-desc">Experimental restream — encode once, HLS + RTMP fanout.</span>
|
||||||
|
</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endif; ?>
|
||||||
<li>
|
<li>
|
||||||
<a href="<?= h(Auth::basePath()) ?>/live/education"
|
<a href="<?= h(Auth::basePath()) ?>/live/education"
|
||||||
class="nav-link"
|
class="nav-link"
|
||||||
@@ -605,6 +633,91 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
|
<?php elseif (($view ?? '') === 'media_pipelines'): ?>
|
||||||
|
<div id="media-pipelines-app" class="reports-app">
|
||||||
|
<div class="toolbar reports-toolbar">
|
||||||
|
<h1>Media pipelines <span class="muted" style="font-size:0.65em;font-weight:normal">(experimental)</span></h1>
|
||||||
|
<div class="toolbar-actions">
|
||||||
|
<button type="button" class="btn" id="mp-refresh">Refresh</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<?php require __DIR__ . '/partials/console_quick_links.php'; ?>
|
||||||
|
<p id="mp-status" class="reports-status muted" aria-live="polite">Loading…</p>
|
||||||
|
<p class="muted graphs-footnote">
|
||||||
|
Lab-only restream control plane. Requires <code>streaming_v2</code> on BE, ffmpeg, yt-dlp.
|
||||||
|
Visible when <code>media_pipelines.enabled</code> and global admin / privilege grant.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<section class="graphs-scope" id="mp-create-section">
|
||||||
|
<h2 class="graphs-scope-title">New pipeline</h2>
|
||||||
|
<form id="mp-create-form" class="tag-editor-add">
|
||||||
|
<label class="tag-field"><span>Name</span><input type="text" name="name" maxlength="128" placeholder="My restream"></label>
|
||||||
|
<label class="tag-field tag-field--wide"><span>Source URL</span><input type="url" name="source_url" required placeholder="https://… or /path/file.mkv"></label>
|
||||||
|
<label class="tag-field"><span>yt-dlp format</span><input type="text" name="source_fmt" placeholder="bv*+ba/b"></label>
|
||||||
|
<label class="tag-field tag-field--wide"><span>Separate audio URL</span><input type="url" name="audio_source" placeholder="optional"></label>
|
||||||
|
<label class="tag-field">
|
||||||
|
<span>Filter</span>
|
||||||
|
<select name="filter_profile">
|
||||||
|
<option value="default">Logo overlay</option>
|
||||||
|
<option value="blurred">Blurred + logo</option>
|
||||||
|
<option value="nologo">No logo</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="tag-field">
|
||||||
|
<span>Preset</span>
|
||||||
|
<select name="output_preset">
|
||||||
|
<option value="1080p">1080p</option>
|
||||||
|
<option value="720p">720p</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="tag-field">
|
||||||
|
<span>Mode</span>
|
||||||
|
<select name="run_mode">
|
||||||
|
<option value="full">Full (encode + RTMP fanout)</option>
|
||||||
|
<option value="encode_only">Encode only (record + HLS)</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<button type="submit" class="btn" id="mp-create-btn">Create pipeline</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="graphs-scope">
|
||||||
|
<h2 class="graphs-scope-title">Pipelines</h2>
|
||||||
|
<div class="reports-table-wrap">
|
||||||
|
<table class="data-table reports-table--cols" id="mp-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Status</th>
|
||||||
|
<th>Mode</th>
|
||||||
|
<th>Source</th>
|
||||||
|
<th>HLS</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="mp-tbody"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="graphs-scope" id="mp-player-section" hidden>
|
||||||
|
<h2 class="graphs-scope-title">Preview</h2>
|
||||||
|
<div class="media-pipelines-player-wrap">
|
||||||
|
<video id="mp-player" class="video-js vjs-default-skin vjs-big-play-centered" controls preload="auto" width="960" height="540"></video>
|
||||||
|
</div>
|
||||||
|
<p class="muted graphs-footnote" id="mp-player-url"></p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="graphs-scope" id="mp-probe-section" hidden>
|
||||||
|
<h2 class="graphs-scope-title">Source profile (ffprobe)</h2>
|
||||||
|
<pre id="mp-probe-json" class="graph-detail-body" style="max-height:240px;overflow:auto"></pre>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="graphs-scope" id="mp-logs-section" hidden>
|
||||||
|
<h2 class="graphs-scope-title">Encode log (tail)</h2>
|
||||||
|
<pre id="mp-logs" class="graph-detail-body" style="max-height:200px;overflow:auto;font-size:0.75rem"></pre>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
<?php elseif (($view ?? '') === 'short_links'): ?>
|
<?php elseif (($view ?? '') === 'short_links'): ?>
|
||||||
<div id="short-links-app" class="reports-app">
|
<div id="short-links-app" class="reports-app">
|
||||||
<div class="toolbar reports-toolbar">
|
<div class="toolbar reports-toolbar">
|
||||||
|
|||||||
Reference in New Issue
Block a user