feat: 작업실 장비 탭 밀링 카드에도 라이브 뷰
- ▶ 라이브 버튼 → go2rtc video-stream 커스텀 엘리먼트(WebRTC→MSE→MJPEG 자동폴백), nvr-app 라이브 모달과 동일 패턴. 릴레이 스트림 "cam"(config nvr.extraCameras) - go2rtc Origin 검사를 통과하도록 같은 오리진 WS 프록시(/api/nvr/go2rtc-ws) 경유, LAN IP 하드코딩 없이 현재 오리진 기준 상대경로(https mixed-content 회피) - 라이브 중엔 20초 스냅샷 폴링을 건너뛴다, 장비 탭을 벗어나면 연결 정리 (stopEquipTimers → stopMillLive), 상태줄에 "● 실시간" 표시 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,8 @@
|
||||
<link rel="icon" type="image/png" sizes="64x64" href="/homeclaw_logo.png">
|
||||
<link rel="stylesheet" href="../css/styles.css">
|
||||
<script>try{var _t=localStorage.getItem('homeclaw_theme')||'dark';document.documentElement.setAttribute('data-theme',_t);}catch(e){}</script>
|
||||
<!-- go2rtc 라이브 플레이어(밀링 카드 ▶ 라이브용) — WebRTC→MSE→MJPEG 자동폴백 커스텀 엘리먼트 -->
|
||||
<script type="module" src="/vendor/go2rtc/video-stream.js"></script>
|
||||
<style>
|
||||
html,body{height:100%;margin:0;padding:0;}
|
||||
body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;display:flex;flex-direction:column;overflow:hidden;height:100dvh;}
|
||||
@@ -258,8 +260,13 @@ body{background:var(--bg);color:var(--text);font-family:system-ui,sans-serif;dis
|
||||
<span>⚙️ CNC 밀링(프린터실)</span>
|
||||
<button class="rb-equip-refresh" onclick="refreshMillWidget()">↺</button>
|
||||
</div>
|
||||
<div class="rb-equip-frame-wrap"><img id="mill-frame" alt="" style="display:none" onerror="millFrameError()" onload="millFrameLoaded()"><span class="rb-equip-placeholder" id="mill-placeholder">불러오는 중...</span></div>
|
||||
<div class="rb-equip-status">20초마다 자동 새로고침(스냅샷) — <a href="/html/milling-app.html" target="_blank" style="color:#f59e0b">밀링 앱에서 라이브로 보기 ↗</a></div>
|
||||
<div class="rb-equip-frame-wrap">
|
||||
<video-stream id="mill-live" mode="webrtc,mse,mp4,mjpeg" style="display:none;width:100%;height:100%;background:#000;"></video-stream>
|
||||
<img id="mill-frame" alt="" style="display:none" onerror="millFrameError()" onload="millFrameLoaded()">
|
||||
<span class="rb-equip-placeholder" id="mill-placeholder">불러오는 중...</span>
|
||||
<button class="rb-equip-live-btn" id="mill-live-btn" onclick="toggleMillLive()">▶ 라이브</button>
|
||||
</div>
|
||||
<div class="rb-equip-status">20초마다 자동 새로고침(스냅샷) — <a href="/html/milling-app.html" target="_blank" style="color:#f59e0b">밀링 앱에서 라이브로 보기 ↗</a><span id="mill-live-marker"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -576,6 +583,42 @@ function switchTab(tab){
|
||||
// "장비" 탭을 보고 있을 때만 폴링한다 — 계속 켜두면 K2는 매번 짧은 WebRTC 연결을,
|
||||
// 밀링은 go2rtc 프레임 요청을 반복하니 안 보는 동안은 자원을 안 쓰는 게 맞다.
|
||||
const MILL_CHANNEL_ID=1000;
|
||||
const MILL_GO2RTC_SRC='cam'; // go2rtc(127.0.0.1:1985) 릴레이 스트림 이름(config nvr.extraCameras.1000.go2rtcSrc)
|
||||
// 밀링 카드 라이브(2026-09-24) — go2rtc video-stream 커스텀 엘리먼트(WebRTC→MSE→MJPEG
|
||||
// 자동폴백)를 nvr-app 라이브 모달과 동일 패턴으로 쓴다. go2rtc(1985)에 브라우저가
|
||||
// 직접 붙으면 Origin 검사로 거부되므로 같은 오리진 WS 프록시(/api/nvr/go2rtc-ws)를 거친다.
|
||||
// https 페이지에서 LAN IP를 ws://로 하드코딩하면 mixed-content로 막히므로 반드시
|
||||
// 현재 오리진 기준 상대경로로 만든다(K2 카메라와 동일 패턴, 09-18 발견).
|
||||
const GO2RTC_WS=(location.protocol==='https:'?'wss://':'ws://')+location.host+'/api/nvr/go2rtc-ws';
|
||||
let millLive=false;
|
||||
function toggleMillLive(){
|
||||
if(millLive)stopMillLive();else startMillLive();
|
||||
}
|
||||
function startMillLive(){
|
||||
if(millLive)return;
|
||||
const vs=document.getElementById('mill-live');
|
||||
millLive=true;
|
||||
const btn=document.getElementById('mill-live-btn');
|
||||
btn.classList.add('on');btn.textContent='⏹ 라이브 종료';
|
||||
document.getElementById('mill-frame').style.display='none';
|
||||
document.getElementById('mill-placeholder').style.display='none';
|
||||
vs.style.display='block';
|
||||
vs.src=GO2RTC_WS+'?src='+encodeURIComponent(MILL_GO2RTC_SRC)+'&token='+encodeURIComponent(getToken());
|
||||
document.getElementById('mill-live-marker').innerHTML=' · <b style="color:#ef4444">● 실시간</b>';
|
||||
}
|
||||
function stopMillLive(){
|
||||
if(!millLive)return;
|
||||
millLive=false;
|
||||
const vs=document.getElementById('mill-live');
|
||||
try{vs.disconnectedCallback();}catch{} // WS/WebRTC 연결 정리(라이브러리 내부 정리 로직 재사용, nvr-app closeLive와 동일)
|
||||
vs.style.display='none';
|
||||
const btn=document.getElementById('mill-live-btn');
|
||||
btn.classList.remove('on');btn.textContent='▶ 라이브';
|
||||
document.getElementById('mill-live-marker').innerHTML='';
|
||||
// 스냅샷으로 즉시 복귀 — 단, 장비 탭을 벗어나며 stopEquipTimers가 부른 경우엔 안 그래도 된다.
|
||||
const pane=document.getElementById('pane-equip');
|
||||
if(pane&&pane.classList.contains('active'))refreshMillWidget();
|
||||
}
|
||||
let equipTimer=null;
|
||||
function startEquipTimers(){
|
||||
if(equipTimer)return;
|
||||
@@ -587,9 +630,11 @@ function stopEquipTimers(){
|
||||
clearInterval(equipTimer);
|
||||
equipTimer=null;
|
||||
stopK2Live(); // 장비 탭을 벗어나면 라이브 WebRTC 연결도 닫는다(안 보는 동안 자원 안 쓰기)
|
||||
stopMillLive();
|
||||
}
|
||||
|
||||
function refreshMillWidget(){
|
||||
if(millLive)return; // 라이브 중엔 스냅샷 폴링 건너뜀 — 실시간 비디오가 이미 떠있고 간섭·낭비 방지
|
||||
const img=document.getElementById('mill-frame');
|
||||
img.src='/api/nvr/frame/'+MILL_CHANNEL_ID+'?t='+Date.now();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user