CameraPage-14haujuN.js 14 KB

1
  1. import{i as e}from"./rolldown-runtime-aKtaBQYM.js";import{C as t,S as n,T as r,a as i,d as ee,k as a,l as te,w as o}from"./client-DSw2TdH4.js";import{d as ne,f as re}from"./chunk-62JRHF6Z-DiDTZQg1.js";import{n as ie}from"./QueryClientProvider-B5vEWYBq.js";import{t as s}from"./useQuery-DfiorXB9.js";import{t as ae}from"./useMutation-DLyYCmQ0.js";import{t as oe}from"./camera-Cx_MQ-FA.js";import{n as se}from"./ToastContext-C3zxW_t3.js";import{a as ce,i as le,n as ue,r as de,t as fe}from"./CameraDiagnoseModal-BydfnYfD.js";import{t as pe}from"./refresh-cw-D7pR-PbA.js";import{t as me}from"./stethoscope-BNkaxpyE.js";import{t as he}from"./triangle-alert-Bb8T_5WO.js";import{t as ge}from"./wifi-off-2Cy9fC-p.js";import{n as _e,t as ve}from"./zoom-out-CV8N-4f5.js";import{n as ye}from"./AuthContext-DM3YxV_q.js";import{n as be}from"./index-DPuWk1vL.js";import{n as xe,t as Se}from"./useCameraViewerId-D30-3MSQ.js";var Ce=t(`maximize`,[[`path`,{d:`M8 3H5a2 2 0 0 0-2 2v3`,key:`1dcmit`}],[`path`,{d:`M21 8V5a2 2 0 0 0-2-2h-3`,key:`1e4gt3`}],[`path`,{d:`M3 16v3a2 2 0 0 0 2 2h3`,key:`wsl5sc`}],[`path`,{d:`M16 21h3a2 2 0 0 0 2-2v-3`,key:`18trek`}]]),c=e(a(),1),l=o(),u=5,we=2e3,Te=2e3,Ee=3e4,De=5e3;function d(){let{t:e}=r(),t=ie(),{showToast:a}=se(),{hasPermission:o,authEnabled:d,user:Oe}=ye(),{printerId:ke}=ne(),f=parseInt(ke||`0`,10),[Ae]=re(),je=parseInt(Ae.get(`fps`)||`15`,10),Me=Math.min(Math.max(isNaN(je)?15:je,1),30);be();let{data:Ne,isPending:Pe}=s({queryKey:[`camera-stream-token`,Oe?.id??null],queryFn:()=>i.getCameraStreamToken(),enabled:!d||!!Oe,staleTime:3e3*1e3}),p=Ne?.token??ee(),[m,Fe]=(0,c.useState)(`stream`),[Ie,Le]=(0,c.useState)(!1),[Re,h]=(0,c.useState)(!1),[g,_]=(0,c.useState)(!1),[v,y]=(0,c.useState)(!0),[b,x]=(0,c.useState)(Date.now()),[S,C]=(0,c.useState)(!1),[ze,Be]=(0,c.useState)(!1),[w,T]=(0,c.useState)(0),[E,D]=(0,c.useState)(!1),[Ve,He]=(0,c.useState)(0),[O,k]=(0,c.useState)(1),[A,j]=(0,c.useState)({x:0,y:0}),[M,N]=(0,c.useState)(!1),[P,Ue]=(0,c.useState)({x:0,y:0}),[We,F]=(0,c.useState)(null),[I,L]=(0,c.useState)(null),R=(0,c.useRef)(null),z=Se(),Ge=xe(R),B=(0,c.useRef)(null),V=(0,c.useRef)(null),H=(0,c.useRef)(null),U=(0,c.useRef)(null),W=(0,c.useRef)(0),G=(0,c.useRef)(!1),K=(0,c.useRef)(null),{data:q}=s({queryKey:[`printer`,f],queryFn:()=>i.getPrinter(f),enabled:f>0}),{data:J}=s({queryKey:[`printerStatus`,f],queryFn:()=>i.getPrinterStatus(f),refetchInterval:3e4,enabled:f>0}),Ke=ae({mutationFn:e=>i.setChamberLight(f,e),onMutate:async e=>{await t.cancelQueries({queryKey:[`printerStatus`,f]});let n=t.getQueryData([`printerStatus`,f]);return t.setQueryData([`printerStatus`,f],t=>({...t,chamber_light:e})),{previousStatus:n}},onSuccess:(e,t)=>{a(`Chamber light ${t?`on`:`off`}`)},onError:(n,r,i)=>{i?.previousStatus&&t.setQueryData([`printerStatus`,f],i.previousStatus),a(n.message||e(`printers.toast.failedToControlChamberLight`),`error`)}}),Y=(J?.state===`RUNNING`||J?.state===`PAUSE`)&&(J?.printable_objects_count??0)>=2;(0,c.useEffect)(()=>(q&&(document.title=`${q.name} - Camera`),()=>{document.title=`Bambuddy`}),[q]);let X=(0,c.useRef)(!1);(0,c.useEffect)(()=>{let e=`/api/v1/printers/${f}/camera/stop?viewer=${z}`;X.current=!1;let t=()=>{if(f>0&&!X.current){X.current=!0;let t={},n=te();n&&(t.Authorization=`Bearer ${n}`),fetch(e,{method:`POST`,keepalive:!0,headers:t}).catch(()=>{})}},n=()=>{t()};return window.addEventListener(`beforeunload`,n),()=>{window.removeEventListener(`beforeunload`,n),t()}},[f,z]),(0,c.useEffect)(()=>{if(v&&!S){let e=setTimeout(()=>{y(!1)},m===`stream`?3e3:2e4);return()=>clearTimeout(e)}},[m,v,b,S]),(0,c.useEffect)(()=>{let e=()=>{let e=!!document.fullscreenElement;Be(e),k(1),j({x:0,y:0}),m===`stream`&&!S&&(R.current&&(R.current.src=``),setTimeout(()=>{y(!0),x(Date.now())},200))};return document.addEventListener(`fullscreenchange`,e),()=>document.removeEventListener(`fullscreenchange`,e)},[m,S]),(0,c.useEffect)(()=>{let e,t=()=>{clearTimeout(e),e=setTimeout(()=>{localStorage.setItem(`cameraWindowState`,JSON.stringify({width:window.outerWidth,height:window.outerHeight,left:window.screenX,top:window.screenY}))},500)};return window.addEventListener(`resize`,t),()=>{clearTimeout(e),window.removeEventListener(`resize`,t)}},[]),(0,c.useEffect)(()=>()=>{V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),U.current&&clearInterval(U.current),K.current&&clearTimeout(K.current)},[]);let Z=(0,c.useCallback)(()=>{if(w>=u){D(!1),_(!0);return}let e=Math.min(Te*2**w,Ee);D(!0),He(Math.ceil(e/1e3)),H.current=setInterval(()=>{He(e=>e<=1?(H.current&&clearInterval(H.current),0):e-1)},1e3),V.current=setTimeout(()=>{T(e=>e+1),D(!1),y(!0),_(!1),R.current&&(R.current.src=``),x(Date.now())},e)},[w]);(0,c.useEffect)(()=>{if(m!==`stream`||v||E||S){U.current&&=(clearInterval(U.current),null);return}return W.current=0,U.current=setInterval(async()=>{try{let e=await i.getCameraStatus(f);if(!(e.stalled||!e.active&&!g)){W.current=0;return}if(W.current+=1,W.current<2)return;W.current=0,console.log(`Stream issue detected: stalled=${e.stalled}, active=${e.active}, reconnecting...`),U.current&&=(clearInterval(U.current),null),y(!1),Z()}catch{}},De),()=>{U.current&&=(clearInterval(U.current),null)}},[m,v,g,E,S,f,Z]);let qe=e=>{e.currentTarget.getAttribute(`src`)&&(y(!1),m===`stream`&&w<u?Z():m===`snapshot`&&!G.current?(G.current=!0,K.current&&clearTimeout(K.current),K.current=setTimeout(()=>{K.current=null,x(Date.now())},we)):_(!0))},Je=()=>{if(G.current=!1,y(!1),_(!1),T(0),W.current=0,D(!1),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),R.current&&!localStorage.getItem(`cameraWindowState`)){let e=R.current,t=e.naturalWidth,n=e.naturalHeight;if(t>0&&n>0){let e=window.outerWidth-window.innerWidth,r=window.outerHeight-window.innerHeight,i=t+16+e,ee=n+45+16+r;try{window.resizeTo(i,ee)}catch{}}}},Ye=()=>{if(f>0){let e={},t=te();t&&(e.Authorization=`Bearer ${t}`),fetch(`/api/v1/printers/${f}/camera/stop?viewer=${z}`,{method:`POST`,headers:e}).catch(()=>{})}},Xe=e=>{m===e||S||(C(!0),y(!0),_(!1),T(0),G.current=!1,D(!1),k(1),j({x:0,y:0}),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),R.current&&(R.current.src=``),m===`stream`&&Ye(),setTimeout(()=>{Fe(e),x(Date.now()),C(!1)},100))},Q=()=>{S||(G.current=!1,C(!0),y(!0),_(!1),T(0),D(!1),V.current&&clearTimeout(V.current),H.current&&clearInterval(H.current),R.current&&(R.current.src=``),m===`stream`&&Ye(),setTimeout(()=>{x(Date.now()),C(!1)},100))},Ze=()=>{B.current&&(document.fullscreenElement?document.exitFullscreen():B.current.requestFullscreen())},Qe=()=>{k(e=>Math.min(e+.5,4))},$e=()=>{k(e=>{let t=Math.max(e-.5,1);return t===1&&j({x:0,y:0}),t})},et=e=>{e.preventDefault(),e.deltaY<0?Qe():$e()},tt=e=>{O>1&&(e.preventDefault(),N(!0),Ue({x:e.clientX-A.x,y:e.clientY-A.y}))},nt=(0,c.useCallback)(()=>{if(!B.current)return{x:300,y:200};let e=B.current.getBoundingClientRect(),t=e.width*(O-1)/2,n=e.height*(O-1)/2;return{x:Math.max(50,t),y:Math.max(50,n)}},[O]),rt=e=>{if(M&&O>1){let t=e.clientX-P.x,n=e.clientY-P.y,r=nt();j({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},it=()=>{N(!1)},at=e=>{if(e.length<2)return 0;let t=e[0].clientX-e[1].clientX,n=e[0].clientY-e[1].clientY;return Math.sqrt(t*t+n*n)},ot=e=>e.length<2?{x:e[0].clientX,y:e[0].clientY}:{x:(e[0].clientX+e[1].clientX)/2,y:(e[0].clientY+e[1].clientY)/2},st=e=>{e.touches.length===2?(e.preventDefault(),F(at(e.touches)),L(ot(e.touches))):e.touches.length===1&&O>1&&(e.preventDefault(),N(!0),Ue({x:e.touches[0].clientX-A.x,y:e.touches[0].clientY-A.y}))},ct=e=>{if(e.touches.length===2&&We!==null){e.preventDefault();let t=at(e.touches),n=t/We;k(e=>{let t=Math.max(1,Math.min(4,e*n));return t===1&&j({x:0,y:0}),t}),F(t);let r=ot(e.touches);if(I){let e=nt();j(t=>({x:Math.max(-e.x,Math.min(e.x,t.x+(r.x-I.x))),y:Math.max(-e.y,Math.min(e.y,t.y+(r.y-I.y)))}))}L(r)}else if(e.touches.length===1&&M&&O>1){e.preventDefault();let t=e.touches[0].clientX-P.x,n=e.touches[0].clientY-P.y,r=nt();j({x:Math.max(-r.x,Math.min(r.x,t)),y:Math.max(-r.y,Math.min(r.y,n))})}},lt=e=>{e.touches.length<2&&(F(null),L(null)),e.touches.length===0&&N(!1)},ut=()=>{k(1),j({x:0,y:0})},dt=S||!p&&(d||Pe)?``:(e=>p?`${e}&token=${encodeURIComponent(p)}`:n(e))(m===`stream`?`/api/v1/printers/${f}/camera/stream?fps=${Me}&t=${b}&viewer=${z}`:`/api/v1/printers/${f}/camera/snapshot?t=${b}`),$=v||S||E;return f?(0,l.jsxs)(`div`,{ref:B,className:`min-h-screen bg-black flex flex-col`,children:[(0,l.jsxs)(`div`,{className:`flex items-center justify-between px-4 py-2 bg-bambu-dark-secondary border-b border-bambu-dark-tertiary`,children:[(0,l.jsxs)(`h1`,{className:`text-sm font-medium text-white flex items-center gap-2`,children:[(0,l.jsx)(oe,{className:`w-4 h-4`}),q?.name||`Printer ${f}`]}),(0,l.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,l.jsxs)(`div`,{className:`flex bg-bambu-dark rounded p-0.5`,children:[(0,l.jsx)(`button`,{onClick:()=>Xe(`stream`),disabled:$,className:`px-3 py-1 text-xs rounded transition-colors ${m===`stream`?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white disabled:opacity-50`}`,children:e(`camera.live`)}),(0,l.jsx)(`button`,{onClick:()=>Xe(`snapshot`),disabled:$,className:`px-3 py-1 text-xs rounded transition-colors ${m===`snapshot`?`bg-bambu-green text-white`:`text-bambu-gray hover:text-white disabled:opacity-50`}`,children:e(`camera.snapshot`)})]}),(0,l.jsx)(`button`,{onClick:()=>Ke.mutate(!J?.chamber_light),disabled:!J?.connected||Ke.isPending||!o(`printers:control`),className:`p-1.5 rounded disabled:opacity-50 ${J?.chamber_light?`bg-yellow-500/20 hover:bg-yellow-500/30`:`hover:bg-bambu-dark-tertiary`}`,title:o(`printers:control`)?e(`camera.chamberLight`):e(`printers.permission.noControl`),children:(0,l.jsx)(le,{on:J?.chamber_light??!1,className:`w-4 h-4`})}),(0,l.jsx)(`button`,{onClick:()=>Le(!0),disabled:!Y||!o(`printers:control`),className:`p-1.5 rounded disabled:opacity-50 ${Y&&o(`printers:control`)?`hover:bg-bambu-dark-tertiary`:``}`,title:o(`printers:control`)?e(Y?`printers.skipObjects.tooltip`:`printers.skipObjects.onlyWhilePrinting`):e(`printers.permission.noControl`),children:(0,l.jsx)(ue,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:Q,disabled:$,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded disabled:opacity-50`,title:e(m===`stream`?`camera.restartStream`:`camera.refreshSnapshot`),children:(0,l.jsx)(pe,{className:`w-4 h-4 text-bambu-gray ${$?`animate-spin`:``}`})}),(0,l.jsx)(`button`,{onClick:()=>h(!0),className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:e(`camera.diagnose.button`),children:(0,l.jsx)(me,{className:`w-4 h-4 text-bambu-gray`})}),(0,l.jsx)(`button`,{onClick:Ze,className:`p-1.5 hover:bg-bambu-dark-tertiary rounded`,title:e(ze?`camera.exitFullscreen`:`camera.fullscreen`),children:ze?(0,l.jsx)(ce,{className:`w-4 h-4 text-bambu-gray`}):(0,l.jsx)(Ce,{className:`w-4 h-4 text-bambu-gray`})})]})]}),(0,l.jsx)(`div`,{className:`flex-1 flex items-center justify-center p-2 overflow-hidden`,onWheel:et,onMouseMove:rt,onMouseUp:it,onMouseLeave:it,onTouchStart:st,onTouchMove:ct,onTouchEnd:lt,style:{touchAction:`none`},children:(0,l.jsxs)(`div`,{className:`relative w-full h-full flex items-center justify-center`,children:[(v||S)&&!E&&(0,l.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/50 z-10`,children:(0,l.jsxs)(`div`,{className:`text-center`,children:[(0,l.jsx)(pe,{className:`w-8 h-8 text-bambu-gray animate-spin mx-auto mb-2`}),(0,l.jsx)(`p`,{className:`text-sm text-bambu-gray`,children:e(m===`stream`?`camera.connectingToCamera`:`camera.capturingSnapshot`)})]})}),E&&(0,l.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black/80 z-10`,children:(0,l.jsxs)(`div`,{className:`text-center p-4`,children:[(0,l.jsx)(ge,{className:`w-10 h-10 text-orange-400 mx-auto mb-3`}),(0,l.jsx)(`p`,{className:`text-white mb-2`,children:e(`camera.connectionLost`)}),(0,l.jsx)(`p`,{className:`text-sm text-bambu-gray mb-3`,children:e(`camera.reconnecting`,{countdown:Ve,attempt:Math.min(w+1,u),max:u})}),(0,l.jsx)(`button`,{onClick:Q,className:`px-4 py-2 bg-bambu-green text-white text-sm rounded hover:bg-bambu-green/80 transition-colors`,children:e(`camera.reconnectNow`)})]})}),g&&!E&&(0,l.jsx)(`div`,{className:`absolute inset-0 flex items-center justify-center bg-black z-10`,children:(0,l.jsxs)(`div`,{className:`text-center p-4`,children:[(0,l.jsx)(he,{className:`w-12 h-12 text-orange-400 mx-auto mb-3`}),(0,l.jsx)(`p`,{className:`text-white mb-2`,children:e(`camera.cameraUnavailable`)}),(0,l.jsx)(`p`,{className:`text-xs text-bambu-gray mb-4 max-w-md`,children:e(`camera.cameraUnavailableDesc`)}),(0,l.jsxs)(`div`,{className:`flex gap-2 justify-center`,children:[(0,l.jsx)(`button`,{onClick:Q,className:`px-4 py-2 bg-bambu-green text-white rounded hover:bg-bambu-green/80 transition-colors`,children:e(`camera.retry`)}),(0,l.jsx)(`button`,{onClick:()=>h(!0),className:`px-4 py-2 bg-bambu-dark border border-bambu-dark-tertiary text-bambu-gray hover:text-white rounded transition-colors`,children:e(`camera.diagnose.button`)})]})]})}),(0,l.jsx)(`img`,{ref:Ge,src:dt,alt:e(`camera.cameraStream`),className:`max-w-full max-h-full object-contain select-none`,style:{transform:`scale(${O}) translate(${A.x/O}px, ${A.y/O}px) rotate(${q?.camera_rotation||0}deg)`,...q?.camera_rotation===90||q?.camera_rotation===270?{maxWidth:`100vh`,maxHeight:`100vw`}:{},cursor:O>1?M?`grabbing`:`grab`:`default`},onError:dt?qe:void 0,onLoad:dt?Je:void 0,onMouseDown:tt,draggable:!1},b),(0,l.jsxs)(`div`,{className:`absolute bottom-4 left-4 flex items-center gap-1.5 bg-black/60 rounded-lg px-2 py-1.5`,children:[(0,l.jsx)(`button`,{onClick:$e,disabled:O<=1,className:`p-1.5 hover:bg-white/10 rounded disabled:opacity-30`,title:e(`camera.zoomOut`),children:(0,l.jsx)(ve,{className:`w-4 h-4 text-white`})}),(0,l.jsxs)(`button`,{onClick:ut,className:`px-2 py-1 text-sm text-white hover:bg-white/10 rounded min-w-[48px]`,title:e(`camera.resetZoom`),children:[Math.round(O*100),`%`]}),(0,l.jsx)(`button`,{onClick:Qe,disabled:O>=4,className:`p-1.5 hover:bg-white/10 rounded disabled:opacity-30`,title:e(`camera.zoomIn`),children:(0,l.jsx)(_e,{className:`w-4 h-4 text-white`})})]})]})}),(0,l.jsx)(de,{printerId:f,isOpen:Ie,onClose:()=>Le(!1)}),Re&&(0,l.jsx)(fe,{printerId:f,printerName:q?.name||null,onClose:()=>h(!1)})]}):(0,l.jsx)(`div`,{className:`min-h-screen bg-black flex items-center justify-center`,children:(0,l.jsx)(`p`,{className:`text-white`,children:e(`camera.invalidPrinterId`)})})}export{d as CameraPage};