switched to yt source

This commit is contained in:
fishtank-dashboard
2026-03-27 16:32:51 -07:00
committed by GitHub
parent ddf9d71386
commit 5d52b6bb11
2 changed files with 283 additions and 3 deletions
+92 -3
View File
@@ -2175,6 +2175,7 @@
<button class="stocks-collapse-btn" onclick="toggleStocks()" id="stocksCollapseBtn">▲ STOCKS</button>
<button class="stocks-collapse-btn" id="chatCollapseBtn" onclick="toggleChat()" title="Hide chat panel">💬 CHAT</button>
<button class="stocks-collapse-btn" id="notifLogBtn" onclick="toggleNotifLog()" title="Notification log" style="position:relative;">🔔 NOTIFS<span class="notif-log-badge" id="notifLogBadge">0</span></button>
<button class="stocks-collapse-btn" id="ytToggleBtn" onclick="toggleYtSource()" title="Switch between fishtank.rip and YouTube" style="border-color:var(--muted);color:var(--muted);">▶ YT SOURCE</button>
</div>
<div id="apiControl" style="display:flex;align-items:center;gap:8px;">
@@ -2873,8 +2874,9 @@
["West Wing", "hwup-5"],
["Jungle Room", "br4j-5"],
["Computer Lab", "bbcl-5"],
["Cameraman", "cameraman2-5"],
["Job Board", "jobb-5"],
["Arena", "bare-5"],
["Cameraman", "cameraman2-5"],
];
// Navigation polygons per camera slug
@@ -2988,6 +2990,8 @@
const DEFAULT_IDX = 1; // Director Mode
const hlsInstances = {};
let featuredIdx = DEFAULT_IDX;
let ytSourceActive = true;
let ytReadyCount = 0;
// directorCell = which grid index currently shows the Director stream (null = director is in featured)
let directorCell = null;
@@ -3019,7 +3023,15 @@
fragLoadingMaxRetry: 3,
manifestLoadingMaxRetry: 3,
});
hls.loadSource('http://localhost:3000/cam/' + slug + '/index.m3u8');
const isYt = ytSourceActive && slug !== '__epyc__';
if (isYt) {
hls.config.startPosition = -1;
hls.config.liveSyncDurationCount = 2;
}
const hlsSource = isYt
? 'http://localhost:3000/yt-stream/' + slug
: 'http://localhost:3000/cam/' + slug + '/index.m3u8';
hls.loadSource(hlsSource);
hls.attachMedia(video);
let reconnectOverlayTimer = null;
@@ -3878,7 +3890,14 @@
};
const hls = new Hls({ maxBufferLength: 2, maxMaxBufferLength: 4 });
hls.loadSource('http://localhost:3000/cam/' + slug + '/index.m3u8');
const ytSlugsSet = new Set(['dirc-5','foyr-5','gsrm-5','mrke-5','mrke2-5','hwdn-5',
'dmrm-5','dmrm2-5','dmcl-5','jckz-5','brrr-5','brrr2-5','brpz-5','ktch-5',
'dnrm-5','hwup-5','bbcl-5','br4j-5','bkny-5','codr-5','cfsl-5','jobb-5','bare-5']);
if (ytSourceActive && !ytSlugsSet.has(slug)) { hls.destroy(); resolve(); return; }
const thumbUrl = ytSourceActive
? 'http://localhost:3000/yt-stream/' + slug
: 'http://localhost:3000/cam/' + slug + '/index.m3u8';
hls.loadSource(thumbUrl);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => video.play().catch(() => {}));
video.addEventListener('timeupdate', capture, { once: true });
@@ -3924,6 +3943,7 @@
const featVideo = document.createElement('video');
featVideo.playsInline = true;
featVideo.autoplay = true;
featVideo.crossOrigin = 'anonymous';
const featLabel = document.createElement('div');
featLabel.className = 'cam-label';
featLabel.textContent = CAMERAS[DEFAULT_IDX][0].toUpperCase();
@@ -3962,6 +3982,7 @@
cell.className = 'cam-cell';
cell.id = 'cam-' + i;
cell.dataset.slug = slug;
cell.dataset.idx = i;
const canvas = document.createElement('canvas');
canvas.style.cssText = 'width:100%;height:100%;display:block;object-fit:cover;';
canvas.id = 'canvas-' + i;
@@ -4228,6 +4249,12 @@
}
}
if (msg._ft === 'yt_status') {
ytReadyCount = msg.ready || 0;
updateYtBtn();
return;
}
if (msg._ft === 'raw') {
console.log('[FT-WS RAW]', msg.data);
}
@@ -4400,6 +4427,67 @@
if (inlineChatAutoScroll) inlineFeed.scrollTop = inlineFeed.scrollHeight;
}
// ── YouTube source toggle ────────────────────────────────────
fetch('http://localhost:3000/yt-status').then(r => r.json()).then(d => {
ytReadyCount = d.ready || 0;
updateYtBtn();
}).catch(() => {});
function updateYtBtn() {
const btn = document.getElementById('ytToggleBtn');
if (!btn) return;
if (ytSourceActive) {
btn.style.borderColor = '#e74c3c';
btn.style.color = '#e74c3c';
btn.textContent = '▶ YT LIVE';
} else if (ytReadyCount > 0) {
btn.style.borderColor = 'var(--green)';
btn.style.color = 'var(--green)';
btn.textContent = '▶ YT (' + ytReadyCount + ')';
} else {
btn.style.borderColor = 'var(--muted)';
btn.style.color = 'var(--muted)';
btn.textContent = '▶ YT SOURCE';
}
}
window.toggleYtSource = function() {
ytSourceActive = !ytSourceActive;
updateYtBtn();
// Switch featured cam — makeHls now reads ytSourceActive
const wrap = document.getElementById('camFeaturedWrap');
const featVideo = wrap && wrap.querySelector('video');
const featSlug = CAMERAS[featuredIdx] && CAMERAS[featuredIdx][1];
if (featVideo && featSlug) {
if (hlsInstances['featured']) hlsInstances['featured'].destroy();
hlsInstances['featured'] = makeHls(featSlug, featVideo, false);
}
// Dim grid cells that have no YT source
const NO_YT = new Set(['cameraman2-5','br3g-5']);
const ytSlugs = new Set(['dirc-5','foyr-5','gsrm-5','mrke-5','mrke2-5','hwdn-5',
'dmrm-5','dmrm2-5','dmcl-5','jckz-5','brrr-5','brrr2-5','brpz-5','ktch-5',
'dnrm-5','hwup-5','bbcl-5','br4j-5','bkny-5','codr-5','cfsl-5','bare-5','jobb-5']);
const grid = document.getElementById('cameraGrid');
if (grid) {
grid.querySelectorAll('.cam-cell').forEach(cell => {
const slug = cell.dataset.slug;
if (ytSourceActive && slug && !ytSlugs.has(slug)) {
cell.style.opacity = '0.25';
cell.style.pointerEvents = 'none';
} else {
cell.style.opacity = '';
cell.style.pointerEvents = '';
}
});
}
// Thumbnails are canvas-based — just refresh them from new source
refreshAllThumbnails();
};
// ── End YouTube source toggle ─────────────────────────────────
// ── Floor plan ───────────────────────────────────────────────
const FLOOR_ROOMS = {
down: [
@@ -4553,6 +4641,7 @@
cell.className = 'cam-cell';
cell.id = 'cam-' + i;
cell.dataset.slug = slug;
cell.dataset.idx = i;
const canvas = document.createElement('canvas');
canvas.style.cssText = 'width:100%;height:100%;display:block;object-fit:cover;';
canvas.id = 'canvas-' + i;