TimelapseViewer-CV7RJDuR.js 17 KB

123456789
  1. import{i as e}from"./rolldown-runtime-aKtaBQYM.js";import{C as t,T as n,a as r,k as i,w as a}from"./client-Bw3urp1w.js";import{n as o}from"./QueryClientProvider-C3eWKLmF.js";import{t as s}from"./useQuery-BTfjV-1Z.js";import{t as c}from"./useMutation-CGk77Rd2.js";import{n as l}from"./ToastContext-lCIPyrWa.js";import{t as u}from"./download-C4eI6RUv.js";import{t as d}from"./film-G4l4BuOq.js";import{t as f}from"./gauge-DaLhnNGA.js";import{t as p}from"./loader-circle-C0WA8zwT.js";import{t as m}from"./music-Bi5Vxo1d.js";import{t as ee}from"./pause-BtQbVD2R.js";import{t as h}from"./pencil-1QfU1Xrb.js";import{t as g}from"./play-CbtkkFO3.js";import{t as _}from"./save-DqcH7pRs.js";import{t as v}from"./skip-forward-CH8Rx295.js";import{t as y}from"./trash-2-ByYJ3UBe.js";import{t as b}from"./upload-BJIt5Xy_.js";import{t as x}from"./x-D4CM9tS6.js";import{t as S}from"./Button-B9_qjR81.js";import{l as C}from"./date-G9KUauqz.js";var w=t(`scissors`,[[`circle`,{cx:`6`,cy:`6`,r:`3`,key:`1lh9wr`}],[`path`,{d:`M8.12 8.12 12 12`,key:`1alkpv`}],[`path`,{d:`M20 4 8.12 15.88`,key:`xgtan2`}],[`circle`,{cx:`6`,cy:`18`,r:`3`,key:`fqmcym`}],[`path`,{d:`M14.8 14.8 20 20`,key:`ptml3r`}]]),T=t(`skip-back`,[[`path`,{d:`M17.971 4.285A2 2 0 0 1 21 6v12a2 2 0 0 1-3.029 1.715l-9.997-5.998a2 2 0 0 1-.003-3.432z`,key:`15892j`}],[`path`,{d:`M3 20V4`,key:`1ptbpl`}]]),E=t(`volume-2`,[[`path`,{d:`M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z`,key:`uqj9uw`}],[`path`,{d:`M16 9a5 5 0 0 1 0 6`,key:`1q6k2b`}],[`path`,{d:`M19.364 18.364a9 9 0 0 0 0-12.728`,key:`ijwkga`}]]),D=t(`volume-x`,[[`path`,{d:`M11 4.702a.705.705 0 0 0-1.203-.498L6.413 7.587A1.4 1.4 0 0 1 5.416 8H3a1 1 0 0 0-1 1v6a1 1 0 0 0 1 1h2.416a1.4 1.4 0 0 1 .997.413l3.383 3.384A.705.705 0 0 0 11 19.298z`,key:`uqj9uw`}],[`line`,{x1:`22`,x2:`16`,y1:`9`,y2:`15`,key:`1ewh16`}],[`line`,{x1:`16`,x2:`22`,y1:`9`,y2:`15`,key:`5ykzw1`}]]),O=e(i(),1),k=a(),A=[.25,.5,.75,1,1.5,2,3,4];function j({archiveId:e,timelapseSrc:t,onClose:i,onSave:a}){let{t:u}=n(),{showToast:h}=l(),v=o(),T=(0,O.useRef)(null),j=(0,O.useRef)(null),[M,N]=(0,O.useState)(!1),[P,te]=(0,O.useState)(0),[F,ne]=(0,O.useState)(0),[I,re]=(0,O.useState)(0),[L,R]=(0,O.useState)(0),[z,ie]=(0,O.useState)(1),[B,V]=(0,O.useState)(null),[H,U]=(0,O.useState)(null),[W,ae]=(0,O.useState)(.8),[G,oe]=(0,O.useState)(!1),{data:K,isLoading:se}=s({queryKey:[`timelapse-info`,e],queryFn:()=>r.getTimelapseInfo(e)}),{data:ce}=s({queryKey:[`timelapse-thumbnails`,e],queryFn:()=>r.getTimelapseThumbnails(e,15)}),q=[`timelapse-job`,e],[le]=(0,O.useState)(()=>Date.now()),{data:J,dataUpdatedAt:ue}=s({queryKey:q,queryFn:()=>r.getTimelapseJob(e),refetchInterval:e=>e.state.data?.status===`running`&&1e3}),Y=J?.status===`running`,X=(0,O.useRef)(!1);Y&&ue>=le&&(X.current=!0),(0,O.useEffect)(()=>{!J||J.status===`running`||!X.current||(X.current=!1,J.status===`completed`?(h(J.message??``,`success`),a?.(),i()):J.status===`failed`?h(J.error||u(`timelapseEditor.failed`),`error`):h(u(`timelapseEditor.cancelled`),`info`))},[J,a,i,h,u]);let Z=c({mutationFn:()=>r.cancelTimelapseJob(e),onSuccess:e=>v.setQueryData(q,e),onError:e=>h(e.message,`error`)}),Q=c({mutationFn:()=>r.processTimelapse(e,{trimStart:I,trimEnd:L,speed:z,audioVolume:G?0:W,saveMode:`replace`},B||void 0),onSuccess:e=>{X.current=!0,v.setQueryData(q,e)},onError:e=>{h(e.message||u(`timelapseEditor.failed`),`error`)}});(0,O.useEffect)(()=>{K?.duration&&L===0&&R(K.duration)},[K?.duration,L]),(0,O.useEffect)(()=>{let e=e=>{e.key===`Escape`&&i()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[i]),(0,O.useEffect)(()=>{let e=T.current;if(!e)return;let t=()=>{let t=e.currentTime;te(t),t>=L&&(e.currentTime=I)},n=()=>{ne(e.duration),L===0&&R(e.duration)},r=()=>N(!0),i=()=>N(!1);return e.addEventListener(`timeupdate`,t),e.addEventListener(`durationchange`,n),e.addEventListener(`play`,r),e.addEventListener(`pause`,i),()=>{e.removeEventListener(`timeupdate`,t),e.removeEventListener(`durationchange`,n),e.removeEventListener(`play`,r),e.removeEventListener(`pause`,i)}},[I,L]),(0,O.useEffect)(()=>{let e=j.current,t=T.current;!e||!t||!H||(e.currentTime=t.currentTime,e.playbackRate=t.playbackRate,M&&!G?e.play().catch(()=>{}):e.pause())},[M,H,G]),(0,O.useEffect)(()=>{j.current&&(j.current.volume=G?0:W)},[W,G]),(0,O.useEffect)(()=>{T.current&&(T.current.playbackRate=z),j.current&&(j.current.playbackRate=z)},[z]);let $=(0,O.useCallback)(()=>{let e=T.current;e&&(M?e.pause():(e.currentTime<I&&(e.currentTime=I),e.play()))},[M,I]),de=e=>{let t=T.current;t&&(t.currentTime=Math.max(I,Math.min(L,e)))},fe=e=>{let t=e.target.files?.[0];t&&(H&&URL.revokeObjectURL(H),V(t),U(URL.createObjectURL(t)))},pe=()=>{H&&URL.revokeObjectURL(H),V(null),U(null)};(0,O.useEffect)(()=>()=>{H&&URL.revokeObjectURL(H)},[H]);let me=L-I,he=me/z;return se?(0,k.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/80`,children:(0,k.jsxs)(`div`,{className:`flex items-center gap-3 text-white`,children:[(0,k.jsx)(p,{className:`w-6 h-6 animate-spin`}),`Loading video info...`]})}):(0,k.jsx)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/80`,children:(0,k.jsxs)(`div`,{className:`relative bg-bambu-dark-secondary rounded-xl max-w-5xl w-full mx-4 max-h-[90vh] overflow-hidden flex flex-col`,children:[(0,k.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary shrink-0`,children:[(0,k.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,k.jsx)(d,{className:`w-5 h-5 text-bambu-green`}),`Edit Timelapse`]}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[Y&&(0,k.jsx)(S,{variant:`secondary`,size:`sm`,onClick:()=>Z.mutate(),disabled:Z.isPending,children:u(`common.cancel`)}),(0,k.jsx)(S,{variant:`primary`,size:`sm`,onClick:()=>Q.mutate(),disabled:Q.isPending||Y,children:Q.isPending||Y?(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(p,{className:`w-4 h-4 animate-spin`}),J?.progress!=null&&Y?u(`timelapseEditor.processingPercent`,{percent:Math.round(J.progress*100)}):u(`timelapseEditor.processing`)]}):(0,k.jsxs)(k.Fragment,{children:[(0,k.jsx)(_,{className:`w-4 h-4`}),`Save`]})}),(0,k.jsx)(`button`,{onClick:i,className:`p-1 hover:bg-bambu-dark-tertiary rounded transition-colors`,children:(0,k.jsx)(x,{className:`w-5 h-5 text-bambu-gray`})})]})]}),(0,k.jsxs)(`div`,{className:`flex-1 overflow-y-auto p-4 space-y-4`,children:[(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsx)(`video`,{ref:T,src:t,className:`w-full max-h-[55dvh] object-contain rounded-lg bg-black`,onClick:$,muted:!!H}),!M&&(0,k.jsx)(`button`,{onClick:$,className:`absolute inset-0 flex items-center justify-center bg-black/30 hover:bg-black/40 transition-colors`,children:(0,k.jsx)(`div`,{className:`p-4 bg-bambu-green rounded-full`,children:(0,k.jsx)(g,{className:`w-8 h-8 text-white`})})}),H&&(0,k.jsx)(`audio`,{ref:j,src:H,loop:!0})]}),(0,k.jsxs)(`div`,{className:`space-y-2`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,k.jsx)(w,{className:`w-4 h-4`}),(0,k.jsx)(`span`,{children:`Trim`}),(0,k.jsxs)(`span`,{className:`ml-auto`,children:[C(I),` - `,C(L),` (`,C(me),`)`]})]}),(0,k.jsxs)(`div`,{className:`relative h-16 bg-bambu-dark rounded-lg overflow-hidden`,children:[(0,k.jsx)(`div`,{className:`absolute inset-0 flex`,children:ce?.thumbnails.map((e,t)=>(0,k.jsx)(`div`,{className:`flex-1 bg-cover bg-center`,style:{backgroundImage:`url(data:image/jpeg;base64,${e})`}},t))}),(0,k.jsx)(`div`,{className:`absolute inset-y-0 left-0 bg-black/60`,style:{width:`${I/F*100}%`}}),(0,k.jsx)(`div`,{className:`absolute inset-y-0 right-0 bg-black/60`,style:{width:`${(F-L)/F*100}%`}}),(0,k.jsx)(`div`,{className:`absolute inset-y-0 border-2 border-bambu-green`,style:{left:`${I/F*100}%`,right:`${(F-L)/F*100}%`}}),(0,k.jsx)(`div`,{className:`absolute top-0 bottom-0 w-0.5 bg-white shadow-lg`,style:{left:`${P/F*100}%`}}),(0,k.jsx)(`input`,{type:`range`,min:0,max:F,step:.1,value:I,onChange:e=>{let t=parseFloat(e.target.value);t<L-1&&(re(t),T.current&&T.current.currentTime<t&&(T.current.currentTime=t))},className:`absolute inset-0 w-full opacity-0 cursor-ew-resize`,style:{clipPath:`inset(0 50% 0 0)`}}),(0,k.jsx)(`input`,{type:`range`,min:0,max:F,step:.1,value:L,onChange:e=>{let t=parseFloat(e.target.value);t>I+1&&R(t)},className:`absolute inset-0 w-full opacity-0 cursor-ew-resize`,style:{clipPath:`inset(0 0 0 50%)`}})]}),(0,k.jsx)(`input`,{type:`range`,min:0,max:F,step:.1,value:P,onChange:e=>de(parseFloat(e.target.value)),className:`w-full h-1 bg-bambu-dark-tertiary rounded-lg appearance-none cursor-pointer
  2. [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
  3. [&::-webkit-slider-thumb]:bg-bambu-green [&::-webkit-slider-thumb]:rounded-full
  4. [&::-webkit-slider-thumb]:cursor-pointer`}),(0,k.jsx)(`div`,{className:`flex items-center justify-center gap-2`,children:(0,k.jsx)(`button`,{onClick:$,className:`p-2 bg-bambu-green hover:bg-bambu-green-dark rounded-lg transition-colors`,children:M?(0,k.jsx)(ee,{className:`w-5 h-5 text-white`}):(0,k.jsx)(g,{className:`w-5 h-5 text-white`})})})]}),(0,k.jsxs)(`div`,{className:`space-y-2`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,k.jsx)(f,{className:`w-4 h-4`}),(0,k.jsx)(`span`,{children:`Speed`}),(0,k.jsxs)(`span`,{className:`ml-auto`,children:[z,`x (output: `,C(he),`)`]})]}),(0,k.jsx)(`div`,{className:`flex gap-1`,children:A.map(e=>(0,k.jsxs)(`button`,{onClick:()=>ie(e),className:`flex-1 px-2 py-2 text-sm rounded transition-colors ${z===e?`bg-bambu-green text-white`:`bg-bambu-dark text-bambu-gray hover:bg-bambu-dark-tertiary`}`,children:[e,`x`]},e))})]}),(0,k.jsxs)(`div`,{className:`space-y-2`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2 text-sm text-bambu-gray`,children:[(0,k.jsx)(m,{className:`w-4 h-4`}),(0,k.jsx)(`span`,{children:`Music Overlay`})]}),B?(0,k.jsxs)(`div`,{className:`flex items-center gap-3 p-3 bg-bambu-dark rounded-lg`,children:[(0,k.jsx)(m,{className:`w-5 h-5 text-bambu-green`}),(0,k.jsxs)(`div`,{className:`flex-1 min-w-0`,children:[(0,k.jsx)(`p`,{className:`text-sm text-white truncate`,children:B.name}),(0,k.jsxs)(`p`,{className:`text-xs text-bambu-gray`,children:[(B.size/1024/1024).toFixed(1),` MB`]})]}),(0,k.jsx)(`button`,{onClick:()=>oe(!G),className:`p-2 hover:bg-bambu-dark-tertiary rounded transition-colors`,children:G?(0,k.jsx)(D,{className:`w-4 h-4 text-bambu-gray`}):(0,k.jsx)(E,{className:`w-4 h-4 text-bambu-green`})}),(0,k.jsx)(`input`,{type:`range`,min:0,max:1,step:.1,value:W,onChange:e=>ae(parseFloat(e.target.value)),className:`w-20 h-1 bg-bambu-dark-tertiary rounded-lg appearance-none cursor-pointer
  5. [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
  6. [&::-webkit-slider-thumb]:bg-bambu-green [&::-webkit-slider-thumb]:rounded-full`}),(0,k.jsx)(`button`,{onClick:pe,className:`p-2 hover:bg-red-100 dark:hover:bg-red-500/20 rounded transition-colors`,children:(0,k.jsx)(y,{className:`w-4 h-4 text-red-600 dark:text-red-400`})})]}):(0,k.jsxs)(`label`,{className:`flex flex-col items-center justify-center gap-2 p-6 border-2 border-dashed border-bambu-dark-tertiary rounded-lg cursor-pointer hover:border-bambu-green/50 transition-colors`,children:[(0,k.jsx)(b,{className:`w-8 h-8 text-bambu-gray`}),(0,k.jsx)(`span`,{className:`text-sm text-bambu-gray`,children:`Drop audio file or click to upload`}),(0,k.jsx)(`span`,{className:`text-xs text-bambu-gray/60`,children:`MP3, WAV, M4A, AAC, OGG`}),(0,k.jsx)(`input`,{type:`file`,accept:`.mp3,.wav,.m4a,.aac,.ogg,audio/*`,onChange:fe,className:`hidden`})]})]}),(0,k.jsxs)(`div`,{className:`p-3 bg-bambu-dark rounded-lg text-sm space-y-1`,children:[(0,k.jsxs)(`p`,{className:`text-bambu-gray`,children:[(0,k.jsx)(`span`,{className:`text-white`,children:`Original:`}),` `,C(F),` @ `,K?.width,`x`,K?.height]}),(0,k.jsxs)(`p`,{className:`text-bambu-gray`,children:[(0,k.jsx)(`span`,{className:`text-white`,children:`Output:`}),` `,C(he),` @ `,z,`x speed`,B&&` + music overlay`]})]})]}),Q.isPending&&(0,k.jsxs)(`div`,{className:`absolute inset-0 bg-black/80 flex flex-col items-center justify-center gap-4`,children:[(0,k.jsx)(p,{className:`w-12 h-12 text-bambu-green animate-spin`}),(0,k.jsx)(`p`,{className:`text-white text-lg`,children:`Processing timelapse...`}),(0,k.jsx)(`p`,{className:`text-bambu-gray text-sm`,children:`This may take a few moments`})]})]})})}var M=[.25,.5,.75,1,1.5,2,3,4];function N({src:e,title:t,downloadFilename:r,archiveId:i,onClose:a,onEdit:o}){let{t:s}=n(),c=(0,O.useRef)(null),[l,f]=(0,O.useState)(!0),[p,m]=(0,O.useState)(1),[_,y]=(0,O.useState)(0),[b,w]=(0,O.useState)(0),[E,D]=(0,O.useState)(!1);(0,O.useEffect)(()=>{let e=c.current;e&&(e.playbackRate=p)},[p]),(0,O.useEffect)(()=>{let e=e=>{e.key===`Escape`&&a()};return window.addEventListener(`keydown`,e),()=>window.removeEventListener(`keydown`,e)},[a]),(0,O.useEffect)(()=>{let e=c.current;if(!e)return;let t=()=>y(e.currentTime),n=()=>w(e.duration),r=()=>f(!0),i=()=>f(!1);return e.addEventListener(`timeupdate`,t),e.addEventListener(`durationchange`,n),e.addEventListener(`play`,r),e.addEventListener(`pause`,i),()=>{e.removeEventListener(`timeupdate`,t),e.removeEventListener(`durationchange`,n),e.removeEventListener(`play`,r),e.removeEventListener(`pause`,i)}},[]);let A=()=>{let e=c.current;e&&(l?e.pause():e.play())};return(0,k.jsxs)(`div`,{className:`fixed inset-0 z-50 flex items-center justify-center bg-black/80`,children:[(0,k.jsxs)(`div`,{"data-testid":`timelapse-viewer`,className:`relative bg-bambu-dark-secondary rounded-xl max-w-4xl w-full mx-4 max-h-[calc(100dvh-2rem)] overflow-y-auto`,children:[(0,k.jsxs)(`div`,{className:`flex items-center justify-between p-4 border-b border-bambu-dark-tertiary`,children:[(0,k.jsxs)(`h3`,{className:`text-lg font-semibold text-white flex items-center gap-2`,children:[(0,k.jsx)(d,{className:`w-5 h-5 text-bambu-green`}),t]}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[i&&(0,k.jsxs)(S,{variant:`secondary`,size:`sm`,onClick:()=>D(!0),children:[(0,k.jsx)(h,{className:`w-4 h-4`}),s(`common.edit`)]}),(0,k.jsxs)(S,{variant:`secondary`,size:`sm`,onClick:()=>{let t=document.createElement(`a`);t.href=e,t.download=r,t.click()},children:[(0,k.jsx)(u,{className:`w-4 h-4`}),s(`common.download`)]}),(0,k.jsx)(`button`,{onClick:a,className:`p-1 hover:bg-bambu-dark-tertiary rounded transition-colors`,children:(0,k.jsx)(x,{className:`w-5 h-5 text-bambu-gray`})})]})]}),(0,k.jsxs)(`div`,{className:`p-4`,children:[(0,k.jsx)(`video`,{ref:c,src:e,autoPlay:!0,className:`w-full max-h-[calc(100dvh-14rem)] object-contain bg-black rounded-lg`,onClick:A}),(0,k.jsxs)(`div`,{className:`mt-4 space-y-3`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-3`,children:[(0,k.jsx)(`span`,{className:`text-xs text-bambu-gray w-12 text-right`,children:C(_)}),(0,k.jsx)(`input`,{type:`range`,min:0,max:b||100,value:_,onChange:e=>{let t=c.current;t&&(t.currentTime=parseFloat(e.target.value))},className:`flex-1 h-1 bg-bambu-dark-tertiary rounded-lg appearance-none cursor-pointer
  7. [&::-webkit-slider-thumb]:appearance-none [&::-webkit-slider-thumb]:w-3 [&::-webkit-slider-thumb]:h-3
  8. [&::-webkit-slider-thumb]:bg-bambu-green [&::-webkit-slider-thumb]:rounded-full
  9. [&::-webkit-slider-thumb]:cursor-pointer`}),(0,k.jsx)(`span`,{className:`text-xs text-bambu-gray w-12`,children:C(b)})]}),(0,k.jsxs)(`div`,{className:`flex items-center justify-between`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(`button`,{onClick:()=>{let e=c.current;e&&(e.currentTime=Math.max(0,e.currentTime-5))},className:`p-2 hover:bg-bambu-dark-tertiary rounded-lg transition-colors`,title:s(`timelapseViewer.skipBack5s`),children:(0,k.jsx)(T,{className:`w-5 h-5 text-bambu-gray`})}),(0,k.jsx)(`button`,{onClick:A,className:`p-2 bg-bambu-green hover:bg-bambu-green-dark rounded-lg transition-colors`,children:l?(0,k.jsx)(ee,{className:`w-5 h-5 text-white`}):(0,k.jsx)(g,{className:`w-5 h-5 text-white`})}),(0,k.jsx)(`button`,{onClick:()=>{let e=c.current;e&&(e.currentTime=Math.min(b,e.currentTime+5))},className:`p-2 hover:bg-bambu-dark-tertiary rounded-lg transition-colors`,title:s(`timelapseViewer.skipForward5s`),children:(0,k.jsx)(v,{className:`w-5 h-5 text-bambu-gray`})})]}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(`span`,{className:`text-sm text-bambu-gray whitespace-nowrap`,children:s(`timelapseViewer.speed`)}),(0,k.jsx)(`div`,{className:`flex gap-1`,children:M.map(e=>(0,k.jsxs)(`button`,{onClick:()=>m(e),className:`px-2 py-1 text-xs rounded transition-colors ${p===e?`bg-bambu-green text-white`:`bg-bambu-dark-tertiary text-bambu-gray hover:bg-bambu-dark-tertiary/80`}`,children:[e,`x`]},e))})]})]})]})]})]}),E&&i&&(0,k.jsx)(j,{archiveId:i,timelapseSrc:e,onClose:()=>D(!1),onSave:o})]})}export{N as t};