diff --git a/dist/vot-min.user.js b/dist/vot-min.user.js index 356fe5fd..9a068be7 100644 --- a/dist/vot-min.user.js +++ b/dist/vot-min.user.js @@ -262,4 +262,4 @@ >`,100*(this.data?.autoVolume??ee),0,100),this.votSettingsDialog.bodyContainer.appendChild(this.votAutoSetVolumeSlider.container),this.votShowVideoSliderCheckbox=Me.createCheckbox(H.get("VOTShowVideoSlider"),this.data?.showVideoSlider??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votShowVideoSliderCheckbox.container),this.votAudioBoosterCheckbox=Me.createCheckbox(H.get("VOTAudioBooster"),this.data?.audioBooster??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votAudioBoosterCheckbox.container),this.votSyncVolumeCheckbox=Me.createCheckbox(H.get("VOTSyncVolume"),this.data?.syncVolume??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votSyncVolumeCheckbox.container),this.votTranslationServiceSelect=Me.createVOTSelect(_.syncGet("translationService",oe).toUpperCase(),H.get("VOTTranslationService"),Ze(Pe,_.syncGet("translationService",oe)),{onSelectCb:async t=>{this.data.translationService=t.target.dataset.votValue,await _.set("translationService",this.data.translationService)},labelElement:Me.createCheckbox(H.get("VOTTranslateAPIErrors"),this.data.translateAPIErrors??!0).container}),this.votTranslationServiceSelect.container.hidden="ru"===H.lang,this.votSettingsDialog.bodyContainer.appendChild(this.votTranslationServiceSelect.container),this.votDetectServiceSelect=Me.createVOTSelect(_.syncGet("detectService",ne).toUpperCase(),H.get("VOTDetectService"),Ze(Ee,_.syncGet("detectService",ne)),{onSelectCb:async t=>{this.data.detectService=t.target.dataset.votValue,await _.set("detectService",this.data.detectService)},labelElement:Me.createVOTSelectLabel(H.get("VOTDetectService"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votDetectServiceSelect.container),this.votSubtitlesHeader=Me.createHeader(H.get("subtitlesSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesHeader),this.votSubtitlesDetails=Me.createDetails(H.get("VOTSubtitlesDesign")),this.votSettingsDialog.bodyContainer.appendChild(this.votSubtitlesDetails.container),this.votProxyHeader=Me.createHeader(H.get("proxySettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votProxyHeader),this.votM3u8ProxyHostTextfield=Me.createTextfield(H.get("VOTM3u8ProxyHost"),this.data?.m3u8ProxyHost,Qt),this.votSettingsDialog.bodyContainer.appendChild(this.votM3u8ProxyHostTextfield.container),this.votProxyWorkerHostTextfield=Me.createTextfield(H.get("VOTProxyWorkerHost"),this.data?.proxyWorkerHost,Xt),this.votSettingsDialog.bodyContainer.appendChild(this.votProxyWorkerHostTextfield.container),this.votAudioProxyCheckbox=Me.createCheckbox(H.get("VOTAudioProxy"),this.data?.audioProxy??!1),this.votSettingsDialog.bodyContainer.appendChild(this.votAudioProxyCheckbox.container),this.votAboutHeader=Me.createHeader(H.get("about")),this.votSettingsDialog.bodyContainer.appendChild(this.votAboutHeader),this.votLanguageSelect=Me.createVOTSelect(H.get("langs")[_.syncGet("locale-lang-override","auto")],H.get("VOTMenuLanguage"),Ze(z,_.syncGet("locale-lang-override","auto")),{onSelectCb:async t=>{await _.set("locale-lang-override",t.target.dataset.votValue)},labelElement:Me.createVOTSelectLabel(H.get("VOTMenuLanguage"))}),this.votSettingsDialog.bodyContainer.appendChild(this.votLanguageSelect.container),this.votShowPiPButtonCheckbox=Me.createCheckbox(H.get("VOTShowPiPButton"),this.data?.showPiPButton??!1),this.votShowPiPButtonCheckbox.container.hidden=!B(),this.votSettingsDialog.bodyContainer.appendChild(this.votShowPiPButtonCheckbox.container),this.votVersionInfo=Me.createInformation(`${H.get("VOTVersion")}:`,GM_info.script.version),this.votSettingsDialog.bodyContainer.appendChild(this.votVersionInfo.container),this.votAuthorsInfo=Me.createInformation(`${H.get("VOTAuthors")}:`,GM_info.script.author),this.votSettingsDialog.bodyContainer.appendChild(this.votAuthorsInfo.container),this.votLoaderInfo=Me.createInformation(`${H.get("VOTLoader")}:`,`${GM_info.scriptHandler} v${GM_info.version}`),this.votSettingsDialog.bodyContainer.appendChild(this.votLoaderInfo.container),this.votBrowserInfo=Me.createInformation(`${H.get("VOTBrowser")}:`,`${Je.browser.name} ${Je.browser.version} (${Je.os.name} ${Je.os.version})`),this.votSettingsDialog.bodyContainer.appendChild(this.votBrowserInfo.container),this.votResetSettingsButton=Me.createButton(H.get("resetSettings")),this.votSettingsDialog.bodyContainer.appendChild(this.votResetSettingsButton)}initUIEvents(){this.votButton.translateButton.addEventListener("click",(()=>{(async()=>{if(this.audio.src)return I.log("[click translationBtn] audio.src is not empty"),void this.stopTranslate();if(this.hls.url)return I.log("[click translationBtn] hls is not empty"),void this.stopTranslate();try{if(I.log("[click translationBtn] trying execute translation"),!this.videoData.videoId)throw new rt("VOTNoVideoIDFound");"vk"===this.site.host&&"clips"===this.site.additionalData&&(this.videoData=await this.getVideoData()),await this.translateExecutor(this.videoData.videoId)}catch(t){console.error("[VOT]",t),"VOTLocalizedError"===t?.name?this.transformBtn("error",t.localizedMessage):this.transformBtn("error",t)}})()})),this.votButton.pipButton.addEventListener("click",(()=>{(async()=>{this.video!==document.pictureInPictureElement?await this.video.requestPictureInPicture():await document.exitPictureInPicture()})()})),this.votButton.menuButton.addEventListener("click",(()=>{this.votMenu.container.hidden=!this.votMenu.container.hidden})),this.votButton.container.addEventListener("mousedown",(()=>{this.dragging=!0})),this.container.addEventListener("mouseup",(()=>{this.dragging=!1})),this.container.addEventListener("mousemove",(async t=>{if(this.dragging){t.preventDefault();const e=t.clientX/this.container.clientWidth*100;this.data.buttonPos=this.container.clientWidth&&this.container.clientWidth>550?e<=44?"left":e>=66?"right":"default":"default",this.votButton.container.dataset.direction="default"===this.data.buttonPos?"row":"column",this.votButton.container.dataset.position=this.data.buttonPos,this.votMenu.container.dataset.position=this.data.buttonPos,this.container.clientWidth&&this.container.clientWidth>550&&await _.set("buttonPos",this.data.buttonPos)}})),this.votDownloadButton.addEventListener("click",(()=>{this.downloadTranslationUrl&&window.open(this.downloadTranslationUrl,"_blank").focus()})),this.votDownloadSubtitlesButton.addEventListener("click",(async()=>{const t=function(t,e="srt"){const o=t.subtitles.map(((t,o)=>{const n=t.startMs/1e3,i=(t.startMs+t.durationMs)/1e3;return("srt"===e?`${o+1}\n`:"")+`${ct(n)} --\x3e ${ct(i)}\n${t.text}\n\n`})).join("").trim();return"vtt"===e?`WEBVTT\n\n${o}`:o}(this.yandexSubtitles,"srt"),e=new Blob([t],{type:"text/plain"}),o=URL.createObjectURL(e),n=document.createElement("a");n.href=o,n.download=`subtitles_${this.videoData.videoId}.srt`,n.click(),URL.revokeObjectURL(o)})),this.votSettingsButton.addEventListener("click",(()=>{this.votSettingsDialog.container.hidden=!this.votSettingsDialog.container.hidden,(document.fullscreenElement||document.webkitFullscreenElement)&&(document.webkitExitFullscreen&&document.webkitExitFullscreen(),document.exitFullscreen&&document.exitFullscreen())})),this.votVideoVolumeSlider.input.addEventListener("input",(t=>{const e=Number(t.target.value);this.votVideoVolumeSlider.label.querySelector("strong").textContent=`${e}%`,this.setVideoVolume(e/100),this.data.syncVolume&&this.syncVolumeWrapper("video",e)})),this.votVideoTranslationVolumeSlider.input.addEventListener("input",(t=>{(async()=>{this.data.defaultVolume=Number(t.target.value),await _.set("defaultVolume",this.data.defaultVolume),this.votVideoTranslationVolumeSlider.label.querySelector("strong").textContent=`${this.data.defaultVolume}%`,this.gainNode.gain.value=this.data.defaultVolume/100,this.data.syncVolume&&(this.syncVolumeWrapper("translation",this.data.defaultVolume),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData&&this.setVideoVolume(this.tempOriginalVolume/100))})()})),this.votAutoTranslateCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.autoTranslate=Number(t.target.checked),await _.set("autoTranslate",this.data.autoTranslate),await this.autoTranslate(),I.log("autoTranslate value changed. New value: ",this.data.autoTranslate)})()})),this.votDontTranslateYourLangSelect.labelElement.addEventListener("change",(t=>{(async()=>{this.data.dontTranslateYourLang=Number(t.target.checked),await _.set("dontTranslateYourLang",this.data.dontTranslateYourLang),I.log("dontTranslateYourLang value changed. New value: ",this.data.dontTranslateYourLang)})()})),this.votAutoSetVolumeCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.autoSetVolumeYandexStyle=Number(t.target.checked),await _.set("autoSetVolumeYandexStyle",this.data.autoSetVolumeYandexStyle),I.log("autoSetVolumeYandexStyle value changed. New value: ",this.data.autoSetVolumeYandexStyle)})()})),this.votAutoSetVolumeSlider.input.addEventListener("input",(t=>{(async()=>{const e=Number(t.target.value);this.data.autoVolume=(e/100).toFixed(2),await _.set("autoVolume",this.data.autoVolume),this.votAutoSetVolumeSlider.label.querySelector("strong").textContent=`${e}%`})()})),this.votShowVideoSliderCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showVideoSlider=Number(t.target.checked),await _.set("showVideoSlider",this.data.showVideoSlider),I.log("showVideoSlider value changed. New value: ",this.data.showVideoSlider),this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status})()})),this.votAudioBoosterCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.audioBooster=Number(t.target.checked),await _.set("audioBooster",this.data.audioBooster),I.log("audioBooster value changed. New value: ",this.data.audioBooster);const e=this.votVideoTranslationVolumeSlider.input.value;this.votVideoTranslationVolumeSlider.input.max=this.data.audioBooster?900:100,this.data.audioBooster||(this.votVideoTranslationVolumeSlider.input.value=e>100?100:e,this.votVideoTranslationVolumeSlider.input.dispatchEvent(new Event("input")))})()})),this.votSyncVolumeCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.syncVolume=Number(t.target.checked),await _.set("syncVolume",this.data.syncVolume),I.log("syncVolume value changed. New value: ",this.data.syncVolume)})()})),this.votTranslationServiceSelect.labelElement.addEventListener("change",(t=>{(async()=>{this.data.translateAPIErrors=Number(t.target.checked),await _.set("translateAPIErrors",this.data.translateAPIErrors),I.log("translateAPIErrors value changed. New value: ",this.data.translateAPIErrors)})()})),this.votSubtitlesDetails.container.addEventListener("click",(()=>{this.votSubtitlesDialog=Me.createDialog(H.get("VOTSubtitlesDesign")),this.votSubtitlesDialog.container.classList.add("vot-dialog-temp"),this.votSubtitlesDialog.container.hidden=!1,this.votSubtitlesDialog.backdrop.onclick=this.votSubtitlesDialog.closeButton.onclick=()=>{this.votSubtitlesDialog.container.remove()},this.votSubtitlesHighlightWordsCheckbox=Me.createCheckbox(H.get("VOTHighlightWords"),this.data?.highlightWords??!1),this.votSubtitlesDialog.bodyContainer.appendChild(this.votSubtitlesHighlightWordsCheckbox.container),this.votSubtitlesMaxLengthSlider=Me.createSlider(It`${H.get("VOTSubtitlesMaxLength")}: ${this.data?.subtitlesMaxLength??300}`,this.data?.subtitlesMaxLength??300,50,300),this.votSubtitlesDialog.bodyContainer.appendChild(this.votSubtitlesMaxLengthSlider.container),this.votSubtitlesFontSizeSlider=Me.createSlider(It`${H.get("VOTSubtitlesFontSize")}: ${this.data?.subtitlesFontSize??20}`,this.data?.subtitlesFontSize??20,8,50),this.votSubtitlesDialog.bodyContainer.appendChild(this.votSubtitlesFontSizeSlider.container),this.votSubtitlesOpacitySlider=Me.createSlider(It`${H.get("VOTSubtitlesOpacity")}: - ${this.data?.subtitlesOpacity??20}`,this.data?.subtitlesOpacity??20,0,100),this.votSubtitlesDialog.bodyContainer.appendChild(this.votSubtitlesOpacitySlider.container),this.votSubtitlesHighlightWordsCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.highlightWords=Number(t.target.checked),await _.set("highlightWords",this.data.highlightWords),I.log("highlightWords value changed. New value: ",this.data.highlightWords),this.subtitlesWidget.setHighlightWords(this.data.highlightWords)})()})),this.votSubtitlesMaxLengthSlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesMaxLength=Number(t.target.value),await _.set("subtitlesMaxLength",this.data.subtitlesMaxLength),this.votSubtitlesMaxLengthSlider.label.querySelector("strong").textContent=`${this.data.subtitlesMaxLength}`,this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength)})()})),this.votSubtitlesFontSizeSlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesFontSize=Number(t.target.value),await _.set("subtitlesFontSize",this.data.subtitlesFontSize),this.votSubtitlesFontSizeSlider.label.querySelector("strong").textContent=`${this.data.subtitlesFontSize}`,this.subtitlesWidget.setFontSize(this.data.subtitlesFontSize)})()})),this.votSubtitlesOpacitySlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesOpacity=Number(t.target.value),await _.set("subtitlesOpacity",this.data.subtitlesOpacity),this.votSubtitlesOpacitySlider.label.querySelector("strong").textContent=`${this.data.subtitlesOpacity}`,this.subtitlesWidget.setOpacity(this.data.subtitlesOpacity)})()})),document.documentElement.appendChild(this.votSubtitlesDialog.container)})),this.votShowPiPButtonCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showPiPButton=Number(t.target.checked),await _.set("showPiPButton",this.data.showPiPButton),I.log("showPiPButton value changed. New value: ",this.data.showPiPButton),this.votButton.pipButton.hidden=!B()||!this.data.showPiPButton,this.votButton.separator2.hidden=!B()||!this.data.showPiPButton})()})),this.votM3u8ProxyHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.m3u8ProxyHost=t.target.value||Qt,await _.set("m3u8ProxyHost",this.data.m3u8ProxyHost),I.log("m3u8ProxyHost value changed. New value: ",this.data.m3u8ProxyHost)})()})),this.votProxyWorkerHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.proxyWorkerHost=t.target.value||Xt,await _.set("proxyWorkerHost",this.data.proxyWorkerHost),I.log("proxyWorkerHost value changed. New value: ",this.data.proxyWorkerHost),this.votClient.host=this.data.proxyWorkerHost})()})),this.votAudioProxyCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.audioProxy=Number(t.target.checked),await _.set("audioProxy",this.data.audioProxy),I.log("audioProxy value changed. New value: ",this.data.audioProxy)})()})),this.votResetSettingsButton.addEventListener("click",(()=>{(async()=>{H.reset();const t=await _.list();for(let e=0;e{this.extraEvents.push({element:t,event:e,handler:o}),t.addEventListener(e,o)},e=(e,o,n)=>{for(const i of o)t(e,i,n)};if(this.resizeObserver=new ResizeObserver((t=>{for(let e=0;e550;this.votButton.container.dataset.position=this.votMenu.container.dataset.position=e?this.data?.buttonPos:"default",this.votButton.container.dataset.direction=this.data?.buttonPos&&"default"!==this.data?.buttonPos&&e?"column":"row"})),this.resizeObserver.observe(this.video),this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData){this.syncVolumeObserver=new MutationObserver((t=>{if(this.audio.src&&this.data.syncVolume)for(let e=0;e{const e=t.target,o=this.votButton.container,n=this.votMenu.container,i=this.container,a=this.votSettingsDialog.container,r=document.querySelector(".vot-dialog-temp"),s=o.contains(e),l=n.contains(e),d=i.contains(e),u=a.contains(e),c=r?.contains(e)??!1;I.log(`[document click] ${s} ${l} ${d} ${u} ${c}`),s||l||u||c||(d||this.logout(0),this.votMenu.container.hidden=!0)})),o="pornhub"===this.site.host?"embed"===this.site.additionalData?document.querySelector("#player"):this.container.querySelector(".mgp_eventCatcher"):"twitter"===this.site.host?document.querySelector('div[data-testid="videoPlayer"]'):"yandexdisk"===this.site.host?document.querySelector(".video-player__player"):this.container,o&&e(o,["mousemove","mouseout"],this.resetTimerBound),t(this.votButton.container,"mousemove",this.changeOpacityOnEventBound),t(this.votMenu.container,"mousemove",this.changeOpacityOnEventBound),e(document,["touchstart","touchmove","touchend"],this.changeOpacityOnEventBound),t(this.votButton.container,"mousedown",(t=>{t.stopImmediatePropagation()})),t(this.votMenu.container,"mousedown",(t=>{t.stopImmediatePropagation()})),"youtube"===this.site.host&&(this.container.draggable=!1),"googledrive"===this.site.host&&(this.container.style.height="100%"),t(this.video,"canplay",(async()=>{"rutube"===this.site.host&&this.video.src||await it(this.site,this.video)!==this.videoData.videoId&&(await this.handleSrcChanged(),I.log("lipsync mode is loadeddata"),await this.autoTranslate())})),t(this.video,"emptied",(async()=>{this.video.src&&await it(this.site,this.video)===this.videoData.videoId||(I.log("lipsync mode is emptied"),this.videoData="",this.stopTranslation())})),["rutube","ok"].includes(this.site.host)||t(this.video,"volumechange",(()=>{this.syncVideoVolumeSlider()}))}logout(t){this.votMenu.container.hidden&&(this.votButton.container.style.opacity=t)}resetTimer(){clearTimeout(this.timer),this.logout(1),this.timer=setTimeout((()=>{this.logout(0)}),1e3)}changeOpacityOnEvent(t){clearTimeout(this.timer),this.logout(1),t.stopPropagation()}async changeSubtitlesLang(t){if(I.log("[onchange] subtitles",t),this.votSubtitlesSelect.setSelected(t),"disabled"===t)this.votSubtitlesSelect.setTitle(H.get("VOTSubtitlesDisabled")),this.subtitlesWidget.setContent(null),this.votDownloadSubtitlesButton.hidden=!0,this.yandexSubtitles=null;else{const e=this.subtitlesList.at(parseInt(t));if(1===this.data.audioProxy&&e.url.startsWith("https://brosubs.s3-private.mds.yandex.net/vtrans/")){const t=e.url.replace("https://brosubs.s3-private.mds.yandex.net/vtrans/","");e.url=`https://${this.data.proxyWorkerHost}/video-subtitles/subtitles-proxy/${t}`,console.log(`[VOT] Subs proxied via ${e.url}`)}this.yandexSubtitles=await qe(e),this.subtitlesWidget.setContent(this.yandexSubtitles),this.votDownloadSubtitlesButton.hidden=!1}}async updateSubtitlesLangSelect(){const t=[{label:H.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1},...this.subtitlesList.map(((t,e)=>({label:(H.get("langs")[t.language]??t.language.toUpperCase())+(t.translatedFromLanguage?` ${H.get("VOTTranslatedFrom")} ${H.get("langs")[t.translatedFromLanguage]??t.translatedFromLanguage.toUpperCase()}`:"")+("yandex"!==t.source?` ${t.source}`:"")+(t.isAutoGenerated?` (${H.get("VOTAutogenerated")})`:""),value:e,selected:!1,disabled:!1})))];this.votSubtitlesSelect.updateItems(t),await this.changeSubtitlesLang(t[0].value)}async updateSubtitles(){if(await this.changeSubtitlesLang("disabled"),!this.videoData.videoId)return console.error(`[VOT] ${H.getDefault("VOTNoVideoIDFound")}`),this.subtitlesList=[],this.subtitlesListVideoId=null,this.votButton.container.hidden=!0,void await this.updateSubtitlesLangSelect();if(this.votButton.container.hidden=!1,this.subtitlesListVideoId!==this.videoData.videoId){try{this.subtitlesList=await ze(this.votClient,this.videoData)}catch(t){if("Unsupported video URL for getting subtitles"===t?.unlocalizedMessage)return void(this.subtitlesList=[]);I.log("Error with yandex server, try auto-fix...",t),this.votOpts={fetchFn:q,hostVOT:te,host:this.data.proxyWorkerHost},this.votClient=new ut(this.votOpts),this.subtitlesList=await ze(this.votClient,this.videoData),await _.set("translateProxyEnabled",1)}this.subtitlesList?this.subtitlesListVideoId=this.videoData.videoId:await this.changeSubtitlesLang("disabled"),await this.updateSubtitlesLangSelect()}}getVideoVolume(){let t=this.video?.volume;return["youtube","googledrive"].includes(this.site.host)&&(t=Be.getVideoVolume()??t),t}setVideoVolume(t){if(["youtube","googledrive"].includes(this.site.host)){if(Be.setVideoVolume(t))return}this.video.volume=t}isMuted(){return["youtube","googledrive"].includes(this.site.host)?Be.isMuted():this.video?.muted}syncVideoVolumeSlider(){const t=this.isMuted()?0:100*this.getVideoVolume(),e=Math.round(t);this.votVideoVolumeSlider.input.value=e,this.votVideoVolumeSlider.label.querySelector("strong").textContent=`${e}%`,Me.updateSlider(this.votVideoVolumeSlider.input),1===this.data.syncVolume&&(this.tempOriginalVolume=Number(e))}setSelectMenuValues(t,e){this.votTranslationLanguageSelect.fromSelect.setTitle(H.get("langs")[t]),this.votTranslationLanguageSelect.toSelect.setTitle(H.get("langs")[e]),this.votTranslationLanguageSelect.fromSelect.setSelected(t),this.votTranslationLanguageSelect.toSelect.setSelected(e),console.log(`[VOT] Set translation from ${t} to ${e}`),this.videoData.detectedLanguage=t,this.videoData.responseLanguage=e}syncVolumeWrapper(t,e){const o="translation"===t?this.votVideoVolumeSlider:this.votVideoTranslationVolumeSlider,n=Number(o.input.value),i=function(t,e,o,n){let i=e;return e>n?(i=o+(e-n),i=i>100?100:Math.max(i,0),t.volume=i/100):e100?100:Math.max(i,0),t.volume=i/100),i}("translation"===t?this.video:this.audio,e,n,"translation"===t?this.tempVolume:this.tempOriginalVolume);o.input.value=i,o.label.querySelector("strong").textContent=`${i}%`,Me.updateSlider(o.input),this.tempOriginalVolume="translation"===t?i:e,this.tempVolume="translation"===t?e:i}async getVideoData(){const{duration:t,url:e,videoId:o,host:n,translationHelp:i,detectedLanguage:a}=await at(this.site,this.video),r={translationHelp:i??null,isStream:!1,duration:this.video?.duration||t||y.defaultDuration,videoId:o,url:e,host:n,detectedLanguage:a??this.translateFromLang,responseLanguage:this.translateToLang};if("youtube"===this.site.host){const t=await Be.getVideoData();r.isStream=t.isLive,t.title&&(r.detectedLanguage=t.detectedLanguage)}else if(["rutube","ok.ru","mail_ru"].includes(this.site.host))r.detectedLanguage="ru";else if("youku"===this.site.host)r.detectedLanguage="zh";else if("vk"===this.site.host){const t=document.getElementsByTagName("track")?.[0]?.srclang;r.detectedLanguage=t||"auto"}else"weverse"===this.site.host?r.detectedLanguage="ko":["bilibili","piped","invidious","bitchute","rumble","peertube","dailymotion","trovo","yandexdisk","coursehunter","archive","directlink"].includes(this.site.host)&&(r.detectedLanguage="auto");return r}videoValidator(){if(["youtube","ok.ru","vk"].includes(this.site.host)&&(I.log("VideoValidator videoData: ",this.videoData),1===this.data.dontTranslateYourLang&&this.videoData.detectedLanguage===this.data.dontTranslateLanguage))throw new rt("VOTDisableFromYourLang");if(!this.videoData.isStream&&this.videoData.duration>14400)throw new rt("VOTVideoIsTooLong");return!0}lipSync(t=!1){if(I.log("lipsync video",this.video),this.video)if(this.audio.currentTime=this.video.currentTime,this.audio.playbackRate=this.video.playbackRate,t)if("play"!=t)["pause","stop","waiting"].includes(t)&&(I.log(`lipsync mode is ${t}`),this.audio.pause()),"playing"==t&&(I.log("lipsync mode is playing"),this.audio.play());else{I.log("lipsync mode is play");const t=this.audio.play();void 0!==t&&t.catch((async t=>{if(console.error("[VOT]",t),"NotAllowedError"===t.name)throw this.transformBtn("error",H.get("grantPermissionToAutoPlay")),new rt("grantPermissionToAutoPlay")}))}else I.log("lipsync mode is not set")}handleVideoEvent(t){I.log(`video ${t.type}`),this.lipSync(t.type)}stopTranslate(){for(const t of Ke)this.video.removeEventListener(t,this.handleVideoEventBound);this.audio.pause(),this.audio.src="",this.audio.removeAttribute("src"),this.votVideoVolumeSlider.container.hidden=!0,this.votVideoTranslationVolumeSlider.container.hidden=!0,this.votDownloadButton.hidden=!0,this.downloadTranslationUrl=null,this.transformBtn("none",H.get("translateVideo")),I.log(`Volume on start: ${this.volumeOnStart}`),this.volumeOnStart&&this.setVideoVolume(this.volumeOnStart),this.volumeOnStart="",clearInterval(this.streamPing),clearTimeout(this.autoRetry),this.hls?.destroy(),this.hls=D(),this.firstSyncVolume=!0}async translateExecutor(t){I.log("Run translateFunc",t),await this.translateFunc(t,this.videoData.isStream,this.videoData.detectedLanguage,this.videoData.responseLanguage,this.videoData.translationHelp)}async updateTranslationErrorMsg(t){const e=H.get("translationTake"),o=H.lang;if(["Подготавливаем перевод","Видео передано в обработку","Ожидаем перевод видео","Загружаем переведенное аудио"].includes(t)&&this.setLoadingBtn(!0),"VOTLocalizedError"===t?.name)this.transformBtn("error",t.localizedMessage);else if(t instanceof Error)this.transformBtn("error",t?.message);else if(1!==this.data.translateAPIErrors||t.includes(e)||"ru"===o)this.transformBtn("error",t);else{this.setLoadingBtn(!0);const e=await async function(t,e="",o="ru"){switch(await _.get("translationService",oe)){case"yandex":{const n=e&&o?`${e}-${o}`:o;return await Ae.translate(t,n)}case"deepl":return await Ce.translate(t,e,o);default:return t}}(t,"ru",o);this.transformBtn("error",e)}}afterUpdateTranslation(t){this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status,this.votVideoTranslationVolumeSlider.container.hidden="success"!==this.votButton.container.dataset.status,1===this.data.autoSetVolumeYandexStyle&&(this.votVideoVolumeSlider.input.value=100*this.data.autoVolume,this.votVideoVolumeSlider.label.querySelector("strong").textContent=100*this.data.autoVolume+"%",Me.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=t}async updateTranslation(t){if(this.cachedTranslation?.url===this.audio.currentSrc)I.log("[translateFunc] Audio src is the same"),this.audio.src=t;else{try{const e=await q(t,{method:"HEAD",timeout:5e3});if(I.log("Test audio response",e),404===e.status){I.log("Yandex returned not valid audio, trying to fix...");let e=await this.translateVideoImpl(this.videoData,this.videoData.detectedLanguage="auto",this.videoData.responseLanguage,this.videoData.translationHelp);this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage),t=e.url,I.log("Fixed audio audioUrl",t)}else I.log("Valid audioUrl",t)}catch(t){"Timeout"===t.message?(I.log("Request timed out. Handling timeout error..."),this.data.audioProxy=1,await _.set("audioProxy",1)):I.log("Test audio error:",t)}this.audio.src=t;try{await this.audio.play()}catch(t){if(console.error("[VOT]",t),"NotSupportedError"===t.name){if([...V,...M].includes(window.location.hostname))throw new rt("VOTMediaCSPError");this.data.audioProxy=1,await _.set("audioProxy",1)}}}if(1===this.data.audioProxy&&t.startsWith("https://vtrans.s3-private.mds.yandex.net/tts/prod/")){const e=t.replace("https://vtrans.s3-private.mds.yandex.net/tts/prod/","");t=`https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${e}`,console.log(`[VOT] Audio proxied via ${t}`)}if(this.audio.src=t,this.volumeOnStart||(this.volumeOnStart=this.getVideoVolume()),this.setupAudioSettings(),"twitter"===this.site.host)document.querySelector('button[data-testid="app-bar-back"][role="button"]').addEventListener("click",this.stopTranslationBound);this.video&&!this.video.paused&&this.lipSync("play");for(const t of Ke)this.video.addEventListener(t,this.handleVideoEventBound);this.transformBtn("success",H.get("disableTranslate")),this.afterUpdateTranslation(t)}async translateFunc(t,e,o,n,i){if(console.log("[VOT] Video Data: ",this.videoData),I.log("Run videoValidator"),this.videoValidator(),this.setLoadingBtn(!0),e){let t=await this.translateStreamImpl(this.videoData,o,n);if(!t)return void I.log("Skip translation");this.transformBtn("success",H.get("disableTranslate"));const e=`https://${this.data.m3u8ProxyHost}/?all=yes&origin=${encodeURIComponent("https://strm.yandex.ru")}&referer=${encodeURIComponent("https://strm.yandex.ru")}&url=${encodeURIComponent(t.result.url)}`;if(this.hls)this.setupHLS(e);else{if(!this.audio.canPlayType("application/vnd.apple.mpegurl"))throw new rt("audioFormatNotSupported");this.audio.src=e}if("youtube"===this.site.host&&Be.videoSeek(this.video,10),this.setupAudioSettings(),!this.video.src&&!this.video.currentSrc&&!this.video.srcObject)return this.stopTranslation();this.video&&!this.video.paused&&this.lipSync("play");for(const t of Ke)this.video.addEventListener(t,this.handleVideoEventBound);return this.afterUpdateTranslation(e)}if(this.cachedTranslation=this.videoTranslations.find((e=>e.videoId===t&&e.expires>Date.now()/1e3&&e.from===o&&e.to===n)),this.cachedTranslation)return await this.updateTranslation(this.cachedTranslation.url),void I.log("[translateFunc] Cached translation was received");let a=await this.translateVideoImpl(this.videoData,o,n,i);I.log("[translateRes]",a),a?(await this.updateTranslation(a.url),[k.kick,k.reddit,k.patreon,k.kodik,k.appledeveloper].includes(this.site.host)||this.subtitlesList.some((t=>"yandex"===t.source&&t.translatedFromLanguage===this.videoData.detectedLanguage&&t.language===this.videoData.responseLanguage))||(this.subtitlesList=await ze(this.votClient,this.videoData),await this.updateSubtitlesLangSelect()),this.videoTranslations.push({videoId:t,from:o,to:n,url:this.downloadTranslationUrl,expires:Date.now()/1e3+this.videoTranslationTTL})):I.log("Skip translation")}setupHLS(t){this.hls.on(Hls.Events.MEDIA_ATTACHED,(function(){I.log("audio and hls.js are now bound together !")})),this.hls.on(Hls.Events.MANIFEST_PARSED,(function(t){I.log("manifest loaded, found "+t?.levels?.length+" quality level")})),this.hls.loadSource(t),this.hls.attachMedia(this.audio),this.hls.on(Hls.Events.ERROR,(function(t){if(t.fatal)switch(t.type){case Hls.ErrorTypes.MEDIA_ERROR:console.log("fatal media error encountered, try to recover"),this.hls.recoverMediaError();break;case Hls.ErrorTypes.NETWORK_ERROR:console.error("fatal network error encountered",t);break;default:this.hls.destroy()}})),I.log(this.hls)}setupAudioSettings(){"number"==typeof this.data.defaultVolume&&(this.gainNode.gain.value=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume)}stopTranslation(){this.stopTranslate(),this.syncVideoVolumeSlider()}async handleSrcChanged(){I.log("[VideoHandler] src changed",this),this.firstPlay=!0,this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage);const t=!this.video.src&&!this.video.currentSrc&&!this.video.srcObject;this.votButton.container.hidden=t,t&&(this.votMenu.container.hidden=t),this.site.selector||(this.container=this.video.parentElement),this.container.contains(this.votButton.container)||(this.container.appendChild(this.votButton.container),this.container.appendChild(this.votMenu.container)),await this.updateSubtitles(),await this.changeSubtitlesLang("disabled"),this.translateToLang=this.data.responseLanguage??"ru"}async release(){I.log("[VideoHandler] release"),this.initialized=!1,this.releaseExtraEvents(),this.subtitlesWidget.release(),this.votButton.container.remove(),this.votMenu.container.remove()}}const Xe=new class{constructor(){this.videoCache=new Set,this.onVideoAdded=new Ue,this.onVideoRemoved=new Ue,this.observer=new MutationObserver(this.handleMutations),this.intersectionObserver=new IntersectionObserver(this.handleIntersections,{threshold:.1})}handleMutations=t=>{window.requestIdleCallback((()=>{for(let e=0;e{for(let e=0;e{if(!t)return;const n=t.querySelectorAll("video");for(let t=0;t{this.videoCache.has(t)||(this.videoCache.add(t),this.intersectionObserver.observe(t))};handleIntersectingVideo=t=>{this.intersectionObserver.unobserve(t),(t=>{if(We.test(t.className)||We.test(t.title))return!0;let e=t.parentElement;for(;e;){if(We.test(e.className)||We.test(e.id))return!0;e=e.parentElement}return!1})(t)||t.hasAttribute("muted")?I.log("The promotional/muted video was ignored",t):((t,e)=>{const o=()=>{(t=>t.readyState>=3)(t)?e(t):requestAnimationFrame(o)};o()})(t,this.handleVideoAdded)};handleVideoAdded=t=>{this.onVideoAdded.dispatch(t)};handleVideoRemoved=t=>{document.contains(t)||(this.videoCache.delete(t),this.onVideoRemoved.dispatch(t))}},to=new WeakMap;function eo(t,e){if(t.shadowRoot){let o=t.selector?Array.from(document.querySelectorAll(t.selector)).find((t=>t.shadowRoot.contains(e))):e.parentElement;return o&&o.shadowRoot?o.parentElement:o}const o=Je.browser.version.split(".")[0];if(t.selector?.includes(":not")&&t.selector?.includes("*")&&o&&("Chrome"===Je.browser.name&&Number(o)<88||"Firefox"===Je.browser.name&&Number(o)<84)){const o=t.selector.split(" *")[0];return o?Array.from(document.querySelectorAll(o)).find((t=>t.contains(e))):e.parentElement}return t.selector?Array.from(document.querySelectorAll(t.selector)).find((t=>t.contains(e))):e.parentElement}(async function(){I.log("Loading extension..."),await H.update(),I.log(`Selected menu language: ${H.lang}`),Xe.onVideoAdded.addListener((t=>{for(const e of function(){if(/(http(s)?:\/\/)(127\.0\.0\.1|localhost)/.exec(window.location.href))return[];const t=window.location.hostname,e=new URL(window.location),o=o=>o instanceof RegExp?o.test(t):"string"==typeof o?t.includes(o):"function"==typeof o&&o(e);return A.filter((t=>(Array.isArray(t.match)?t.match.some(o):o(t.match))&&t.host&&t.url))}()){if(!e)continue;let o=eo(e,t);if(o&&(("rumble"!==e.host||t.style.display)&&(["peertube","directlink"].includes(e.host)&&(e.url=window.location.origin),!to.has(t)))){to.set(t,new Qe(t,o,e));break}}})),Xe.onVideoRemoved.addListener((async t=>{to.has(t)&&(await to.get(t).release(),to.delete(t))})),Xe.enable()})().catch((t=>{console.error("[VOT]",t)}))})()})(); \ No newline at end of file + ${this.data?.subtitlesOpacity??20}`,this.data?.subtitlesOpacity??20,0,100),this.votSubtitlesDialog.bodyContainer.appendChild(this.votSubtitlesOpacitySlider.container),this.votSubtitlesHighlightWordsCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.highlightWords=Number(t.target.checked),await _.set("highlightWords",this.data.highlightWords),I.log("highlightWords value changed. New value: ",this.data.highlightWords),this.subtitlesWidget.setHighlightWords(this.data.highlightWords)})()})),this.votSubtitlesMaxLengthSlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesMaxLength=Number(t.target.value),await _.set("subtitlesMaxLength",this.data.subtitlesMaxLength),this.votSubtitlesMaxLengthSlider.label.querySelector("strong").textContent=`${this.data.subtitlesMaxLength}`,this.subtitlesWidget.setMaxLength(this.data.subtitlesMaxLength)})()})),this.votSubtitlesFontSizeSlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesFontSize=Number(t.target.value),await _.set("subtitlesFontSize",this.data.subtitlesFontSize),this.votSubtitlesFontSizeSlider.label.querySelector("strong").textContent=`${this.data.subtitlesFontSize}`,this.subtitlesWidget.setFontSize(this.data.subtitlesFontSize)})()})),this.votSubtitlesOpacitySlider.input.addEventListener("input",(t=>{(async()=>{this.data.subtitlesOpacity=Number(t.target.value),await _.set("subtitlesOpacity",this.data.subtitlesOpacity),this.votSubtitlesOpacitySlider.label.querySelector("strong").textContent=`${this.data.subtitlesOpacity}`,this.subtitlesWidget.setOpacity(this.data.subtitlesOpacity)})()})),document.documentElement.appendChild(this.votSubtitlesDialog.container)})),this.votShowPiPButtonCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.showPiPButton=Number(t.target.checked),await _.set("showPiPButton",this.data.showPiPButton),I.log("showPiPButton value changed. New value: ",this.data.showPiPButton),this.votButton.pipButton.hidden=!B()||!this.data.showPiPButton,this.votButton.separator2.hidden=!B()||!this.data.showPiPButton})()})),this.votM3u8ProxyHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.m3u8ProxyHost=t.target.value||Qt,await _.set("m3u8ProxyHost",this.data.m3u8ProxyHost),I.log("m3u8ProxyHost value changed. New value: ",this.data.m3u8ProxyHost)})()})),this.votProxyWorkerHostTextfield.input.addEventListener("change",(t=>{(async()=>{this.data.proxyWorkerHost=t.target.value||Xt,await _.set("proxyWorkerHost",this.data.proxyWorkerHost),I.log("proxyWorkerHost value changed. New value: ",this.data.proxyWorkerHost),this.votClient.host=this.data.proxyWorkerHost})()})),this.votAudioProxyCheckbox.input.addEventListener("change",(t=>{(async()=>{this.data.audioProxy=Number(t.target.checked),await _.set("audioProxy",this.data.audioProxy),I.log("audioProxy value changed. New value: ",this.data.audioProxy)})()})),this.votResetSettingsButton.addEventListener("click",(()=>{(async()=>{H.reset();const t=await _.list();for(let e=0;e{this.extraEvents.push({element:t,event:e,handler:o}),t.addEventListener(e,o)},e=(e,o,n)=>{for(const i of o)t(e,i,n)};if(this.resizeObserver=new ResizeObserver((t=>{for(let e=0;e550;this.votButton.container.dataset.position=this.votMenu.container.dataset.position=e?this.data?.buttonPos:"default",this.votButton.container.dataset.direction=this.data?.buttonPos&&"default"!==this.data?.buttonPos&&e?"column":"row"})),this.resizeObserver.observe(this.video),this.votMenu.container.setAttribute("style",`--vot-container-height: ${this.video.getBoundingClientRect().height}px`),["youtube","googledrive"].includes(this.site.host)&&"mobile"!==this.site.additionalData){this.syncVolumeObserver=new MutationObserver((t=>{if(this.audio.src&&this.data.syncVolume)for(let e=0;e{const e=t.target,o=this.votButton.container,n=this.votMenu.container,i=this.container,a=this.votSettingsDialog.container,r=document.querySelector(".vot-dialog-temp"),s=o.contains(e),l=n.contains(e),d=i.contains(e),u=a.contains(e),c=r?.contains(e)??!1;I.log(`[document click] ${s} ${l} ${d} ${u} ${c}`),s||l||u||c||(d||this.logout(0),this.votMenu.container.hidden=!0)})),o="pornhub"===this.site.host?"embed"===this.site.additionalData?document.querySelector("#player"):this.container.querySelector(".mgp_eventCatcher"):"twitter"===this.site.host?document.querySelector('div[data-testid="videoPlayer"]'):"yandexdisk"===this.site.host?document.querySelector(".video-player__player"):this.container,o&&e(o,["mousemove","mouseout"],this.resetTimerBound),t(this.votButton.container,"mousemove",this.changeOpacityOnEventBound),t(this.votMenu.container,"mousemove",this.changeOpacityOnEventBound),e(document,["touchstart","touchmove","touchend"],this.changeOpacityOnEventBound),t(this.votButton.container,"mousedown",(t=>{t.stopImmediatePropagation()})),t(this.votMenu.container,"mousedown",(t=>{t.stopImmediatePropagation()})),"youtube"===this.site.host&&(this.container.draggable=!1),"googledrive"===this.site.host&&(this.container.style.height="100%"),t(this.video,"canplay",(async()=>{"rutube"===this.site.host&&this.video.src||await it(this.site,this.video)!==this.videoData.videoId&&(await this.handleSrcChanged(),I.log("lipsync mode is loadeddata"),await this.autoTranslate())})),t(this.video,"emptied",(async()=>{this.video.src&&await it(this.site,this.video)===this.videoData.videoId||(I.log("lipsync mode is emptied"),this.videoData="",this.stopTranslation())})),["rutube","ok"].includes(this.site.host)||t(this.video,"volumechange",(()=>{this.syncVideoVolumeSlider()}))}logout(t){this.votMenu.container.hidden&&(this.votButton.container.style.opacity=t)}resetTimer(){clearTimeout(this.timer),this.logout(1),this.timer=setTimeout((()=>{this.logout(0)}),1e3)}changeOpacityOnEvent(t){clearTimeout(this.timer),this.logout(1),t.stopPropagation()}async changeSubtitlesLang(t){if(I.log("[onchange] subtitles",t),this.votSubtitlesSelect.setSelected(t),"disabled"===t)this.votSubtitlesSelect.setTitle(H.get("VOTSubtitlesDisabled")),this.subtitlesWidget.setContent(null),this.votDownloadSubtitlesButton.hidden=!0,this.yandexSubtitles=null;else{const e=this.subtitlesList.at(parseInt(t));if(1===this.data.audioProxy&&e.url.startsWith("https://brosubs.s3-private.mds.yandex.net/vtrans/")){const t=e.url.replace("https://brosubs.s3-private.mds.yandex.net/vtrans/","");e.url=`https://${this.data.proxyWorkerHost}/video-subtitles/subtitles-proxy/${t}`,console.log(`[VOT] Subs proxied via ${e.url}`)}this.yandexSubtitles=await qe(e),this.subtitlesWidget.setContent(this.yandexSubtitles),this.votDownloadSubtitlesButton.hidden=!1}}async updateSubtitlesLangSelect(){const t=[{label:H.get("VOTSubtitlesDisabled"),value:"disabled",selected:!0,disabled:!1},...this.subtitlesList.map(((t,e)=>({label:(H.get("langs")[t.language]??t.language.toUpperCase())+(t.translatedFromLanguage?` ${H.get("VOTTranslatedFrom")} ${H.get("langs")[t.translatedFromLanguage]??t.translatedFromLanguage.toUpperCase()}`:"")+("yandex"!==t.source?` ${t.source}`:"")+(t.isAutoGenerated?` (${H.get("VOTAutogenerated")})`:""),value:e,selected:!1,disabled:!1})))];this.votSubtitlesSelect.updateItems(t),await this.changeSubtitlesLang(t[0].value)}async updateSubtitles(){if(await this.changeSubtitlesLang("disabled"),!this.videoData.videoId)return console.error(`[VOT] ${H.getDefault("VOTNoVideoIDFound")}`),this.subtitlesList=[],this.subtitlesListVideoId=null,this.votButton.container.hidden=!0,void await this.updateSubtitlesLangSelect();if(this.votButton.container.hidden=!1,this.subtitlesListVideoId!==this.videoData.videoId){try{this.subtitlesList=await ze(this.votClient,this.videoData)}catch(t){if("Unsupported video URL for getting subtitles"===t?.unlocalizedMessage)return void(this.subtitlesList=[]);I.log("Error with yandex server, try auto-fix...",t),this.votOpts={fetchFn:q,hostVOT:te,host:this.data.proxyWorkerHost},this.votClient=new ut(this.votOpts),this.subtitlesList=await ze(this.votClient,this.videoData),await _.set("translateProxyEnabled",1)}this.subtitlesList?this.subtitlesListVideoId=this.videoData.videoId:await this.changeSubtitlesLang("disabled"),await this.updateSubtitlesLangSelect()}}getVideoVolume(){let t=this.video?.volume;return["youtube","googledrive"].includes(this.site.host)&&(t=Be.getVideoVolume()??t),t}setVideoVolume(t){if(["youtube","googledrive"].includes(this.site.host)){if(Be.setVideoVolume(t))return}this.video.volume=t}isMuted(){return["youtube","googledrive"].includes(this.site.host)?Be.isMuted():this.video?.muted}syncVideoVolumeSlider(){const t=this.isMuted()?0:100*this.getVideoVolume(),e=Math.round(t);this.votVideoVolumeSlider.input.value=e,this.votVideoVolumeSlider.label.querySelector("strong").textContent=`${e}%`,Me.updateSlider(this.votVideoVolumeSlider.input),1===this.data.syncVolume&&(this.tempOriginalVolume=Number(e))}setSelectMenuValues(t,e){this.votTranslationLanguageSelect.fromSelect.setTitle(H.get("langs")[t]),this.votTranslationLanguageSelect.toSelect.setTitle(H.get("langs")[e]),this.votTranslationLanguageSelect.fromSelect.setSelected(t),this.votTranslationLanguageSelect.toSelect.setSelected(e),console.log(`[VOT] Set translation from ${t} to ${e}`),this.videoData.detectedLanguage=t,this.videoData.responseLanguage=e}syncVolumeWrapper(t,e){const o="translation"===t?this.votVideoVolumeSlider:this.votVideoTranslationVolumeSlider,n=Number(o.input.value),i=function(t,e,o,n){let i=e;return e>n?(i=o+(e-n),i=i>100?100:Math.max(i,0),t.volume=i/100):e100?100:Math.max(i,0),t.volume=i/100),i}("translation"===t?this.video:this.audio,e,n,"translation"===t?this.tempVolume:this.tempOriginalVolume);o.input.value=i,o.label.querySelector("strong").textContent=`${i}%`,Me.updateSlider(o.input),this.tempOriginalVolume="translation"===t?i:e,this.tempVolume="translation"===t?e:i}async getVideoData(){const{duration:t,url:e,videoId:o,host:n,translationHelp:i,detectedLanguage:a}=await at(this.site,this.video),r={translationHelp:i??null,isStream:!1,duration:this.video?.duration||t||y.defaultDuration,videoId:o,url:e,host:n,detectedLanguage:a??this.translateFromLang,responseLanguage:this.translateToLang};if("youtube"===this.site.host){const t=await Be.getVideoData();r.isStream=t.isLive,t.title&&(r.detectedLanguage=t.detectedLanguage)}else if(["rutube","ok.ru","mail_ru"].includes(this.site.host))r.detectedLanguage="ru";else if("youku"===this.site.host)r.detectedLanguage="zh";else if("vk"===this.site.host){const t=document.getElementsByTagName("track")?.[0]?.srclang;r.detectedLanguage=t||"auto"}else"weverse"===this.site.host?r.detectedLanguage="ko":["bilibili","piped","invidious","bitchute","rumble","peertube","dailymotion","trovo","yandexdisk","coursehunter","archive","directlink"].includes(this.site.host)&&(r.detectedLanguage="auto");return r}videoValidator(){if(["youtube","ok.ru","vk"].includes(this.site.host)&&(I.log("VideoValidator videoData: ",this.videoData),1===this.data.dontTranslateYourLang&&this.videoData.detectedLanguage===this.data.dontTranslateLanguage))throw new rt("VOTDisableFromYourLang");if(!this.videoData.isStream&&this.videoData.duration>14400)throw new rt("VOTVideoIsTooLong");return!0}lipSync(t=!1){if(I.log("lipsync video",this.video),this.video)if(this.audio.currentTime=this.video.currentTime,this.audio.playbackRate=this.video.playbackRate,t)if("play"!=t)["pause","stop","waiting"].includes(t)&&(I.log(`lipsync mode is ${t}`),this.audio.pause()),"playing"==t&&(I.log("lipsync mode is playing"),this.audio.play());else{I.log("lipsync mode is play");const t=this.audio.play();void 0!==t&&t.catch((async t=>{if(console.error("[VOT]",t),"NotAllowedError"===t.name)throw this.transformBtn("error",H.get("grantPermissionToAutoPlay")),new rt("grantPermissionToAutoPlay")}))}else I.log("lipsync mode is not set")}handleVideoEvent(t){I.log(`video ${t.type}`),this.lipSync(t.type)}stopTranslate(){for(const t of Ke)this.video.removeEventListener(t,this.handleVideoEventBound);this.audio.pause(),this.audio.src="",this.audio.removeAttribute("src"),this.votVideoVolumeSlider.container.hidden=!0,this.votVideoTranslationVolumeSlider.container.hidden=!0,this.votDownloadButton.hidden=!0,this.downloadTranslationUrl=null,this.transformBtn("none",H.get("translateVideo")),I.log(`Volume on start: ${this.volumeOnStart}`),this.volumeOnStart&&this.setVideoVolume(this.volumeOnStart),this.volumeOnStart="",clearInterval(this.streamPing),clearTimeout(this.autoRetry),this.hls?.destroy(),this.hls=D(),this.firstSyncVolume=!0}async translateExecutor(t){I.log("Run translateFunc",t),await this.translateFunc(t,this.videoData.isStream,this.videoData.detectedLanguage,this.videoData.responseLanguage,this.videoData.translationHelp)}async updateTranslationErrorMsg(t){const e=H.get("translationTake"),o=H.lang;if(["Подготавливаем перевод","Видео передано в обработку","Ожидаем перевод видео","Загружаем переведенное аудио"].includes(t)&&this.setLoadingBtn(!0),"VOTLocalizedError"===t?.name)this.transformBtn("error",t.localizedMessage);else if(t instanceof Error)this.transformBtn("error",t?.message);else if(1!==this.data.translateAPIErrors||t.includes(e)||"ru"===o)this.transformBtn("error",t);else{this.setLoadingBtn(!0);const e=await async function(t,e="",o="ru"){switch(await _.get("translationService",oe)){case"yandex":{const n=e&&o?`${e}-${o}`:o;return await Ae.translate(t,n)}case"deepl":return await Ce.translate(t,e,o);default:return t}}(t,"ru",o);this.transformBtn("error",e)}}afterUpdateTranslation(t){this.votVideoVolumeSlider.container.hidden=1!==this.data.showVideoSlider||"success"!==this.votButton.container.dataset.status,this.votVideoTranslationVolumeSlider.container.hidden="success"!==this.votButton.container.dataset.status,1===this.data.autoSetVolumeYandexStyle&&(this.votVideoVolumeSlider.input.value=100*this.data.autoVolume,this.votVideoVolumeSlider.label.querySelector("strong").textContent=100*this.data.autoVolume+"%",Me.updateSlider(this.votVideoVolumeSlider.input)),this.votDownloadButton.hidden=!1,this.downloadTranslationUrl=t}async updateTranslation(t){if(this.cachedTranslation?.url===this.audio.currentSrc)I.log("[translateFunc] Audio src is the same"),this.audio.src=t;else{try{const e=await q(t,{method:"HEAD",timeout:5e3});if(I.log("Test audio response",e),404===e.status){I.log("Yandex returned not valid audio, trying to fix...");let e=await this.translateVideoImpl(this.videoData,this.videoData.detectedLanguage="auto",this.videoData.responseLanguage,this.videoData.translationHelp);this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage),t=e.url,I.log("Fixed audio audioUrl",t)}else I.log("Valid audioUrl",t)}catch(t){"Timeout"===t.message?(I.log("Request timed out. Handling timeout error..."),this.data.audioProxy=1,await _.set("audioProxy",1)):I.log("Test audio error:",t)}this.audio.src=t;try{await this.audio.play()}catch(t){if(console.error("[VOT]",t),"NotSupportedError"===t.name){if([...V,...M].includes(window.location.hostname))throw new rt("VOTMediaCSPError");this.data.audioProxy=1,await _.set("audioProxy",1)}}}if(1===this.data.audioProxy&&t.startsWith("https://vtrans.s3-private.mds.yandex.net/tts/prod/")){const e=t.replace("https://vtrans.s3-private.mds.yandex.net/tts/prod/","");t=`https://${this.data.proxyWorkerHost}/video-translation/audio-proxy/${e}`,console.log(`[VOT] Audio proxied via ${t}`)}if(this.audio.src=t,this.volumeOnStart||(this.volumeOnStart=this.getVideoVolume()),this.setupAudioSettings(),"twitter"===this.site.host)document.querySelector('button[data-testid="app-bar-back"][role="button"]').addEventListener("click",this.stopTranslationBound);this.video&&!this.video.paused&&this.lipSync("play");for(const t of Ke)this.video.addEventListener(t,this.handleVideoEventBound);this.transformBtn("success",H.get("disableTranslate")),this.afterUpdateTranslation(t)}async translateFunc(t,e,o,n,i){if(console.log("[VOT] Video Data: ",this.videoData),I.log("Run videoValidator"),this.videoValidator(),this.setLoadingBtn(!0),e){let t=await this.translateStreamImpl(this.videoData,o,n);if(!t)return void I.log("Skip translation");this.transformBtn("success",H.get("disableTranslate"));const e=`https://${this.data.m3u8ProxyHost}/?all=yes&origin=${encodeURIComponent("https://strm.yandex.ru")}&referer=${encodeURIComponent("https://strm.yandex.ru")}&url=${encodeURIComponent(t.result.url)}`;if(this.hls)this.setupHLS(e);else{if(!this.audio.canPlayType("application/vnd.apple.mpegurl"))throw new rt("audioFormatNotSupported");this.audio.src=e}if("youtube"===this.site.host&&Be.videoSeek(this.video,10),this.setupAudioSettings(),!this.video.src&&!this.video.currentSrc&&!this.video.srcObject)return this.stopTranslation();this.video&&!this.video.paused&&this.lipSync("play");for(const t of Ke)this.video.addEventListener(t,this.handleVideoEventBound);return this.afterUpdateTranslation(e)}if(this.cachedTranslation=this.videoTranslations.find((e=>e.videoId===t&&e.expires>Date.now()/1e3&&e.from===o&&e.to===n)),this.cachedTranslation)return await this.updateTranslation(this.cachedTranslation.url),void I.log("[translateFunc] Cached translation was received");let a=await this.translateVideoImpl(this.videoData,o,n,i);I.log("[translateRes]",a),a?(await this.updateTranslation(a.url),[k.kick,k.reddit,k.patreon,k.kodik,k.appledeveloper].includes(this.site.host)||this.subtitlesList.some((t=>"yandex"===t.source&&t.translatedFromLanguage===this.videoData.detectedLanguage&&t.language===this.videoData.responseLanguage))||(this.subtitlesList=await ze(this.votClient,this.videoData),await this.updateSubtitlesLangSelect()),this.videoTranslations.push({videoId:t,from:o,to:n,url:this.downloadTranslationUrl,expires:Date.now()/1e3+this.videoTranslationTTL})):I.log("Skip translation")}setupHLS(t){this.hls.on(Hls.Events.MEDIA_ATTACHED,(function(){I.log("audio and hls.js are now bound together !")})),this.hls.on(Hls.Events.MANIFEST_PARSED,(function(t){I.log("manifest loaded, found "+t?.levels?.length+" quality level")})),this.hls.loadSource(t),this.hls.attachMedia(this.audio),this.hls.on(Hls.Events.ERROR,(function(t){if(t.fatal)switch(t.type){case Hls.ErrorTypes.MEDIA_ERROR:console.log("fatal media error encountered, try to recover"),this.hls.recoverMediaError();break;case Hls.ErrorTypes.NETWORK_ERROR:console.error("fatal network error encountered",t);break;default:this.hls.destroy()}})),I.log(this.hls)}setupAudioSettings(){"number"==typeof this.data.defaultVolume&&(this.gainNode.gain.value=this.data.defaultVolume/100),"number"==typeof this.data.autoSetVolumeYandexStyle&&this.data.autoSetVolumeYandexStyle&&this.setVideoVolume(this.data.autoVolume)}stopTranslation(){this.stopTranslate(),this.syncVideoVolumeSlider()}async handleSrcChanged(){I.log("[VideoHandler] src changed",this),this.firstPlay=!0,this.videoData=await this.getVideoData(),this.setSelectMenuValues(this.videoData.detectedLanguage,this.videoData.responseLanguage);const t=!this.video.src&&!this.video.currentSrc&&!this.video.srcObject;this.votButton.container.hidden=t,t&&(this.votMenu.container.hidden=t),this.site.selector||(this.container=this.video.parentElement),this.container.contains(this.votButton.container)||(this.container.appendChild(this.votButton.container),this.container.appendChild(this.votMenu.container)),await this.updateSubtitles(),await this.changeSubtitlesLang("disabled"),this.translateToLang=this.data.responseLanguage??"ru"}async release(){I.log("[VideoHandler] release"),this.initialized=!1,this.releaseExtraEvents(),this.subtitlesWidget.release(),this.votButton.container.remove(),this.votMenu.container.remove()}}const Xe=new class{constructor(){this.videoCache=new Set,this.onVideoAdded=new Ue,this.onVideoRemoved=new Ue,this.observer=new MutationObserver(this.handleMutations),this.intersectionObserver=new IntersectionObserver(this.handleIntersections,{threshold:.1})}handleMutations=t=>{window.requestIdleCallback((()=>{for(let e=0;e{for(let e=0;e{if(!t)return;const n=t.querySelectorAll("video");for(let t=0;t{this.videoCache.has(t)||(this.videoCache.add(t),this.intersectionObserver.observe(t))};handleIntersectingVideo=t=>{this.intersectionObserver.unobserve(t),(t=>{if(We.test(t.className)||We.test(t.title))return!0;let e=t.parentElement;for(;e;){if(We.test(e.className)||We.test(e.id))return!0;e=e.parentElement}return!1})(t)||(t=>t.hasAttribute("muted")&&!t.classList.contains("vjs-tech"))(t)?I.log("The promotional/muted video was ignored",t):((t,e)=>{const o=()=>{(t=>t.readyState>=3)(t)?e(t):requestAnimationFrame(o)};o()})(t,this.handleVideoAdded)};handleVideoAdded=t=>{this.onVideoAdded.dispatch(t)};handleVideoRemoved=t=>{document.contains(t)||(this.videoCache.delete(t),this.onVideoRemoved.dispatch(t))}},to=new WeakMap;function eo(t,e){if(t.shadowRoot){let o=t.selector?Array.from(document.querySelectorAll(t.selector)).find((t=>t.shadowRoot.contains(e))):e.parentElement;return o&&o.shadowRoot?o.parentElement:o}const o=Je.browser.version.split(".")[0];if(t.selector?.includes(":not")&&t.selector?.includes("*")&&o&&("Chrome"===Je.browser.name&&Number(o)<88||"Firefox"===Je.browser.name&&Number(o)<84)){const o=t.selector.split(" *")[0];return o?Array.from(document.querySelectorAll(o)).find((t=>t.contains(e))):e.parentElement}return t.selector?Array.from(document.querySelectorAll(t.selector)).find((t=>t.contains(e))):e.parentElement}(async function(){I.log("Loading extension..."),await H.update(),I.log(`Selected menu language: ${H.lang}`),Xe.onVideoAdded.addListener((t=>{for(const e of function(){if(/(http(s)?:\/\/)(127\.0\.0\.1|localhost)/.exec(window.location.href))return[];const t=window.location.hostname,e=new URL(window.location),o=o=>o instanceof RegExp?o.test(t):"string"==typeof o?t.includes(o):"function"==typeof o&&o(e);return A.filter((t=>(Array.isArray(t.match)?t.match.some(o):o(t.match))&&t.host&&t.url))}()){if(!e)continue;let o=eo(e,t);if(o&&(("rumble"!==e.host||t.style.display)&&(["peertube","directlink"].includes(e.host)&&(e.url=window.location.origin),!to.has(t)))){to.set(t,new Qe(t,o,e));break}}})),Xe.onVideoRemoved.addListener((async t=>{to.has(t)&&(await to.get(t).release(),to.delete(t))})),Xe.enable()})().catch((t=>{console.error("[VOT]",t)}))})()})(); \ No newline at end of file diff --git a/dist/vot.user.js b/dist/vot.user.js index e20e3914..943fab83 100644 --- a/dist/vot.user.js +++ b/dist/vot.user.js @@ -6125,6 +6125,10 @@ const isAdVideo = (video) => { return false; }; +const isMutedVideo = (video) => { + return video.hasAttribute("muted") && !video.classList.contains("vjs-tech"); +}; + const isVideoReady = (video) => video.readyState >= 3; const waitForVideoReady = (video, callback) => { @@ -6233,7 +6237,7 @@ class VideoObserver { handleIntersectingVideo = (video) => { this.intersectionObserver.unobserve(video); - if (isAdVideo(video) || video.hasAttribute("muted")) { + if (isAdVideo(video) || isMutedVideo(video)) { utils_debug.log("The promotional/muted video was ignored", video); return; } diff --git a/src/utils/VideoObserver.js b/src/utils/VideoObserver.js index 7863f2a0..780983ba 100644 --- a/src/utils/VideoObserver.js +++ b/src/utils/VideoObserver.js @@ -61,6 +61,10 @@ const isAdVideo = (video) => { return false; }; +const isMutedVideo = (video) => { + return video.hasAttribute("muted") && !video.classList.contains("vjs-tech"); +}; + const isVideoReady = (video) => video.readyState >= 3; const waitForVideoReady = (video, callback) => { @@ -169,7 +173,7 @@ export class VideoObserver { handleIntersectingVideo = (video) => { this.intersectionObserver.unobserve(video); - if (isAdVideo(video) || video.hasAttribute("muted")) { + if (isAdVideo(video) || isMutedVideo(video)) { debug.log("The promotional/muted video was ignored", video); return; }