diff --git a/README.md b/README.md index dac5a10..039b00c 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,11 @@ # SileroSilenceSkipperDemo -### Demonstration of using Silero VAD to accelerate parts of a video where there is no spoken content. +### Javascript bookmarklet (and other demos) using Silero VAD to accelerate parts of a video where there is no spoken content. Browser extensions like SilenceSkipper, which rely on volume thresholds, cannot detect the difference between music and dialogue. As such, they often slow down for loud music and speed up for quiet talking, the opposite of what we want. Silero VAD is great at identifying when a person is talking, even with music or other noises in the background, making it ideal for watching content where spoken content is most important, for example, lectures or podcasts. ### NEW: How To use Currently works only on Chromium based browsers (Google Chrome, Microsoft Edge, Brave, etc.) -1. Select all the following and drag it to your bookmarks bar +1. Select all the following and drag it to your bookmarks bar (Ctrl + Shift + B to unhide bookmarks bar if you have it hidden) ``` javascript: (() => { if(window.VADInitialized)console.log("VAD already intialized, resetting..."),window.resetVAD();else{window.VADInitialized=!0;let e,t,n,o=3,l=1.5,d=.5,i=.5,a=2,c=1,r=new AudioContext({sampleRate:44100}),p=0,u=0,m=!1,y=null,g=0;function loadScript1(){var e=document.createElement("script");e.src="https://cdn.jsdelivr.net/npm/onnxruntime-web/dist/ort.js",document.head.appendChild(e),console.log("Script 1 loaded"),e.addEventListener("load",loadScript2)}function loadScript2(){var e=document.createElement("script");e.src="https://cdn.jsdelivr.net/npm/@ricky0123/vad-web/dist/bundle.min.js",document.head.appendChild(e),console.log("Script 2 loaded"),e.addEventListener("load",runVAD)}function runVAD(){function s(){if(m){r.resume(),t=new MediaStreamAudioSourceNode(r,{mediaStream:e.captureStream()});const o=r.createChannelMerger(1);t.connect(o),n.receive(o)}}e=document.querySelector("video"),async function(){m||(n=await vad.AudioNodeVAD.new(r,{frameSamples:512,positiveSpeechThreshold:1,negativeSpeechThreshold:0,onFrameProcessed:t=>{if(t.isSpeech>d)if(c!=l){c=l,e.playbackRate=c,p=0;const t=e.currentTime;if(null!==y){const e=Math.round(1e3*(t-y));console.log(`Sped up video time: ${e}ms`),g+=Math.round(e*(o-1)/(o*l))}console.log("Speech started - slowing down - time saved ",g/1e3)}else p>0&&p--;t.isSpeech=a&&(c=o,e.playbackRate=c,console.log("End of speech - speeding up"),u++,u>=10&&(e.currentTime=e.currentTime,u=0,console.log("Resync video/audio")),y=e.currentTime)),e.playbackRate!=c&&(console.log("FALLBACK: Set playback speed"),e.playbackRate=c)}}));if(0){alert("Hacky way to add bookmarklet title: /VAD Silence Skipper;");}}().then((()=>{m=!0,null===e?(console.log("Unable to find video..."),C.textContent="Unable to find video..."):(C.style.display="none",E.style.display="block",b.style.display="block"),e.paused||t||(s(),n.start())})),e.addEventListener("play",(function(){y=null,console.log("Play event"),t||s(),p=-2,n.start()})),e.addEventListener("pause",(()=>{y=null,console.log("Pause event"),n.pause()})),e.addEventListener("seeked",(()=>{y=null,console.log("Seeked event")})),e.addEventListener("loadeddata",(()=>{y=null,console.log("LoadedData event"),s()}))}loadScript1();const v=document.createElement("div");v.style.position="fixed",v.style.bottom="10px",v.style.right="10px",v.style.zIndex="9999",v.style.backgroundColor="rgba(255, 255, 255, 0.5)",v.style.padding="10px",v.style.borderRadius="5px",v.style.boxShadow="0 0 10px rgba(0, 0, 0, 0.3)",document.body.appendChild(v);const h=document.createElement("div");h.style.display="flex",h.style.alignItems="center",h.style.justifyContent="space-between",h.style.cursor="move";const S=document.createElement("div");S.textContent="VAD Script Settings",S.style.fontSize="14px",S.style.fontWeight="bold",h.appendChild(S);const x=document.createElement("button");x.textContent="-",x.style.cursor="pointer",x.style.marginLeft="10px",x.addEventListener("click",toggleMinimize),h.appendChild(x),v.appendChild(h);const C=document.createElement("div");C.textContent="Loading VAD scripts...",C.style.fontSize="14px",v.appendChild(C);const E=createSlider("Speech Speed",1,5,l,.25,(e=>s(e)));E.style.display="none",v.appendChild(E);const b=createSlider("Skip Speed",1,5,o,.25,(e=>f(e)));b.style.display="none",v.appendChild(b),h.addEventListener("mousedown",startDrag),document.addEventListener("mousemove",handleDrag),document.addEventListener("mouseup",endDrag);let w,L,D=!1;function startDrag(e){D=!0,w=e.clientX-v.getBoundingClientRect().left,L=e.clientY-v.getBoundingClientRect().top}function handleDrag(e){if(D){const t=e.clientX-w,n=e.clientY-L;v.style.left=`${t}px`,v.style.top=`${n}px`,v.style.bottom="auto",v.style.right="auto"}}function endDrag(){D=!1;const e=v.getBoundingClientRect().top,t=v.getBoundingClientRect().left,n=document.documentElement.clientHeight-v.getBoundingClientRect().bottom,o=document.documentElement.clientWidth-v.getBoundingClientRect().right;e{const e=parseFloat(r.value).toFixed(2);c.textContent=`${e}x`,d(e)})),i.appendChild(r),i}function toggleMinimize(){const e=Array.from(v.children).slice(2),t="none"===e[0].style.display;e.forEach((e=>{e.style.display=t?"block":"none"})),x.textContent=t?"-":"+"}function s(e){l=e,y=null}function f(e){o=e,y=null}window.resetVAD=function(){e=document.querySelector("video"),y=null,r.resume(),t=new MediaStreamAudioSourceNode(r,{mediaStream:e.captureStream()});const o=r.createChannelMerger(1);t.connect(o),n.receive(o),n.start(),e.addEventListener("play",(function(){y=null,console.log("Play event"),p=-2,n.start()})),e.addEventListener("pause",(()=>{y=null,console.log("Pause event"),n.pause()})),e.addEventListener("seeked",(()=>{y=null,console.log("Seeked event")})),e.addEventListener("loadeddata",(()=>{y=null,console.log("LoadedData event"),setupVAD()}))}}