Spaces:
Running on Zero
Running on Zero
Download assets/script.js from fffiloni/ZONOS3-Mini: direct link, hf CLI and curl.
- Browser
- Download file 3.89 kB
-
https://huggingface.co/spaces/fffiloni/ZONOS3-Mini/resolve/main/assets/script.js
- Command line
-
hf download hf://spaces/fffiloni/ZONOS3-Mini/assets/script.js
-
curl -L -o script.js https://huggingface.co/spaces/fffiloni/ZONOS3-Mini/resolve/main/assets/script.js
3.89 kB
| const host=document.getElementById('script-input'); | |
| const draft=element.querySelector('textarea'), viewport=element.querySelector('.reading-window'); | |
| const track=element.querySelector('.reading-track'), edit=element.querySelector('[data-edit]'); | |
| const hint=element.querySelector('#script-hint'), pages=element.querySelector('[data-pages]'); | |
| let take=null, reading=false, clock=0, page=0, pageCount=1, spans=[], lineHeight=35; | |
| const listeners=new AbortController(); | |
| const on=(node,event,fn)=>node.addEventListener(event,fn,{signal:listeners.signal}); | |
| draft.value=props.value || ''; | |
| function publish() { props.value=draft.value; host.dataset.draft=draft.value; } | |
| function showMode() { | |
| draft.hidden=reading; viewport.hidden=!reading; | |
| edit.hidden=!take; edit.textContent=reading?'Edit text':'View take'; | |
| pages.hidden=!reading || take?.alignment==='ready' || pageCount<2; | |
| hint.textContent=reading?(take.alignment==='ready'?'': 'Word timing unavailable'):'Write your text · '+draft.value.length+'/600'; | |
| if(reading && take.text!==draft.value) hint.textContent='Previous take'; | |
| } | |
| function layout() { | |
| if(!reading || !spans.length) return; | |
| track.style.transform='none'; | |
| lineHeight=parseFloat(getComputedStyle(viewport).lineHeight); | |
| spans.forEach(s=>s.line=Math.max(0,Math.round(s.node.offsetTop/lineHeight))); | |
| pageCount=Math.max(1,Math.ceil((Math.max(...spans.map(s=>s.line))+1)/2)); | |
| renderClock(); showMode(); | |
| } | |
| function renderClock() { | |
| if(!reading || !take) return; | |
| if(take.alignment==='ready') { | |
| let index=-1; | |
| for(let i=0;i<spans.length;i++) { | |
| const spoken=clock>=spans[i].start; | |
| spans[i].node.classList.toggle('spoken',spoken); | |
| if(spoken) index=i; | |
| } | |
| page=index<0?0:Math.floor(spans[index].line/2); | |
| } else spans.forEach(s=>s.node.classList.add('spoken')); | |
| page=Math.max(0,Math.min(pageCount-1,page)); | |
| track.style.transform=`translateY(${-page*2*lineHeight}px)`; | |
| element.querySelector('[data-previous]').disabled=page===0; | |
| element.querySelector('[data-next]').disabled=page===pageCount-1; | |
| } | |
| function receive(data) { | |
| if(!data?.text) return; | |
| take=data; clock=0; page=0; track.replaceChildren(); | |
| const words=data.alignment==='ready' && data.words?.length?data.words: | |
| (data.text.match(/\S+\s*|\s+/gu)||[data.text]).map(text=>({text,start:0,end:0})); | |
| spans=words.map(word=>{ | |
| const node=document.createElement('span'); node.className='word'; node.textContent=word.text; | |
| track.append(node); return {...word,node,line:0}; | |
| }); | |
| reading=true; showMode(); requestAnimationFrame(layout); | |
| } | |
| on(draft,'input',()=>{publish();showMode();}); | |
| on(edit,'click',()=>{ | |
| reading=!reading; | |
| if(!reading) document.getElementById('speech-player')?.dispatchEvent(new CustomEvent('zonos:pause')); | |
| showMode(); if(reading) layout(); else draft.focus(); | |
| }); | |
| on(element.querySelector('[data-previous]'),'click',()=>{page--;renderClock();}); | |
| on(element.querySelector('[data-next]'),'click',()=>{page++;renderClock();}); | |
| on(host,'zonos:take',e=>receive(e.detail)); | |
| on(host,'zonos:clock',e=>{ | |
| clock=e.detail.time; | |
| if(e.detail.playing && !reading){reading=true;showMode();layout();} | |
| renderClock(); | |
| }); | |
| watch('value',()=>{if(props.value!==draft.value){draft.value=props.value||'';reading=false;showMode();}host.dataset.draft=draft.value;}); | |
| // Layout writes can resize Gradio's outer wrapper. Defer them outside the | |
| // observer delivery cycle to avoid a ResizeObserver feedback warning in WebKit. | |
| let resizeFrame=0; | |
| const resize=new ResizeObserver(()=>{ | |
| if(resizeFrame)return; | |
| resizeFrame=requestAnimationFrame(()=>{resizeFrame=0;if(element.isConnected)layout();}); | |
| });resize.observe(viewport); | |
| const observer=new MutationObserver(()=>{if(!element.isConnected){listeners.abort();cancelAnimationFrame(resizeFrame);resize.disconnect();observer.disconnect();}}); | |
| observer.observe(document.documentElement,{childList:true,subtree:true}); | |
| publish();showMode(); | |
| host.dataset.ready='true'; | |