CameraPage-DaU4aAdP.js 14 KB

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